5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-07-07 10:55:46 +00:00
panel/app/javascript/editor/types/marks.ts

88 lines
2.4 KiB
TypeScript
Raw Normal View History

import { Editor } from 'editor/editor'
import { EditorNode } from 'editor/types'
import { safeGetSelection, safeGetRangeAt, moveChildren, splitNode } from 'editor/utils'
export const markNames = ['bold', 'italic', 'deleted', 'underline', 'sub', 'super', 'mark', 'a']
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: makeMark('mark', 'mark'),
link: makeMark('link', 'a'),
}
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
if (!(range.commonAncestorContainer instanceof Element))
throw new Error(':/')
const existingMarks = recursiveFilterSelection(
range.commonAncestorContainer,
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 {
const tagEl = type.create()
try {
range.surroundContents(tagEl)
} catch (error) {
// TODO: mostrar error
return console.error("No puedo marcar cosas a través de distintos bloques!")
}
range.insertNode(tagEl)
range.selectNode(tagEl)
}
return false
})
}
}