5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-15 04:41:43 +00:00

Merge branch 'editor-nuevo' of 0xacab.org:sutty/sutty into editor-nuevo

This commit is contained in:
f 2020-11-16 17:05:48 -03:00
commit cc0dcf47a7
3 changed files with 49 additions and 53 deletions

View file

@ -145,13 +145,6 @@ function rgb2hex(rgb) {
return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
} }
// Encuentra lx primer hijx de `selector` que esté en la selección dentro de `node`
const findInSelection = (selector, node) => {
for (const child of node.querySelectorAll(selector)) {
if (window.getSelection().containsNode(child)) return child
}
}
const getSelected = contentEl => contentEl.querySelector(".selected") const getSelected = contentEl => contentEl.querySelector(".selected")
const typesWithProperties = { const typesWithProperties = {
@ -172,7 +165,7 @@ const typesWithProperties = {
setupInput (editorEl, contentEl) { setupInput (editorEl, contentEl) {
const markColorInputEl = editorEl.querySelector(`*[data-prop="mark-color"]`) const markColorInputEl = editorEl.querySelector(`*[data-prop="mark-color"]`)
markColorInputEl.addEventListener("change", event => { markColorInputEl.addEventListener("change", event => {
const markEl = findInSelection(marks.mark.selector, contentEl) const markEl = contentEl.querySelector(marks.mark.selector + ".selected")
if (markEl) markEl.style.backgroundColor = markColorInputEl.value if (markEl) markEl.style.backgroundColor = markColorInputEl.value
}, false) }, false)
}, },

View file

@ -236,6 +236,14 @@ function cleanContent (contentEl) {
} else if (!elementIsBlock(child)) { } else if (!elementIsBlock(child)) {
child.tagName = "P" child.tagName = "P"
} }
} else if (child.nodeType === Node.TEXT_NODE) {
const wasSelected = sel.getRangeAt(0).intersectsNode(child)
const el = document.createElement("p")
el.appendChild(child)
contentEl.insertBefore(el, child.nextSibling)
if (wasSelected) sel.collapse(el, child.data.length)
} }
} }
} }
@ -246,12 +254,6 @@ function cleanContent (contentEl) {
* * Wrappea el contenido de un UL o OL en un LI si no lo está * * Wrappea el contenido de un UL o OL en un LI si no lo está
*/ */
function fixContent (contentEl) { function fixContent (contentEl) {
if (!contentEl.firstChild) {
const newEl = document.createElement("p")
contentEl.appendChild(newEl)
window.getSelection().collapse(newEl)
}
for (const child of contentEl.childNodes) { for (const child of contentEl.childNodes) {
if (child.tagName) { if (child.tagName) {
if (elementIsParentBlock(child)) { if (elementIsParentBlock(child)) {
@ -324,6 +326,42 @@ function cleanNode (node, contentEl) {
} }
} }
/* Generar el clickListener para este editor.
*/
function generateClickListener (editorEl, contentEl) {
/* El event listener para los typesWithProperties.
*/
return function clickListener (event) {
// Borrar todas las selecciones
for (const el of contentEl.querySelectorAll(".selected")) {
el.classList.remove("selected")
}
setAuxiliaryToolbar(editorEl)
let selectedType
let selectedEl
for (const [name, type] of Object.entries(typesWithProperties)) {
type.disableInput(editorEl)
let el = event.target
while (el && !el.matches(type.selector)) el = el.parentElement
if (el && contentEl.contains(el)) {
selectedType = type
selectedEl = el
}
}
if (selectedType) {
event.preventDefault()
selectedType.updateInput(selectedEl, editorEl)
event.target.classList.add("selected")
return false
}
}
}
function setupEditor (editorEl) { function setupEditor (editorEl) {
// XXX: ¡Esto afecta a todo el documento! ¿Quizás usar un iframe para el editor? // XXX: ¡Esto afecta a todo el documento! ¿Quizás usar un iframe para el editor?
document.execCommand('defaultParagraphSeparator', false, 'p') document.execCommand('defaultParagraphSeparator', false, 'p')
@ -342,46 +380,11 @@ function setupEditor (editorEl) {
}) })
document.addEventListener("selectionchange", event => { document.addEventListener("selectionchange", event => {
cleanContent(contentEl) cleanContent(contentEl)
const sel = window.getSelection()
const range = sel.getRangeAt(0)
let parentEl = range.commonAncestorContainer
if (parentEl.nodeType !== Node.ELEMENT_NODE) parentEl = parentEl.parentElement
if (!contentEl.contains(parentEl)) return
// Borrar todas las selecciones
for (const el of contentEl.querySelectorAll(".selected")) {
el.classList.remove("selected")
}
for (const el of contentEl.querySelectorAll(".selected-unactive")) {
el.classList.remove("selected-unactive")
}
setAuxiliaryToolbar(editorEl)
for (const [name, type] of Object.entries(typesWithProperties)) {
let i = 0
const results = parentEl.querySelectorAll(type.selector)
if (results.length) {
for (const el of results) {
if (!sel.containsNode(el)) continue
if (i === 0) {
type.updateInput(el, editorEl)
el.classList.add("selected")
} else {
el.classList.add("selected-unactive")
}
i++
}
} else {
type.disableInput(editorEl)
}
}
}) })
const clickListener = generateClickListener(editorEl, contentEl)
contentEl.addEventListener("click", clickListener, true)
const htmlEl = editorEl.querySelector("textarea") const htmlEl = editorEl.querySelector("textarea")
const observer = new MutationObserver((mutationList, observer) => { const observer = new MutationObserver((mutationList, observer) => {
cleanContent(contentEl) cleanContent(contentEl)
@ -432,6 +435,7 @@ function setupEditor (editorEl) {
cleanContent(contentEl) cleanContent(contentEl)
htmlEl.value = contentEl.innerHTML htmlEl.value = contentEl.innerHTML
fixContent(contentEl)
} }
// TODO: por ahora confiamos, quizás queremos filtrar estilos? // TODO: por ahora confiamos, quizás queremos filtrar estilos?

View file

@ -14,7 +14,6 @@
} }
.selected { outline: #f206f9 solid medium; } .selected { outline: #f206f9 solid medium; }
.selected-unactive { outline: gray solid medium; }
img, video, iframe, audio { img, video, iframe, audio {
width: 100%; width: 100%;