2021-02-12 15:57:23 +00:00
|
|
|
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
|
|
|
|
|
2021-02-12 19:10:55 +00:00
|
|
|
let parentEl = range.commonAncestorContainer
|
|
|
|
while (!(parentEl instanceof Element)) {
|
|
|
|
if (!parentEl.parentElement) return
|
|
|
|
parentEl = parentEl.parentElement
|
|
|
|
}
|
|
|
|
|
2021-02-12 15:57:23 +00:00
|
|
|
const existingMarks = recursiveFilterSelection(
|
2021-02-12 19:10:55 +00:00
|
|
|
parentEl,
|
2021-02-12 15:57:23 +00:00
|
|
|
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 {
|
2021-02-12 19:10:55 +00:00
|
|
|
if (range.commonAncestorContainer === editor.contentEl)
|
2021-02-12 15:57:23 +00:00
|
|
|
// TODO: mostrar error
|
|
|
|
return console.error("No puedo marcar cosas a través de distintos bloques!")
|
2021-02-12 19:10:55 +00:00
|
|
|
|
|
|
|
const tagEl = type.create()
|
|
|
|
|
|
|
|
tagEl.appendChild(range.extractContents())
|
2021-02-12 15:57:23 +00:00
|
|
|
|
|
|
|
range.insertNode(tagEl)
|
|
|
|
range.selectNode(tagEl)
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|