From 4107267e5bf79f0035f124c0ecdb83e09be2b164 Mon Sep 17 00:00:00 2001 From: void Date: Mon, 16 Nov 2020 16:31:05 -0300 Subject: [PATCH 1/2] =?UTF-8?q?cambiar=20sistema=20de=20selecci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/javascripts/01-types.js | 9 +--- app/assets/javascripts/02-editor.js | 78 +++++++++++++++-------------- app/assets/stylesheets/editor.scss | 1 - 3 files changed, 41 insertions(+), 47 deletions(-) diff --git a/app/assets/javascripts/01-types.js b/app/assets/javascripts/01-types.js index 62749598..369b650f 100644 --- a/app/assets/javascripts/01-types.js +++ b/app/assets/javascripts/01-types.js @@ -145,13 +145,6 @@ function rgb2hex(rgb) { return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); } -// Encuentra lx primer hijx de `selector` que esté en la selección dentro de `node` -const findInSelection = (selector, node) => { - for (const child of node.querySelectorAll(selector)) { - if (window.getSelection().containsNode(child)) return child - } -} - const getSelected = contentEl => contentEl.querySelector(".selected") const typesWithProperties = { @@ -172,7 +165,7 @@ const typesWithProperties = { setupInput (editorEl, contentEl) { const markColorInputEl = editorEl.querySelector(`*[data-prop="mark-color"]`) markColorInputEl.addEventListener("change", event => { - const markEl = findInSelection(marks.mark.selector, contentEl) + const markEl = contentEl.querySelector(marks.mark.selector + ".selected") if (markEl) markEl.style.backgroundColor = markColorInputEl.value }, false) }, diff --git a/app/assets/javascripts/02-editor.js b/app/assets/javascripts/02-editor.js index 0a839b3f..78938408 100644 --- a/app/assets/javascripts/02-editor.js +++ b/app/assets/javascripts/02-editor.js @@ -324,6 +324,42 @@ function cleanNode (node, contentEl) { } } +/* Generar el clickListener para este editor. + */ +function generateClickListener (editorEl, contentEl) { + /* El event listener para los typesWithProperties. + */ + return function clickListener (event) { + // Borrar todas las selecciones + for (const el of contentEl.querySelectorAll(".selected")) { + el.classList.remove("selected") + } + + setAuxiliaryToolbar(editorEl) + + let selectedType + let selectedEl + + for (const [name, type] of Object.entries(typesWithProperties)) { + type.disableInput(editorEl) + + let el = event.target + while (el && !el.matches(type.selector)) el = el.parentElement + if (el && contentEl.contains(el)) { + selectedType = type + selectedEl = el + } + } + + if (selectedType) { + event.preventDefault() + selectedType.updateInput(selectedEl, editorEl) + event.target.classList.add("selected") + return false + } + } +} + function setupEditor (editorEl) { // XXX: ¡Esto afecta a todo el documento! ¿Quizás usar un iframe para el editor? document.execCommand('defaultParagraphSeparator', false, 'p') @@ -342,46 +378,11 @@ function setupEditor (editorEl) { }) document.addEventListener("selectionchange", event => { cleanContent(contentEl) - - const sel = window.getSelection() - const range = sel.getRangeAt(0) - - let parentEl = range.commonAncestorContainer - if (parentEl.nodeType !== Node.ELEMENT_NODE) parentEl = parentEl.parentElement - - if (!contentEl.contains(parentEl)) return - - // Borrar todas las selecciones - for (const el of contentEl.querySelectorAll(".selected")) { - el.classList.remove("selected") - } - for (const el of contentEl.querySelectorAll(".selected-unactive")) { - el.classList.remove("selected-unactive") - } - - setAuxiliaryToolbar(editorEl) - - for (const [name, type] of Object.entries(typesWithProperties)) { - let i = 0 - const results = parentEl.querySelectorAll(type.selector) - - if (results.length) { - for (const el of results) { - if (!sel.containsNode(el)) continue - if (i === 0) { - type.updateInput(el, editorEl) - el.classList.add("selected") - } else { - el.classList.add("selected-unactive") - } - i++ - } - } else { - type.disableInput(editorEl) - } - } }) + const clickListener = generateClickListener(editorEl, contentEl) + contentEl.addEventListener("click", clickListener, true) + const htmlEl = editorEl.querySelector("textarea") const observer = new MutationObserver((mutationList, observer) => { cleanContent(contentEl) @@ -432,6 +433,7 @@ function setupEditor (editorEl) { cleanContent(contentEl) htmlEl.value = contentEl.innerHTML + fixContent(contentEl) } // TODO: por ahora confiamos, quizás queremos filtrar estilos? diff --git a/app/assets/stylesheets/editor.scss b/app/assets/stylesheets/editor.scss index af7ec76a..dcfa9528 100644 --- a/app/assets/stylesheets/editor.scss +++ b/app/assets/stylesheets/editor.scss @@ -14,7 +14,6 @@ } .selected { outline: #f206f9 solid medium; } - .selected-unactive { outline: gray solid medium; } img, video, iframe, audio { width: 100%; From c646ad3fe000c96a38515f30106d5cd10d169884 Mon Sep 17 00:00:00 2001 From: void Date: Mon, 16 Nov 2020 16:31:52 -0300 Subject: [PATCH 2/2] =?UTF-8?q?prevenir=20loop=20infinito=20arreglando=20p?= =?UTF-8?q?oner=20p=C3=A1rrafos=20autom=C3=A1gicamente=20cuando=20no=20los?= =?UTF-8?q?=20hay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/javascripts/02-editor.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/02-editor.js b/app/assets/javascripts/02-editor.js index 78938408..7e27e269 100644 --- a/app/assets/javascripts/02-editor.js +++ b/app/assets/javascripts/02-editor.js @@ -236,6 +236,14 @@ function cleanContent (contentEl) { } else if (!elementIsBlock(child)) { child.tagName = "P" } + } else if (child.nodeType === Node.TEXT_NODE) { + const wasSelected = sel.getRangeAt(0).intersectsNode(child) + + const el = document.createElement("p") + el.appendChild(child) + contentEl.insertBefore(el, child.nextSibling) + + if (wasSelected) sel.collapse(el, child.data.length) } } } @@ -246,12 +254,6 @@ function cleanContent (contentEl) { * * Wrappea el contenido de un UL o OL en un LI si no lo está */ function fixContent (contentEl) { - if (!contentEl.firstChild) { - const newEl = document.createElement("p") - contentEl.appendChild(newEl) - window.getSelection().collapse(newEl) - } - for (const child of contentEl.childNodes) { if (child.tagName) { if (elementIsParentBlock(child)) {