mirror of
https://0xacab.org/sutty/sutty
synced 2024-07-05 23:55:45 +00:00
72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import { Editor } from 'editor/editor'
|
|
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'
|
|
|
|
export interface EditorNode {
|
|
selector: string,
|
|
// la string es el nombre en la gran lista de types O 'text'
|
|
// XXX: esto es un hack para no poner EditorNode dentro de EditorNode,
|
|
// quizás podemos hacer que esto sea una función que retorna bool
|
|
allowedChildren: string[] | 'ignore-children',
|
|
|
|
// * si es 'do-nothing', no hace nada si está vacío (esto es para cuando
|
|
// permitís 'text' entonces se puede tipear adentro, ej: párrafo vacío)
|
|
// * si es 'remove', sacamos el coso si está vacío.
|
|
// ej: strong: { handleNothing: 'remove' }
|
|
// * si es un block, insertamos el bloque y movemos la selección ahí
|
|
// ej: ul: { handleNothing: li }
|
|
handleEmpty: 'do-nothing' | 'remove' | EditorBlock,
|
|
|
|
create: (editor: Editor) => HTMLElement,
|
|
|
|
onClick?: (editor: Editor, target: Element) => void,
|
|
}
|
|
|
|
export const types: { [propName: string]: EditorNode } = {
|
|
...marks,
|
|
...blocks,
|
|
li,
|
|
...parentBlocks,
|
|
contentEl: {
|
|
selector: '.editor-content',
|
|
allowedChildren: [...blockNames, ...parentBlockNames, 'multimedia'],
|
|
handleEmpty: blocks.paragraph,
|
|
create: () => { throw new Error('se intentó crear contentEl') }
|
|
},
|
|
br: {
|
|
selector: 'br',
|
|
allowedChildren: [],
|
|
handleEmpty: 'do-nothing',
|
|
create: () => { throw new Error('se intentó crear br') }
|
|
},
|
|
multimedia,
|
|
}
|
|
|
|
export function getType (node: Element): { typeName: string, type: EditorNode } | null {
|
|
for (let [typeName, type] of Object.entries(types)) {
|
|
if (node.matches(type.selector)) return { typeName, type }
|
|
}
|
|
return null
|
|
}
|
|
|
|
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!')
|
|
return [...node.childNodes].filter(n => {
|
|
// si permite texto y esto es un texto, es válido
|
|
if (n.nodeType === Node.TEXT_NODE)
|
|
return type.allowedChildren.includes('text')
|
|
|
|
// si no es un elemento, no es válido
|
|
if (!(n instanceof Element))
|
|
return false
|
|
|
|
const t = getType(n)
|
|
if (!t) return false
|
|
return type.allowedChildren.includes(t.typeName)
|
|
})
|
|
}
|