From b0510c8fd04167d31095a2bd157757a981ee8058 Mon Sep 17 00:00:00 2001 From: prabhat Date: Fri, 14 Aug 2020 23:53:20 +0100 Subject: [PATCH 1/6] Fixes: #81 and #82 --- css/index.css | 8 +++- index.html | 22 +++++++++- js/app.mjs | 56 ++++++++++++++++++++++---- js/generate-images.mjs | 80 ++++++++++++------------------------- js/utils/generate-utils.mjs | 16 ++++---- js/utils/helpers.mjs | 73 ++++++++++++++++++++++++++++++++- 6 files changed, 181 insertions(+), 74 deletions(-) diff --git a/css/index.css b/css/index.css index acbe209..adf0a31 100644 --- a/css/index.css +++ b/css/index.css @@ -163,7 +163,7 @@ body.dark .github-corner { } .left-margin-and-content { - min-height: calc(100% - 50px); + height: calc(100% - 50px); } .page-a { @@ -177,7 +177,7 @@ body.dark .github-corner { font-family: var(--handwriting-font); color: var(--ink-color); line-height: 1.5em; - overflow-y: auto; + overflow-y: hidden; scrollbar-color: transparent; scrollbar-width: thin; } @@ -218,6 +218,7 @@ body.dark .github-corner { top: 0px; padding-top: 50px; overflow-x: hidden; + overflow-y: hidden; position: absolute; left: 0; } @@ -236,6 +237,9 @@ body.dark .github-corner { /* background-image: linear-gradient(10deg, #000a, #0001); */ } +.draw-button { + display: inline-block; +} /* OUTPUT */ .output { width: 100%; diff --git a/index.html b/index.html index 3bc11ec..46f1f10 100644 --- a/index.html +++ b/index.html @@ -16,7 +16,11 @@ gtag('config', 'UA-125454191-4'); - + @@ -175,6 +179,22 @@

Input

> Draw (Beta) + + diff --git a/js/app.mjs b/js/app.mjs index f539c1c..74d5894 100644 --- a/js/app.mjs +++ b/js/app.mjs @@ -1,4 +1,11 @@ -import { addFontFromFile, formatText } from './utils/helpers.mjs'; +import { + addFontFromFile, + formatText, + preventNewDiv, + trimContent, + addPage, + removePage +} from './utils/helpers.mjs'; import { generateImages, downloadAsPDF } from './generate-images.mjs'; import { setInkColor, toggleDrawCanvas } from './utils/draw.mjs'; @@ -93,6 +100,18 @@ const EVENT_MAP = { toggleDrawCanvas(); } }, + '#add-page-button': { + on: 'click', + action: () => { + addPage(); + } + }, + '#remove-page-button': { + on: 'click', + action: () => { + removePage(); + } + }, '.draw-container .close-button': { on: 'click', action: () => { @@ -104,22 +123,43 @@ const EVENT_MAP = { action: () => { downloadAsPDF(); } - }, - '.page-a .paper-content': { + } +}; + +const DELEGATED_EVENT_MAP = [ + { on: 'paste', action: formatText + }, + { + on: 'keydown', + action: trimContent + }, + { + on: 'keydown', + action: preventNewDiv } -}; +]; for (const eventSelector in EVENT_MAP) { document - .querySelector(eventSelector) - .addEventListener( - EVENT_MAP[eventSelector].on, - EVENT_MAP[eventSelector].action + .querySelectorAll(eventSelector) + .forEach((node) => + node.addEventListener( + EVENT_MAP[eventSelector].on, + EVENT_MAP[eventSelector].action + ) ); } +for (const childSelector of DELEGATED_EVENT_MAP) { + $('.page-container').on( + childSelector.on, + '.page-a div[contenteditable=true]', + childSelector.action + ); +} + /** * This makes toggles, accessible. */ diff --git a/js/generate-images.mjs b/js/generate-images.mjs index 50e694d..4d460e3 100644 --- a/js/generate-images.mjs +++ b/js/generate-images.mjs @@ -5,14 +5,13 @@ import { } from './utils/generate-utils.mjs'; import { createPDF } from './utils/helpers.mjs'; -const pageEl = document.querySelector('.page-a'); const outputImages = []; /** * To generate image, we add styles to DIV and converts that HTML Element into Image. * This is the function that deals with it. */ -async function convertDIVToImage() { +async function convertDIVToImage(pageEl) { const options = { scrollX: 0, scrollY: -window.scrollY, @@ -29,72 +28,43 @@ async function convertDIVToImage() { contrastImage(imageData, 0.55); canvas.getContext('2d').putImageData(imageData, 0, 0); } - - outputImages.push(canvas); - // Displaying no. of images on addition - if (outputImages.length >= 1) { - document.querySelector('#output-header').textContent = - 'Output ' + '( ' + outputImages.length + ' )'; - } + return canvas; } /** * This is the function that gets called on clicking "Generate Image" button. */ export async function generateImages() { - applyPaperStyles(); - pageEl.scrollTo(0, 0); - - const paperContentEl = document.querySelector('.page-a .paper-content'); - const scrollHeight = paperContentEl.scrollHeight; - const clientHeight = 514; // height of .paper-content when there is no content - - const totalPages = Math.ceil(scrollHeight / clientHeight); - - if (totalPages > 1) { - // For multiple pages - if (paperContentEl.innerHTML.includes('= 1) { + document.querySelector('#output-header').textContent = + 'Output ' + '( ' + outputImages.length + ' )'; } - - removePaperStyles(); renderOutput(outputImages); setRemoveImageListeners(); } /** * Downloads generated images as PDF + * */ export const downloadAsPDF = () => createPDF(outputImages); diff --git a/js/utils/generate-utils.mjs b/js/utils/generate-utils.mjs index 45fcab6..a1f9c1f 100644 --- a/js/utils/generate-utils.mjs +++ b/js/utils/generate-utils.mjs @@ -1,6 +1,6 @@ -const pageEl = document.querySelector('.page-a'); -const paperContentEl = document.querySelector('.page-a .paper-content'); -const overlayEl = document.querySelector('.overlay'); +// const pageEl = document.querySelector('.page-a'); +let paperContentEl; +let overlayEl; let paperContentPadding; @@ -15,10 +15,11 @@ function isFontErrory() { ); } -function applyPaperStyles() { +async function applyPaperStyles(pageEl) { pageEl.style.border = 'none'; pageEl.style.overflowY = 'hidden'; - + paperContentEl = pageEl.querySelector('.paper-content'); + overlayEl = pageEl.querySelector('.overlay'); // Adding class shadows even if effect is scanner if (document.querySelector('#page-effects').value === 'scanner') { overlayEl.classList.add('shadows'); @@ -46,10 +47,11 @@ function applyPaperStyles() { } } -function removePaperStyles() { +async function removePaperStyles(pageEl) { pageEl.style.overflowY = 'auto'; pageEl.style.border = '1px solid var(--elevation-background)'; - + paperContentEl = pageEl.querySelector('.paper-content'); + overlayEl = pageEl.querySelector('.overlay'); if (document.querySelector('#page-effects').value === 'scanner') { overlayEl.classList.remove('shadows'); } else { diff --git a/js/utils/helpers.mjs b/js/utils/helpers.mjs index 810a0fe..9c7e889 100644 --- a/js/utils/helpers.mjs +++ b/js/utils/helpers.mjs @@ -1,4 +1,7 @@ const pageEl = document.querySelector('.page-a'); +const fixedPage = document.querySelector( + '.display-flex.left-margin-and-content' +); const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); function addFontFromFile(fileObj) { @@ -50,4 +53,72 @@ function formatText(event) { document.execCommand('insertHTML', false, text); } -export { isMobile, addFontFromFile, createPDF, formatText }; +function preventNewDiv(event) { + if (event.key === 'Enter') { + document.execCommand('insertLineBreak'); + event.preventDefault(); + } +} + +function setEndOfContenteditable(contentEditableElement) { + let range; + let selection; + if (document.createRange) { + range = document.createRange(); + range.selectNodeContents(contentEditableElement); + range.collapse(false); + selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + } else if (document.selection) { + // IE 8 and lower + range = document.body.createTextRange(); + range.moveToElementText(contentEditableElement); + range.collapse(false); + range.select(); + } +} + +function trimContent(event) { + const fixedHeight = fixedPage.clientHeight; + let flag = false; + const className = '.' + this.className; + const paddingTop = parseInt( + $(className).css('padding-top').replace('px', '') + ); + while (fixedHeight < this.scrollHeight - paddingTop) { + flag = true; + let innerContent = this.innerHTML; + innerContent = innerContent.substring(0, innerContent.length - 1); + this.innerHTML = innerContent; + } + if (flag) setEndOfContenteditable(this); +} + +function addPage() { + const pageList = document.querySelectorAll('.page-a'); + const pageArr = [...pageList]; + const lastNode = pageArr[pageArr.length - 1]; + const newNode = lastNode.cloneNode(true); + newNode + .querySelectorAll('div[contenteditable=true]') + .forEach((node) => (node.innerHTML = '')); + lastNode.insertAdjacentElement('afterend', newNode); +} + +function removePage() { + const pageList = document.querySelectorAll('.page-a'); + const pageArr = [...pageList]; + const lastNode = pageArr[pageArr.length - 1]; + if (pageArr.length > 1) lastNode.remove(); +} +export { + isMobile, + addFontFromFile, + createPDF, + formatText, + preventNewDiv, + trimContent, + addPage, + removePage +}; From 85aab0ac9297290fc2b758cf9683b9437ad80010 Mon Sep 17 00:00:00 2001 From: prabhat Date: Sat, 15 Aug 2020 13:52:51 +0100 Subject: [PATCH 2/6] Fixes: pasting event handler Use of Jquery adds an additional prototype in getting clipboard data from event Please enter the commit message for your changes. Lines starting --- js/utils/helpers.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/utils/helpers.mjs b/js/utils/helpers.mjs index 9c7e889..9d85e63 100644 --- a/js/utils/helpers.mjs +++ b/js/utils/helpers.mjs @@ -47,7 +47,7 @@ function createPDF(imgs) { function formatText(event) { event.preventDefault(); - const text = event.clipboardData + const text = event.originalEvent.clipboardData .getData('text/plain') .replace(/\n/g, '
'); document.execCommand('insertHTML', false, text); From 967259a776fdbb417e097f1c6384f5f935abcd14 Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 23 Aug 2020 18:26:33 +0100 Subject: [PATCH 3/6] Feature: Add page automatically Added the functionality of automatically creating pages when the content becomes more than the current page capacity --- js/app.mjs | 4 ++-- js/utils/helpers.mjs | 51 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/js/app.mjs b/js/app.mjs index 74d5894..0fd5f1d 100644 --- a/js/app.mjs +++ b/js/app.mjs @@ -133,11 +133,11 @@ const DELEGATED_EVENT_MAP = [ }, { on: 'keydown', - action: trimContent + action: preventNewDiv }, { on: 'keydown', - action: preventNewDiv + action: trimContent } ]; diff --git a/js/utils/helpers.mjs b/js/utils/helpers.mjs index 9d85e63..28c8a8a 100644 --- a/js/utils/helpers.mjs +++ b/js/utils/helpers.mjs @@ -2,6 +2,7 @@ const pageEl = document.querySelector('.page-a'); const fixedPage = document.querySelector( '.display-flex.left-margin-and-content' ); +const fixedHeight = fixedPage.clientHeight; const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); function addFontFromFile(fileObj) { @@ -51,6 +52,7 @@ function formatText(event) { .getData('text/plain') .replace(/\n/g, '
'); document.execCommand('insertHTML', false, text); + adjustContent.call(this); } function preventNewDiv(event) { @@ -79,20 +81,51 @@ function setEndOfContenteditable(contentEditableElement) { } } -function trimContent(event) { - const fixedHeight = fixedPage.clientHeight; - let flag = false; +function adjustContent(remainingContent = '') { const className = '.' + this.className; const paddingTop = parseInt( $(className).css('padding-top').replace('px', '') ); + let extraContent = ''; + const initialContent = this.innerHTML; + remainingContent += initialContent; + this.innerHTML = remainingContent; while (fixedHeight < this.scrollHeight - paddingTop) { - flag = true; - let innerContent = this.innerHTML; - innerContent = innerContent.substring(0, innerContent.length - 1); - this.innerHTML = innerContent; + extraContent = remainingContent.slice(-1) + extraContent; + remainingContent = remainingContent.substring( + 0, + remainingContent.length - 1 + ); + this.innerHTML = remainingContent; + } + if (extraContent == '') setEndOfContenteditable(this); + else { + const pageList = document.querySelectorAll('.page-a'); + const pageArr = [...pageList]; + const lastNode = pageArr[pageArr.length - 1]; + const pageContentArr = pageArr.map((page) => page.querySelector(className)); + const lastContentNode = pageContentArr[pageContentArr.length - 1]; + if (lastContentNode.isSameNode(this)) { + const newNode = lastNode.cloneNode(true); + newNode + .querySelectorAll('div[contenteditable=true]') + .forEach((node) => (node.innerHTML = '')); + lastNode.insertAdjacentElement('afterend', newNode); + const newContentNode = newNode.querySelector(className); + adjustContent.call(newContentNode, extraContent); + } else { + const currentNode = this; + const currentIndex = pageContentArr.findIndex((node) => + node.isSameNode(currentNode) + ); + const nextContentNode = pageContentArr[currentIndex + 1]; + adjustContent.call(nextContentNode, extraContent); + } } - if (flag) setEndOfContenteditable(this); +} + +function trimContent(event) { + adjustContent.call(this); } function addPage() { @@ -104,6 +137,8 @@ function addPage() { .querySelectorAll('div[contenteditable=true]') .forEach((node) => (node.innerHTML = '')); lastNode.insertAdjacentElement('afterend', newNode); + + return newNode; } function removePage() { From e226d1812a7d943004a33071f8217353ca70e981 Mon Sep 17 00:00:00 2001 From: prabhat Date: Tue, 25 Aug 2020 13:18:40 +0100 Subject: [PATCH 4/6] Fixed: Backspace selection --- js/utils/helpers.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/utils/helpers.mjs b/js/utils/helpers.mjs index 28c8a8a..c2c62c2 100644 --- a/js/utils/helpers.mjs +++ b/js/utils/helpers.mjs @@ -125,7 +125,8 @@ function adjustContent(remainingContent = '') { } function trimContent(event) { - adjustContent.call(this); + if (String.fromCharCode(event.keyCode).match(/(\w|\s|\n|\r|\t)/g)) + adjustContent.call(this); } function addPage() { From b7281e8566565ab054257e3be712fa5199726e9c Mon Sep 17 00:00:00 2001 From: prabhat Date: Tue, 25 Aug 2020 13:47:03 +0100 Subject: [PATCH 5/6] Fixed: Copy selection --- js/app.mjs | 18 ++++++++++++++++++ js/utils/helpers.mjs | 3 +++ 2 files changed, 21 insertions(+) diff --git a/js/app.mjs b/js/app.mjs index 0fd5f1d..baf2fa4 100644 --- a/js/app.mjs +++ b/js/app.mjs @@ -28,6 +28,11 @@ const pageEl = document.querySelector('.page-a'); const setTextareaStyle = (attrib, v) => (pageEl.style[attrib] = v); +// eslint-disable-next-line no-var +var ctrlDown = false; +const ctrlKey = 17; +const cmdKey = 91; + /** * Add event listeners here, they will be automatically mapped with addEventListener later */ @@ -127,6 +132,19 @@ const EVENT_MAP = { }; const DELEGATED_EVENT_MAP = [ + { + on: 'keydown', + action: (e) => { + if (e.keyCode == ctrlKey || e.keyCode == cmdKey) ctrlDown = true; + } + }, + { + on: 'keyup', + action: (e) => { + // eslint-disable-next-line no-unused-vars + if (e.keyCode == ctrlKey || e.keyCode == cmdKey) ctrlDown = false; + } + }, { on: 'paste', action: formatText diff --git a/js/utils/helpers.mjs b/js/utils/helpers.mjs index c2c62c2..3175750 100644 --- a/js/utils/helpers.mjs +++ b/js/utils/helpers.mjs @@ -3,6 +3,8 @@ const fixedPage = document.querySelector( '.display-flex.left-margin-and-content' ); const fixedHeight = fixedPage.clientHeight; +const vKey = 86; +const cKey = 67; const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); function addFontFromFile(fileObj) { @@ -125,6 +127,7 @@ function adjustContent(remainingContent = '') { } function trimContent(event) { + if (ctrlDown && (event.keyCode == vKey || event.keyCode == cKey)) return; if (String.fromCharCode(event.keyCode).match(/(\w|\s|\n|\r|\t)/g)) adjustContent.call(this); } From 9ce49285c9f70764cc84d9821bc71ad389fc3b9e Mon Sep 17 00:00:00 2001 From: prabhat Date: Tue, 25 Aug 2020 15:56:14 +0100 Subject: [PATCH 6/6] Fix: Copy slection fixed --- js/app.mjs | 16 ++++------------ js/utils/helpers.mjs | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/js/app.mjs b/js/app.mjs index baf2fa4..2b4d6ff 100644 --- a/js/app.mjs +++ b/js/app.mjs @@ -3,6 +3,8 @@ import { formatText, preventNewDiv, trimContent, + setFalse, + setTrue, addPage, removePage } from './utils/helpers.mjs'; @@ -28,11 +30,6 @@ const pageEl = document.querySelector('.page-a'); const setTextareaStyle = (attrib, v) => (pageEl.style[attrib] = v); -// eslint-disable-next-line no-var -var ctrlDown = false; -const ctrlKey = 17; -const cmdKey = 91; - /** * Add event listeners here, they will be automatically mapped with addEventListener later */ @@ -134,16 +131,11 @@ const EVENT_MAP = { const DELEGATED_EVENT_MAP = [ { on: 'keydown', - action: (e) => { - if (e.keyCode == ctrlKey || e.keyCode == cmdKey) ctrlDown = true; - } + action: setTrue }, { on: 'keyup', - action: (e) => { - // eslint-disable-next-line no-unused-vars - if (e.keyCode == ctrlKey || e.keyCode == cmdKey) ctrlDown = false; - } + action: setFalse }, { on: 'paste', diff --git a/js/utils/helpers.mjs b/js/utils/helpers.mjs index 3175750..2aa3959 100644 --- a/js/utils/helpers.mjs +++ b/js/utils/helpers.mjs @@ -3,8 +3,13 @@ const fixedPage = document.querySelector( '.display-flex.left-margin-and-content' ); const fixedHeight = fixedPage.clientHeight; + const vKey = 86; const cKey = 67; +const ctrlKey = 17; +const cmdKey = 91; +let ctrlDown = false; + const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); function addFontFromFile(fileObj) { @@ -126,9 +131,18 @@ function adjustContent(remainingContent = '') { } } +function setFalse(event) { + if (event.keyCode == ctrlKey || event.keyCode == cmdKey) ctrlDown = false; +} + +function setTrue(event) { + if (event.keyCode == ctrlKey || event.keyCode == cmdKey) ctrlDown = true; +} + function trimContent(event) { - if (ctrlDown && (event.keyCode == vKey || event.keyCode == cKey)) return; - if (String.fromCharCode(event.keyCode).match(/(\w|\s|\n|\r|\t)/g)) + if (ctrlDown && (event.keyCode == vKey || event.keyCode == cKey)) { + console.log("I'm here"); + } else if (String.fromCharCode(event.keyCode).match(/(\w|\s|\n|\r|\t)/g)) adjustContent.call(this); } @@ -158,6 +172,8 @@ export { formatText, preventNewDiv, trimContent, + setFalse, + setTrue, addPage, removePage };