From b11346074af6590f68f57197079e4109a451b152 Mon Sep 17 00:00:00 2001 From: void Date: Sat, 27 Mar 2021 18:44:24 +0000 Subject: [PATCH] =?UTF-8?q?editor:=20desrepetir=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit esto me huele a que podría introducir bugs pero espero que no. --- app/javascript/editor/types.ts | 50 ++++++++++++++++++++- app/javascript/editor/types/blocks.ts | 38 +++++----------- app/javascript/editor/types/multimedia.ts | 31 ++----------- app/javascript/editor/types/parentBlocks.ts | 40 ++++------------- 4 files changed, 71 insertions(+), 88 deletions(-) diff --git a/app/javascript/editor/types.ts b/app/javascript/editor/types.ts index 0e75081..9bce809 100644 --- a/app/javascript/editor/types.ts +++ b/app/javascript/editor/types.ts @@ -3,7 +3,7 @@ import { marks } from 'editor/types/marks' import { blocks, li, EditorBlock } from 'editor/types/blocks' import { parentBlocks } from 'editor/types/parentBlocks' import { multimedia } from 'editor/types/multimedia' -import { blockNames, parentBlockNames } from 'editor/utils' +import { blockNames, parentBlockNames, safeGetRangeAt, safeGetSelection } from 'editor/utils' export interface EditorNode { selector: string, @@ -56,6 +56,54 @@ export function getType (node: Element): { typeName: string, type: EditorNode } return null } +// encuentra el primer pariente que pueda tener al type, y retorna un array +// donde +// array[0] = elemento que matchea el type +// array[array.len - 1] = primer elemento seleccionado +export function getValidParentInSelection (args: { + editor: Editor, + type: string, +}): Element[] { + const sel = safeGetSelection(args.editor) + if (!sel) throw new Error('No se donde insertar esto') + const range = safeGetRangeAt(sel) + if (!range) throw new Error('No se donde insertar esto') + + let list: Element[] = [] + + if (!sel.anchorNode) { + throw new Error('No se donde insertar esto') + } else if (sel.anchorNode instanceof Element) { + list = [sel.anchorNode] + } else if (sel.anchorNode.parentElement) { + list = [sel.anchorNode.parentElement] + } else { + throw new Error('No se donde insertar esto') + } + + while (true) { + const el = list[0] + if (!args.editor.contentEl.contains(el) + && el != args.editor.contentEl) + throw new Error('No se donde insertar esto') + const type = getType(el) + + if (type) { + //if (type.typeName === 'contentEl') break + //if (parentBlockNames.includes(type.typeName)) break + if ((type.type.allowedChildren instanceof Array) + && type.type.allowedChildren.includes(args.type)) break + } + if (el.parentElement) { + list = [el.parentElement, ...list] + } else { + throw new Error('No se donde insertar esto') + } + } + + return list +} + export function getValidChildren (node: Element, type: EditorNode): Node[] { if (type.allowedChildren === 'ignore-children') throw new Error('se llamó a getValidChildren con un type que no lo permite!') diff --git a/app/javascript/editor/types/blocks.ts b/app/javascript/editor/types/blocks.ts index 28f6384..52ad157 100644 --- a/app/javascript/editor/types/blocks.ts +++ b/app/javascript/editor/types/blocks.ts @@ -2,9 +2,9 @@ import { Editor } from 'editor/editor' import { safeGetSelection, safeGetRangeAt, moveChildren, - markNames, parentBlockNames, + markNames, blockNames, parentBlockNames, } from 'editor/utils' -import { EditorNode, getType } from 'editor/types' +import { EditorNode, getType, getValidParentInSelection } from 'editor/types' export interface EditorBlock extends EditorNode { } @@ -49,40 +49,22 @@ export function setupButtons (editor: Editor): void { buttonEl.addEventListener("click", event => { event.preventDefault() - const sel = safeGetSelection(editor) - if (!sel) return - const range = safeGetRangeAt(sel) - if (!range) return + const list = getValidParentInSelection({ editor, type: name }) - let blockEl = sel.anchorNode - while (true) { - if (!blockEl) throw new Error('WTF') - if (!blockEl.parentElement) throw new Error('No pude encontrar contentEl!') - - let type = getType(blockEl.parentElement) - if (!type) throw new Error('La selección está en algo que no es un type!') - - if (type.typeName === 'contentEl' - || parentBlockNames.includes(type.typeName) - ) break - - blockEl = blockEl.parentElement + // No borrar cosas como multimedia + if (blockNames.indexOf(getType(list[1])!.typeName) === -1) { + return } - if (!(blockEl instanceof Element)) - throw new Error('La selección no está en un elemento!') - const parentEl = blockEl.parentElement - if (!parentEl) throw new Error('Inesperado') - - let replacementType = blockEl.matches(type.selector) + let replacementType = list[1].matches(type.selector) ? blocks.paragraph : type const el = replacementType.create(editor) replacementType.onClick && replacementType.onClick(editor, el) - moveChildren(blockEl, el, null) - parentEl.replaceChild(el, blockEl) - sel.collapse(el) + moveChildren(list[1], el, null) + list[0].replaceChild(el, list[1]) + window.getSelection()?.collapse(el) return false }) diff --git a/app/javascript/editor/types/multimedia.ts b/app/javascript/editor/types/multimedia.ts index 7fdc0ca..7ebf8e8 100644 --- a/app/javascript/editor/types/multimedia.ts +++ b/app/javascript/editor/types/multimedia.ts @@ -1,5 +1,5 @@ import { Editor } from 'editor/editor' -import { EditorNode, getType } from 'editor/types' +import { EditorNode, getValidParentInSelection } from 'editor/types' import { safeGetSelection, safeGetRangeAt, markNames, parentBlockNames, @@ -192,34 +192,11 @@ export function setupButtons (editor: Editor): void { buttonEl.addEventListener('click', event => { event.preventDefault() - const sel = safeGetSelection(editor) - if (!sel) return - const range = safeGetRangeAt(sel) - if (!range) return - - let blockEl = sel.anchorNode - while (true) { - if (!blockEl) throw new Error('WTF') - if (!blockEl.parentElement) throw new Error('No pude encontrar contentEl!') - - let type = getType(blockEl.parentElement) - if (!type) throw new Error('La selección está en algo que no es un type!') - - if (type.typeName === 'contentEl' - || parentBlockNames.includes(type.typeName) - ) break - - blockEl = blockEl.parentElement - } - if (!(blockEl instanceof Element)) - throw new Error('La selección no está en un elemento!') - - const parentEl = blockEl.parentElement - if (!parentEl) throw new Error('Inesperado') + const list = getValidParentInSelection({ editor, type: 'multimedia' }) const el = multimedia.create(editor) - multimedia.onClick!(editor, el) - parentEl.insertBefore(el, blockEl.nextElementSibling) + list[0].insertBefore(el, list[1].nextElementSibling) + select(editor, el) return false }) diff --git a/app/javascript/editor/types/parentBlocks.ts b/app/javascript/editor/types/parentBlocks.ts index 9f78042..55a8c3d 100644 --- a/app/javascript/editor/types/parentBlocks.ts +++ b/app/javascript/editor/types/parentBlocks.ts @@ -4,7 +4,7 @@ import { moveChildren, blockNames, parentBlockNames, } from 'editor/utils' -import { EditorNode, getType } from 'editor/types' +import { EditorNode, getType, getValidParentInSelection } from 'editor/types' function makeParentBlock (tag: string, create: EditorNode["create"]): EditorNode { return { @@ -45,48 +45,24 @@ export function setupButtons (editor: Editor): void { buttonEl.addEventListener("click", event => { event.preventDefault() - const sel = safeGetSelection(editor) - if (!sel) return - const range = safeGetRangeAt(sel) - if (!range) return - // TODO: Esto solo mueve el bloque en el que está el final de la selección // (anchorNode). quizás lo podemos hacer al revés (iterar desde contentEl // para encontrar los bloques que están seleccionados y moverlos/cambiarles // el parentBlock) - let blockEl = sel.anchorNode - while (true) { - if (!blockEl) throw new Error('WTF') - if (!blockEl.parentElement) throw new Error('No pude encontrar contentEl!') - - let type = getType(blockEl.parentElement) - if (!type) throw new Error('La selección está en algo que no es un type!') - - if (type.typeName === 'contentEl' - || parentBlockNames.includes(type.typeName) - ) break - - blockEl = blockEl.parentElement - } - if (!(blockEl instanceof Element)) - throw new Error('La selección no está en un elemento!') - - const parentEl = blockEl.parentElement - if (!parentEl) - throw new Error('no') + const list = getValidParentInSelection({ editor, type: name }) const replacementEl = type.create(editor) - if (parentEl == editor.contentEl) { + if (list[0] == editor.contentEl) { // no está en un parentBlock - editor.contentEl.insertBefore(replacementEl, blockEl) - replacementEl.appendChild(blockEl) + editor.contentEl.insertBefore(replacementEl, list[1]) + replacementEl.appendChild(list[1]) } else { // está en un parentBlock - moveChildren(parentEl, replacementEl, null) - editor.contentEl.replaceChild(replacementEl, parentEl) + moveChildren(list[0], replacementEl, null) + editor.contentEl.replaceChild(replacementEl, list[0]) } - sel.collapse(replacementEl) + window.getSelection()?.collapse(replacementEl) return false })