mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-15 05:41:42 +00:00
Merge branch 'void/editor' into rails
This commit is contained in:
commit
365146ed59
8 changed files with 59 additions and 35 deletions
|
@ -1,5 +1,5 @@
|
||||||
import { storeContent, restoreContent, forgetContent } from 'editor/storage'
|
import { storeContent, restoreContent, forgetContent } from 'editor/storage'
|
||||||
import { isDirectChild, moveChildren, safeGetSelection, safeGetRangeAt, setAuxiliaryToolbar } from 'editor/utils'
|
import { isDirectChild, moveChildren, safeGetSelection, safeGetRangeAt, setAuxiliaryToolbar, parentBlockNames, clearSelected } from 'editor/utils'
|
||||||
import { types, getValidChildren, getType } from 'editor/types'
|
import { types, getValidChildren, getType } from 'editor/types'
|
||||||
import { setupButtons as setupMarksButtons } from 'editor/types/marks'
|
import { setupButtons as setupMarksButtons } from 'editor/types/marks'
|
||||||
import { setupButtons as setupBlocksButtons } from 'editor/types/blocks'
|
import { setupButtons as setupBlocksButtons } from 'editor/types/blocks'
|
||||||
|
@ -252,8 +252,7 @@ function setupEditor (editorEl: HTMLElement): void {
|
||||||
const type = getType(target)
|
const type = getType(target)
|
||||||
if (!type || !type.type.onClick) {
|
if (!type || !type.type.onClick) {
|
||||||
setAuxiliaryToolbar(editor, null)
|
setAuxiliaryToolbar(editor, null)
|
||||||
const selectedEl = editor.contentEl.querySelector('[data-editor-selected]')
|
clearSelected(editor)
|
||||||
if (selectedEl) delete (selectedEl as HTMLElement).dataset.editorSelected
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
type.type.onClick(editor, target)
|
type.type.onClick(editor, target)
|
||||||
|
@ -279,19 +278,19 @@ function setupEditor (editorEl: HTMLElement): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("turbolinks:load", () => {
|
document.addEventListener("turbolinks:load", () => {
|
||||||
const flash = document.querySelector<HTMLElement>('.js-flash')
|
const flash = document.querySelector<HTMLElement>('.js-flash')
|
||||||
|
|
||||||
if (flash) {
|
if (flash) {
|
||||||
const keys = JSON.parse(flash.dataset.keys || '')
|
const keys = JSON.parse(flash.dataset.keys || '[]')
|
||||||
|
|
||||||
switch (flash.dataset.target) {
|
switch (flash.dataset.target) {
|
||||||
case 'editor':
|
case 'editor':
|
||||||
switch (flash.dataset.action) {
|
switch (flash.dataset.action) {
|
||||||
case 'forget-content':
|
case 'forget-content':
|
||||||
keys.forEach(forgetContent)
|
keys.forEach(forgetContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const editorEl of document.querySelectorAll<HTMLElement>('.editor[data-editor]')) {
|
for (const editorEl of document.querySelectorAll<HTMLElement>('.editor[data-editor]')) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -20,6 +20,10 @@ export interface EditorNode {
|
||||||
// ej: ul: { handleNothing: li }
|
// ej: ul: { handleNothing: li }
|
||||||
handleEmpty: 'do-nothing' | 'remove' | EditorBlock,
|
handleEmpty: 'do-nothing' | 'remove' | EditorBlock,
|
||||||
|
|
||||||
|
// esta función puede ser llamada para cosas que no necesariamente sea la
|
||||||
|
// creación del nodo con el botón; por ejemplo, al intentar recuperar
|
||||||
|
// el formato. esto es importante por que, por ejemplo, no deberíamos
|
||||||
|
// cambiar la selección acá.
|
||||||
create: (editor: Editor) => HTMLElement,
|
create: (editor: Editor) => HTMLElement,
|
||||||
|
|
||||||
onClick?: (editor: Editor, target: Element) => void,
|
onClick?: (editor: Editor, target: Element) => void,
|
||||||
|
|
|
@ -79,6 +79,7 @@ export function setupButtons (editor: Editor): void {
|
||||||
: type
|
: type
|
||||||
|
|
||||||
const el = replacementType.create(editor)
|
const el = replacementType.create(editor)
|
||||||
|
replacementType.onClick && replacementType.onClick(editor, el)
|
||||||
moveChildren(blockEl, el, null)
|
moveChildren(blockEl, el, null)
|
||||||
parentEl.replaceChild(el, blockEl)
|
parentEl.replaceChild(el, blockEl)
|
||||||
sel.collapse(el)
|
sel.collapse(el)
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import { Editor } from 'editor/editor'
|
import { Editor } from 'editor/editor'
|
||||||
import { EditorNode } from 'editor/types'
|
import { EditorNode } from 'editor/types'
|
||||||
import { markNames, setAuxiliaryToolbar } from 'editor/utils'
|
import { markNames, setAuxiliaryToolbar, clearSelected } from 'editor/utils'
|
||||||
|
|
||||||
|
function select (editor: Editor, el: HTMLAnchorElement): void {
|
||||||
|
clearSelected(editor)
|
||||||
|
el.dataset.editorSelected = ''
|
||||||
|
editor.toolbar.auxiliary.link.urlEl.value = el.href
|
||||||
|
setAuxiliaryToolbar(editor, editor.toolbar.auxiliary.link.parentEl)
|
||||||
|
}
|
||||||
|
|
||||||
export const link: EditorNode = {
|
export const link: EditorNode = {
|
||||||
selector: 'a',
|
selector: 'a',
|
||||||
|
@ -10,9 +17,7 @@ export const link: EditorNode = {
|
||||||
onClick (editor, el) {
|
onClick (editor, el) {
|
||||||
if (!(el instanceof HTMLAnchorElement))
|
if (!(el instanceof HTMLAnchorElement))
|
||||||
throw new Error('oh no')
|
throw new Error('oh no')
|
||||||
el.dataset.editorSelected = ''
|
select(editor, el)
|
||||||
editor.toolbar.auxiliary.link.urlEl.value = el.href
|
|
||||||
setAuxiliaryToolbar(editor, editor.toolbar.auxiliary.link.parentEl)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Editor } from 'editor/editor'
|
import { Editor } from 'editor/editor'
|
||||||
import { EditorNode } from 'editor/types'
|
import { EditorNode } from 'editor/types'
|
||||||
import { markNames, setAuxiliaryToolbar } from 'editor/utils'
|
import { markNames, setAuxiliaryToolbar, clearSelected } from 'editor/utils'
|
||||||
|
|
||||||
const hex = (x: string) => ("0" + parseInt(x).toString(16)).slice(-2)
|
const hex = (x: string) => ("0" + parseInt(x).toString(16)).slice(-2)
|
||||||
// https://stackoverflow.com/a/3627747
|
// https://stackoverflow.com/a/3627747
|
||||||
|
@ -11,6 +11,16 @@ function rgbToHex (rgb: string): string {
|
||||||
return "#" + hex(matches[1]) + hex(matches[2]) + hex(matches[3])
|
return "#" + hex(matches[1]) + hex(matches[2]) + hex(matches[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function select (editor: Editor, el: HTMLElement): void {
|
||||||
|
clearSelected(editor)
|
||||||
|
el.dataset.editorSelected = ''
|
||||||
|
editor.toolbar.auxiliary.mark.colorEl.value
|
||||||
|
= el.style.backgroundColor
|
||||||
|
? rgbToHex(el.style.backgroundColor)
|
||||||
|
: '#f206f9'
|
||||||
|
setAuxiliaryToolbar(editor, editor.toolbar.auxiliary.mark.parentEl)
|
||||||
|
}
|
||||||
|
|
||||||
export const mark: EditorNode = {
|
export const mark: EditorNode = {
|
||||||
selector: 'mark',
|
selector: 'mark',
|
||||||
allowedChildren: [...markNames.filter(n => n !== 'mark'), 'text'],
|
allowedChildren: [...markNames.filter(n => n !== 'mark'), 'text'],
|
||||||
|
@ -19,12 +29,7 @@ export const mark: EditorNode = {
|
||||||
onClick (editor, el) {
|
onClick (editor, el) {
|
||||||
if (!(el instanceof HTMLElement))
|
if (!(el instanceof HTMLElement))
|
||||||
throw new Error('oh no')
|
throw new Error('oh no')
|
||||||
el.dataset.editorSelected = ''
|
select(editor, el)
|
||||||
editor.toolbar.auxiliary.mark.colorEl.value
|
|
||||||
= el.style.backgroundColor
|
|
||||||
? rgbToHex(el.style.backgroundColor)
|
|
||||||
: '#f206f9'
|
|
||||||
setAuxiliaryToolbar(editor, editor.toolbar.auxiliary.mark.parentEl)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {
|
||||||
safeGetSelection, safeGetRangeAt,
|
safeGetSelection, safeGetRangeAt,
|
||||||
moveChildren,
|
moveChildren,
|
||||||
markNames,
|
markNames,
|
||||||
setAuxiliaryToolbar,
|
|
||||||
} from 'editor/utils'
|
} from 'editor/utils'
|
||||||
import { link } from 'editor/types/link'
|
import { link } from 'editor/types/link'
|
||||||
import { mark } from 'editor/types/mark'
|
import { mark } from 'editor/types/mark'
|
||||||
|
@ -82,6 +81,7 @@ export function setupButtons (editor: Editor): void {
|
||||||
return console.error("No puedo marcar cosas a través de distintos bloques!")
|
return console.error("No puedo marcar cosas a través de distintos bloques!")
|
||||||
|
|
||||||
const tagEl = type.create(editor)
|
const tagEl = type.create(editor)
|
||||||
|
type.onClick && type.onClick(editor, tagEl)
|
||||||
|
|
||||||
tagEl.appendChild(range.extractContents())
|
tagEl.appendChild(range.extractContents())
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { EditorNode, getType } from 'editor/types'
|
||||||
import {
|
import {
|
||||||
safeGetSelection, safeGetRangeAt,
|
safeGetSelection, safeGetRangeAt,
|
||||||
markNames, parentBlockNames,
|
markNames, parentBlockNames,
|
||||||
setAuxiliaryToolbar,
|
setAuxiliaryToolbar, clearSelected,
|
||||||
} from 'editor/utils'
|
} from 'editor/utils'
|
||||||
|
|
||||||
// TODO: tener ActiveStorage como import así no hacemos hacks
|
// TODO: tener ActiveStorage como import así no hacemos hacks
|
||||||
|
@ -59,6 +59,18 @@ function setAlt (multimediaInnerEl: HTMLElement, value: string): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function select (editor: Editor, el: HTMLElement): void {
|
||||||
|
clearSelected(editor)
|
||||||
|
el.dataset.editorSelected = ''
|
||||||
|
|
||||||
|
const innerEl = el.querySelector<HTMLElement>('[data-multimedia-inner]')
|
||||||
|
if (!innerEl) throw new Error('No hay multimedia válida')
|
||||||
|
if (innerEl.tagName !== 'P')
|
||||||
|
editor.toolbar.auxiliary.multimedia.altEl.value = getAlt(innerEl) || ''
|
||||||
|
|
||||||
|
setAuxiliaryToolbar(editor, editor.toolbar.auxiliary.multimedia.parentEl)
|
||||||
|
}
|
||||||
|
|
||||||
export const multimedia: EditorNode = {
|
export const multimedia: EditorNode = {
|
||||||
selector: 'figure[data-multimedia]',
|
selector: 'figure[data-multimedia]',
|
||||||
allowedChildren: 'ignore-children',
|
allowedChildren: 'ignore-children',
|
||||||
|
@ -85,14 +97,7 @@ export const multimedia: EditorNode = {
|
||||||
onClick (editor, el) {
|
onClick (editor, el) {
|
||||||
if (!(el instanceof HTMLElement))
|
if (!(el instanceof HTMLElement))
|
||||||
throw new Error('oh no')
|
throw new Error('oh no')
|
||||||
el.dataset.editorSelected = ''
|
select(editor, el)
|
||||||
|
|
||||||
const innerEl = el.querySelector<HTMLElement>('[data-multimedia-inner]')
|
|
||||||
if (!innerEl) throw new Error('No hay multimedia válida')
|
|
||||||
if (innerEl.tagName !== 'P')
|
|
||||||
editor.toolbar.auxiliary.multimedia.altEl.value = getAlt(innerEl) || ''
|
|
||||||
|
|
||||||
setAuxiliaryToolbar(editor, editor.toolbar.auxiliary.multimedia.parentEl)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
function createElementWithFile (url: string, type: string): HTMLElement {
|
function createElementWithFile (url: string, type: string): HTMLElement {
|
||||||
|
@ -213,6 +218,7 @@ export function setupButtons (editor: Editor): void {
|
||||||
if (!parentEl) throw new Error('Inesperado')
|
if (!parentEl) throw new Error('Inesperado')
|
||||||
|
|
||||||
const el = multimedia.create(editor)
|
const el = multimedia.create(editor)
|
||||||
|
multimedia.onClick!(editor, el)
|
||||||
parentEl.insertBefore(el, blockEl.nextElementSibling)
|
parentEl.insertBefore(el, blockEl.nextElementSibling)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -71,3 +71,7 @@ export function setAuxiliaryToolbar (editor: Editor, bar: HTMLElement | null): v
|
||||||
}
|
}
|
||||||
if (bar) bar.dataset.editorAuxiliaryActive = 'active'
|
if (bar) bar.dataset.editorAuxiliaryActive = 'active'
|
||||||
}
|
}
|
||||||
|
export function clearSelected (editor: Editor): void {
|
||||||
|
const selectedEl = editor.contentEl.querySelector('[data-editor-selected]')
|
||||||
|
if (selectedEl) delete (selectedEl as HTMLElement).dataset.editorSelected
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue