mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-15 07:01:42 +00:00
Merge branch 'editor-nuevo' of 0xacab.org:sutty/sutty into editor-nuevo
This commit is contained in:
commit
cc0dcf47a7
3 changed files with 49 additions and 53 deletions
|
@ -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)
|
||||||
},
|
},
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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%;
|
||||||
|
|
Loading…
Reference in a new issue