import { Editor } from "editor/editor"; import { EditorNode } from "editor/types"; import { safeGetSelection, safeGetRangeAt, moveChildren, markNames, } from "editor/utils"; import { link } from "editor/types/link"; import { mark } from "editor/types/mark"; function makeMark(name: string, tag: string): EditorNode { return { selector: tag, allowedChildren: [...markNames.filter((n) => n !== name), "text"], handleEmpty: "remove", create: () => document.createElement(tag), }; } // XXX: si agregás algo acá, agregalo a markNames export const marks: { [propName: string]: EditorNode } = { bold: makeMark("bold", "strong"), italic: makeMark("italic", "em"), deleted: makeMark("deleted", "del"), underline: makeMark("underline", "u"), sub: makeMark("sub", "sub"), super: makeMark("super", "sup"), mark, link, small: makeMark("small", "small"), }; function recursiveFilterSelection( node: Element, selection: Selection, selector: string ): Element[] { let output: Element[] = []; for (const child of [...node.children]) { if (child.matches(selector) && selection.containsNode(child)) output.push(child); output = [ ...output, ...recursiveFilterSelection(child, selection, selector), ]; } return output; } export function setupButtons(editor: Editor): void { for (const [name, type] of Object.entries(marks)) { const buttonEl = editor.toolbarEl.querySelector( `[data-editor-button="mark-${name}"]` ); if (!buttonEl) continue; buttonEl.addEventListener("click", (event) => { event.preventDefault(); const sel = safeGetSelection(editor); if (!sel) return; const range = safeGetRangeAt(sel); if (!range) return; let parentEl = range.commonAncestorContainer; while (!(parentEl instanceof Element)) { if (!parentEl.parentElement) return; parentEl = parentEl.parentElement; } const existingMarks = recursiveFilterSelection( parentEl, sel, type.selector ); console.debug("marks encontradas:", existingMarks); if (existingMarks.length > 0) { const mark = existingMarks[0]; if (!mark.parentElement) throw new Error(":/"); moveChildren(mark, mark.parentElement, mark); mark.parentElement.removeChild(mark); } else { if (range.commonAncestorContainer === editor.contentEl) // TODO: mostrar error return console.error( "No puedo marcar cosas a través de distintos bloques!" ); const tagEl = type.create(editor); type.onClick && type.onClick(editor, tagEl); tagEl.appendChild(range.extractContents()); range.insertNode(tagEl); range.selectNode(tagEl); } return false; }); } }