sutty/app/javascript/editor/types/parentBlocks.ts

95 lines
2.7 KiB
TypeScript
Raw Normal View History

import { Editor } from 'editor/editor'
import {
safeGetSelection, safeGetRangeAt,
moveChildren,
blockNames, parentBlockNames,
} from 'editor/utils'
import { EditorNode, getType } from 'editor/types'
function makeParentBlock (tag: string, create: EditorNode["create"]): EditorNode {
return {
selector: tag,
allowedChildren: blockNames,
handleEmpty: 'remove',
create,
}
}
// TODO: añadir blockquote
// XXX: si agregás algo acá, probablemente le quieras hacer un botón
// en app/views/posts/attributes/_content.haml
export const parentBlocks: { [propName: string]: EditorNode } = {
left: makeParentBlock('div[data-align=left]', () => {
const el = document.createElement('div')
el.dataset.align = 'left'
return el
}),
center: makeParentBlock('div[data-align=center]', () => {
const el = document.createElement('div')
el.dataset.align = 'center'
return el
}),
right: makeParentBlock('div[data-align=right]', () => {
const el = document.createElement('div')
el.dataset.align = 'right'
return el
}),
}
export function setupButtons (editor: Editor): void {
for (const [ name, type ] of Object.entries(parentBlocks)) {
const buttonEl = editor.toolbarEl.querySelector(
`[data-editor-button="parentBlock-${name}"]`
)
if (!buttonEl) continue
buttonEl.addEventListener("click", event => {
event.preventDefault()
const sel = safeGetSelection(editor)
if (!sel) return
const range = safeGetRangeAt(sel)
if (!range) return
// TODO: Esto solo mueve el bloque en el que está el final de la selección
// (anchorNode). quizás lo podemos hacer al revés (iterar desde contentEl
// para encontrar los bloques que están seleccionados y moverlos/cambiarles
// el parentBlock)
let blockEl = sel.anchorNode
while (true) {
if (!blockEl) throw new Error('WTF')
if (!blockEl.parentElement) throw new Error('No pude encontrar contentEl!')
let type = getType(blockEl.parentElement)
if (!type) throw new Error('La selección está en algo que no es un type!')
if (type.typeName === 'contentEl'
|| parentBlockNames.includes(type.typeName)
) break
blockEl = blockEl.parentElement
}
if (!(blockEl instanceof Element))
throw new Error('La selección no está en un elemento!')
const parentEl = blockEl.parentElement
if (!parentEl)
throw new Error('no')
2021-02-13 01:14:36 +00:00
const replacementEl = type.create(editor)
if (parentEl == editor.contentEl) {
// no está en un parentBlock
editor.contentEl.insertBefore(replacementEl, blockEl)
replacementEl.appendChild(blockEl)
} else {
// está en un parentBlock
moveChildren(parentEl, replacementEl, null)
editor.contentEl.replaceChild(replacementEl, parentEl)
}
sel.collapse(replacementEl)
return false
})
}
}