mirror of
https://0xacab.org/sutty/sutty
synced 2024-07-07 10:55:46 +00:00
88 lines
2.4 KiB
TypeScript
88 lines
2.4 KiB
TypeScript
![]() |
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
|
||
|
})
|
||
|
}
|
||
|
}
|