diff --git a/app/assets/javascripts/02-editor.js b/app/javascript/editor/editor.js similarity index 89% rename from app/assets/javascripts/02-editor.js rename to app/javascript/editor/editor.js index 2227c60b..d44cdb50 100644 --- a/app/assets/javascripts/02-editor.js +++ b/app/javascript/editor/editor.js @@ -1,3 +1,13 @@ +import { + moveChildren, + marks, + blocks, + parentBlocks, + typesWithProperties, + setAuxiliaryToolbar, + tagNameSetFn +} from 'editor/types' + const origin = location.origin /* @@ -27,7 +37,7 @@ const restoreContent = (editorEl, contentEl) => { /* getRangeAt puede fallar si no hay una selección */ -function safeGetRangeAt (num) { +const safeGetRangeAt = (num) => { try { return window.getSelection().getRangeAt(num) } catch (error) { @@ -36,48 +46,27 @@ function safeGetRangeAt (num) { } } -function uploadFile (file) { - return new Promise((resolve, reject) => { - const upload = new ActiveStorage.DirectUpload( - file, - origin + '/rails/active_storage/direct_uploads', - ) - upload.create((error, blob) => { - if (error) { - reject(error) - } else { - const url = `${origin}/rails/active_storage/blobs/${blob.signed_id}/${blob.filename}` - resolve(url) - } - }) - }) -} - -function moveChildren (from, to, toRef) { - while (from.firstChild) to.insertBefore(from.firstChild, toRef); -} - -function isDirectChild (node, supposedChild) { +const isDirectChild = (node, supposedChild) => { for (const child of node.childNodes) { if (child == supposedChild) return true } } -function isChildSelection (sel, el) { +const isChildSelection = (sel, el) => { return ( (el.contains(sel.anchorNode) || el.contains(sel.focusNode)) && !(sel.anchorNode == el || sel.focusNode == el) ) } -function getElementParent (node) { +const getElementParent = (node) => { let parentEl = node while (parentEl.nodeType != Node.ELEMENT_NODE) parentEl = parentEl.parentElement return parentEl } -function splitNode (node, range) { +const splitNode = (node, range) => { const [left, right] = [ { range: document.createRange(), node: node.cloneNode(false) }, { range: document.createRange(), node: node.cloneNode(false) }, @@ -109,7 +98,7 @@ function splitNode (node, range) { * * mark: un objeto que representa el tipo de acción (ver types.js) * * contentEl: el elemento de contenido del editor. */ -function setupMarkButton (button, mark, contentEl) { +const setupMarkButton = (button, mark, contentEl) => { button.addEventListener("click", event => { event.preventDefault() @@ -168,7 +157,7 @@ function setupMarkButton (button, mark, contentEl) { } /* Igual que `setupMarkButton` pero para bloques. */ -function setupBlockButton (button, block, contentEl, editorEl) { +const setupBlockButton = (button, block, contentEl, editorEl) => { button.addEventListener("click", event => { event.preventDefault() @@ -203,7 +192,7 @@ function setupBlockButton (button, block, contentEl, editorEl) { } /* Igual que `setupBlockButton` pero para bloques parientes. */ -function setupParentBlockButton (button, parentBlock, contentEl) { +const setupParentBlockButton = (button, parentBlock, contentEl) => { button.addEventListener("click", event => { event.preventDefault() @@ -246,7 +235,7 @@ const elementIsTypes = types => element => { const elementIsBlock = elementIsTypes(blocks) const elementIsParentBlock = elementIsTypes(parentBlocks) -function hasContent (element) { +const hasContent = (element) => { if (element.firstElementChild) return true for (const child of element.childNodes) { if (child.nodeType === Node.TEXT_NODE && child.data.length > 0) return true @@ -266,7 +255,7 @@ function hasContent (element) { * * Cambia el tag de los bloques no reconocidos (ver `elementIsBlock`) * * Hace lo que hace cleanNode */ -function cleanContent (contentEl) { +const cleanContent = (contentEl) => { const sel = window.getSelection() cleanNode(contentEl, contentEl) @@ -276,14 +265,18 @@ function cleanContent (contentEl) { if (elementIsParentBlock(child)) { cleanContent(child) } else if (!elementIsBlock(child)) { - child.tagName = "P" + const el = document.createElement("p") + moveChildren(child, el, null) + contentEl.insertBefore(el, child) + child.parentNode.removeChild(child) } } else if (child.nodeType === Node.TEXT_NODE) { const el = document.createElement("p") contentEl.insertBefore(el, child.nextSibling) el.appendChild(child) - sel.collapse(el, el.textContent.length) + sel.selectAllChildren(el) + sel.collapseToEnd() } } } @@ -293,7 +286,7 @@ function cleanContent (contentEl) { * * Crea un p y inserta la selección si no hay elementos * * Wrappea el contenido de un UL o OL en un LI si no lo está */ -function fixContent (contentEl) { +const fixContent = (contentEl) => { for (const child of contentEl.childNodes) { if (child.tagName) { if (elementIsParentBlock(child)) { @@ -323,7 +316,7 @@ function fixContent (contentEl) { * * Borra propiedades de IMG no autorizadas * * Borra y