editor: hacer que sea posible poner parentBlocks y reestructurar

This commit is contained in:
void 2021-02-12 22:18:48 +00:00
parent c9d0fb87a4
commit 0602c6ccb8
6 changed files with 87 additions and 26 deletions

View file

@ -1,9 +1,9 @@
import { storeContent, restoreContent } from 'editor/storage'
import { isDirectChild, moveChildren, safeGetSelection, safeGetRangeAt } from 'editor/utils'
import { types, EditorNode, getValidChildren, getType } from 'editor/types'
import { types, getValidChildren, getType } from 'editor/types'
import { setupButtons as setupMarksButtons } from 'editor/types/marks'
import { blocks, EditorBlock, setupButtons as setupBlocksButtons } from 'editor/types/blocks'
import { parentBlocks, parentBlockNames } from 'editor/types/parentBlocks'
import { setupButtons as setupBlocksButtons } from 'editor/types/blocks'
import { setupButtons as setupParentBlocksButtons } from 'editor/types/parentBlocks'
export interface Editor {
editorEl: HTMLElement,
@ -177,6 +177,7 @@ function setupEditor (editorEl: HTMLElement): void {
// Setup botones
setupMarksButtons(editor)
setupBlocksButtons(editor)
setupParentBlocksButtons(editor)
// Finally...
routine(editor)

View file

@ -1,6 +1,7 @@
import { marks } from 'editor/types/marks'
import { blocks, li, blockNames, EditorBlock } from 'editor/types/blocks'
import { blocks, li, EditorBlock } from 'editor/types/blocks'
import { parentBlocks } from 'editor/types/parentBlocks'
import { blockNames } from 'editor/utils'
export interface EditorNode {
selector: string,

View file

@ -1,8 +1,10 @@
import { Editor } from 'editor/editor'
import { safeGetSelection, safeGetRangeAt, moveChildren } from 'editor/utils'
import {
safeGetSelection, safeGetRangeAt,
moveChildren,
markNames, parentBlockNames,
} from 'editor/utils'
import { EditorNode, getType } from 'editor/types'
import { markNames } from 'editor/types/marks'
import { parentBlockNames } from 'editor/types/parentBlocks'
// TODO: implementar multimedia como otro tipo! ya que no puede tener children
// debe ser tratado distinto que los bloques (quizás EditorBlockWithText y
@ -11,22 +13,12 @@ import { parentBlockNames } from 'editor/types/parentBlocks'
export interface EditorBlock extends EditorNode {
}
export const blockNames = ['paragraph', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'unordered_list', 'ordered_list']
function makeBlock (tag: string): EditorBlock {
return {
selector: tag,
allowedChildren: [...markNames, 'text'],
handleEmpty: 'do-nothing',
create: () => {
const el = document.createElement(tag)
return el
//moveChildren(el, newEl, null)
//el.parentNode!.replaceChild(newEl, el)
//// TODO: mantener la selección
//const sel = window.getSelection()
//sel && sel.collapse(newEl, 0)
},
create: () => document.createElement(tag),
}
}

View file

@ -1,8 +1,10 @@
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']
import {
safeGetSelection, safeGetRangeAt,
moveChildren,
markNames,
} from 'editor/utils'
function makeMark (name: string, tag: string): EditorNode {
return {

View file

@ -1,18 +1,24 @@
import { blockNames, EditorBlock } from 'editor/types/blocks'
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: EditorBlock["create"]): EditorBlock {
function makeParentBlock (tag: string, create: EditorNode["create"]): EditorNode {
return {
selector: tag,
allowedChildren: blockNames,
handleEmpty: 'remove',
create: create,
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]: EditorBlock } = {
export const parentBlocks: { [propName: string]: EditorNode } = {
left: makeParentBlock('div[data-align=left]', () => {
const el = document.createElement('div')
el.dataset.align = 'left'
@ -30,4 +36,59 @@ export const parentBlocks: { [propName: string]: EditorBlock } = {
}),
}
export const parentBlockNames = Object.keys(parentBlocks)
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')
const replacementEl = type.create()
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
})
}
}

View file

@ -1,5 +1,9 @@
import { Editor } from 'editor/editor'
export const blockNames = ['paragraph', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'unordered_list', 'ordered_list']
export const markNames = ['bold', 'italic', 'deleted', 'underline', 'sub', 'super', 'mark', 'a']
export const parentBlockNames = ['left', 'center', 'right']
export function moveChildren (from: Element, to: Element, toRef: Node | null) {
while (from.firstChild) to.insertBefore(from.firstChild, toRef)
}