mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-23 00:26:22 +00:00
parar de usar checkFn, reemplazar con selectores
This commit is contained in:
parent
774cfdbf76
commit
5f8c368541
3 changed files with 61 additions and 76 deletions
|
@ -1,24 +1,22 @@
|
|||
// TODO: minimizar complejidad utilizando selectores css/querySelector
|
||||
|
||||
const marks = {
|
||||
bold: {
|
||||
checkFn: el => el.tagName === "STRONG",
|
||||
selector: "strong",
|
||||
createFn: () => document.createElement("STRONG"),
|
||||
},
|
||||
italic: {
|
||||
checkFn: el => el.tagName === "EM",
|
||||
selector: "em",
|
||||
createFn: () => document.createElement("EM"),
|
||||
},
|
||||
deleted: {
|
||||
checkFn: el => el.tagName === "DEL",
|
||||
selector: "del",
|
||||
createFn: () => document.createElement("DEL"),
|
||||
},
|
||||
underline: {
|
||||
checkFn: el => el.tagName === "U",
|
||||
selector: "u",
|
||||
createFn: () => document.createElement("U"),
|
||||
},
|
||||
mark: {
|
||||
checkFn: el => el.tagName === "MARK",
|
||||
selector: "mark",
|
||||
createFn: () => document.createElement("MARK"),
|
||||
},
|
||||
}
|
||||
|
@ -34,43 +32,43 @@ const tagNameSetFn = tagName => el => {
|
|||
const blocks = {
|
||||
p: {
|
||||
noButton: true,
|
||||
checkFn: el => el.tagName == "P",
|
||||
selector: "P",
|
||||
setFn: tagNameSetFn("P"),
|
||||
},
|
||||
h1: {
|
||||
checkFn: el => el.tagName == "H1",
|
||||
selector: "H1",
|
||||
setFn: tagNameSetFn("H1"),
|
||||
},
|
||||
h2: {
|
||||
checkFn: el => el.tagName == "H2",
|
||||
selector: "H2",
|
||||
setFn: tagNameSetFn("H2"),
|
||||
},
|
||||
h3: {
|
||||
checkFn: el => el.tagName == "H3",
|
||||
selector: "H3",
|
||||
setFn: tagNameSetFn("H3"),
|
||||
},
|
||||
h4: {
|
||||
checkFn: el => el.tagName == "H4",
|
||||
selector: "H4",
|
||||
setFn: tagNameSetFn("H4"),
|
||||
},
|
||||
h5: {
|
||||
checkFn: el => el.tagName == "H5",
|
||||
selector: "H5",
|
||||
setFn: tagNameSetFn("H5"),
|
||||
},
|
||||
h6: {
|
||||
checkFn: el => el.tagName == "H6",
|
||||
selector: "H6",
|
||||
setFn: tagNameSetFn("H6"),
|
||||
},
|
||||
ul: {
|
||||
checkFn: el => el.tagName == "UL",
|
||||
selector: "UL",
|
||||
setFn: tagNameSetFn("UL"),
|
||||
},
|
||||
ol: {
|
||||
checkFn: el => el.tagName == "OL",
|
||||
selector: "OL",
|
||||
setFn: tagNameSetFn("OL"),
|
||||
},
|
||||
img: {
|
||||
checkFn: el => el.tagName == "IMG",
|
||||
selector: "IMG",
|
||||
createFn: editorEl => {
|
||||
const el = document.createElement("IMG")
|
||||
el.src = "https://radio.sutty.nl/public/placeholder_992x992.png"
|
||||
|
@ -79,7 +77,7 @@ const blocks = {
|
|||
},
|
||||
},
|
||||
audio: {
|
||||
checkFn: el => el.tagName == "AUDIO",
|
||||
selector: "AUDIO",
|
||||
createFn: editorEl => {
|
||||
const el = document.createElement("AUDIO")
|
||||
el.controls = true
|
||||
|
@ -87,7 +85,7 @@ const blocks = {
|
|||
},
|
||||
},
|
||||
video: {
|
||||
checkFn: el => el.tagName == "VIDEO",
|
||||
selector: "VIDEO",
|
||||
createFn: editorEl => {
|
||||
const el = document.createElement("VIDEO")
|
||||
el.controls = true
|
||||
|
@ -96,7 +94,7 @@ const blocks = {
|
|||
},
|
||||
// PDF
|
||||
pdf: {
|
||||
checkFn: el => el.tagName == "IFRAME",
|
||||
selector: "IFRAME",
|
||||
createFn: editorEl => {
|
||||
const el = document.createElement("IFRAME")
|
||||
return el
|
||||
|
@ -112,15 +110,15 @@ const divWithStyleCreateFn = styleFn => () => {
|
|||
|
||||
const parentBlocks = {
|
||||
left: {
|
||||
checkFn: el => el.tagName === "DIV" && el.dataset.align === "left",
|
||||
selector: "div[data-align=left]",
|
||||
createFn: divWithStyleCreateFn(el => el.dataset.align = "left"),
|
||||
},
|
||||
center: {
|
||||
checkFn: el => el.tagName === "DIV" && el.dataset.align === "center",
|
||||
selector: "div[data-align=center]",
|
||||
createFn: divWithStyleCreateFn(el => el.dataset.align = "center"),
|
||||
},
|
||||
right: {
|
||||
checkFn: el => el.tagName === "DIV" && el.dataset.align === "right",
|
||||
selector: "div[data-align=right]",
|
||||
createFn: divWithStyleCreateFn(el => el.dataset.align = "right"),
|
||||
},
|
||||
}
|
||||
|
@ -135,12 +133,10 @@ function rgb2hex(rgb) {
|
|||
return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
|
||||
}
|
||||
|
||||
// Encuentra lx primer hijx que esté en la selección que cumpla con checkFn
|
||||
const findRecursiveChild = (checkFn, node) => {
|
||||
if (checkFn(node) && window.getSelection().containsNode(node)) return node
|
||||
for (const child of node.childNodes) {
|
||||
const result = findRecursiveChild(checkFn, child)
|
||||
if (result) return result
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,7 +144,7 @@ const getSelected = contentEl => contentEl.querySelector(".selected")
|
|||
|
||||
const typesWithProperties = {
|
||||
mark: {
|
||||
checkFn: marks.mark.checkFn,
|
||||
selector: marks.mark.selector,
|
||||
updateInput (el, editorEl) {
|
||||
const markColorInputEl = editorEl.querySelector(`*[data-prop="mark-color"]`)
|
||||
markColorInputEl.disabled = false
|
||||
|
@ -162,13 +158,13 @@ const typesWithProperties = {
|
|||
setupInput (editorEl, contentEl) {
|
||||
const markColorInputEl = editorEl.querySelector(`*[data-prop="mark-color"]`)
|
||||
markColorInputEl.addEventListener("change", event => {
|
||||
const markEl = findRecursiveChild(marks.mark.checkFn, contentEl)
|
||||
const markEl = findInSelection(marks.mark.selector, contentEl)
|
||||
if (markEl) markEl.style.backgroundColor = markColorInputEl.value
|
||||
}, false)
|
||||
},
|
||||
},
|
||||
img: {
|
||||
checkFn: blocks.img.checkFn,
|
||||
selector: blocks.img.selector,
|
||||
updateInput (el, editorEl) {
|
||||
const imgFileEl = editorEl.querySelector(`*[data-prop="img-file"]`)
|
||||
imgFileEl.disabled = false
|
||||
|
@ -189,8 +185,7 @@ const typesWithProperties = {
|
|||
setupInput (editorEl, contentEl) {
|
||||
const imgFileEl = editorEl.querySelector(`*[data-prop="img-file"]`)
|
||||
imgFileEl.addEventListener("input", event => {
|
||||
// const imgEl = findRecursiveChild(blocks.img.checkFn, contentEl)
|
||||
const imgEl = getSelected(contentEl)
|
||||
const imgEl = contentEl.querySelector("img.selected")
|
||||
if (!imgEl) return
|
||||
|
||||
const file = imgFileEl.files[0]
|
||||
|
@ -214,14 +209,13 @@ const typesWithProperties = {
|
|||
|
||||
const imgAltEl = editorEl.querySelector(`*[data-prop="img-alt"]`)
|
||||
imgAltEl.addEventListener("input", event => {
|
||||
// const imgEl = findRecursiveChild(blocks.img.checkFn, contentEl)
|
||||
const imgEl = getSelected(contentEl)
|
||||
const imgEl = contentEl.querySelector("img.selected")
|
||||
if (imgEl) imgEl.alt = imgAltEl.value
|
||||
}, false)
|
||||
},
|
||||
},
|
||||
audio: {
|
||||
checkFn: blocks.audio.checkFn,
|
||||
selector: blocks.audio.selector,
|
||||
updateInput (el, editorEl) {
|
||||
const audioFileEl = editorEl.querySelector(`*[data-prop="audio-file"]`)
|
||||
audioFileEl.disabled = false
|
||||
|
@ -258,7 +252,7 @@ const typesWithProperties = {
|
|||
},
|
||||
},
|
||||
video: {
|
||||
checkFn: blocks.video.checkFn,
|
||||
selector: blocks.video.selector,
|
||||
updateInput (el, editorEl) {
|
||||
const videoFileEl = editorEl.querySelector(`*[data-prop="video-file"]`)
|
||||
videoFileEl.disabled = false
|
||||
|
@ -295,7 +289,7 @@ const typesWithProperties = {
|
|||
},
|
||||
},
|
||||
pdf: {
|
||||
checkFn: blocks.pdf.checkFn,
|
||||
selector: blocks.pdf.selector,
|
||||
updateInput (el, editorEl) {
|
||||
const pdfFileEl = editorEl.querySelector(`*[data-prop="pdf-file"]`)
|
||||
pdfFileEl.disabled = false
|
||||
|
|
|
@ -82,11 +82,10 @@ function setupMarkButton (button, mark, contentEl) {
|
|||
|
||||
let parentEl = getElementParent(sel.anchorNode)
|
||||
//if (sel.anchorNode == parentEl) parentEl = parentEl.firstChild
|
||||
const parentChildren = Array.from(parentEl.childNodes)
|
||||
|
||||
const range = sel.getRangeAt(0)
|
||||
|
||||
if (mark.checkFn(parentEl)) {
|
||||
if (parentEl.matches(mark.selector)) {
|
||||
const [left, right] = splitNode(parentEl, range)
|
||||
right.range.insertNode(range.extractContents())
|
||||
|
||||
|
@ -96,8 +95,12 @@ function setupMarkButton (button, mark, contentEl) {
|
|||
sel.removeAllRanges()
|
||||
sel.addRange(selectionRange)
|
||||
} else {
|
||||
for (const child of parentChildren) {
|
||||
if (mark.checkFn(child) && sel.containsNode(child)) {
|
||||
for (const child of parentEl.childNodes) {
|
||||
if (
|
||||
(child instanceof Element)
|
||||
&& child.matches(mark.selector)
|
||||
&& sel.containsNode(child)
|
||||
) {
|
||||
moveChildren(child, parentEl, child)
|
||||
parentEl.removeChild(child)
|
||||
// TODO: agregar a selección
|
||||
|
@ -115,7 +118,7 @@ function setupMarkButton (button, mark, contentEl) {
|
|||
}
|
||||
|
||||
for (const child of tagEl.childNodes) {
|
||||
if (mark.checkFn(child)) {
|
||||
if (child instanceof Element && child.matches(mark.selector)) {
|
||||
moveChildren(child, tagEl, child)
|
||||
tagEl.removeChild(child)
|
||||
}
|
||||
|
@ -147,7 +150,7 @@ function setupBlockButton (button, block, contentEl, editorEl) {
|
|||
while (!isDirectChild(contentEl, parentEl)) parentEl = parentEl.parentElement
|
||||
|
||||
if (block.setFn) {
|
||||
if (block.checkFn(parentEl)) {
|
||||
if (parentEl.matches(block.selector)) {
|
||||
tagNameSetFn("P")(parentEl)
|
||||
} else {
|
||||
block.setFn(parentEl)
|
||||
|
@ -177,7 +180,7 @@ function setupParentBlockButton (button, parentBlock, contentEl) {
|
|||
let parentEl = sel.anchorNode
|
||||
while (!isDirectChild(contentEl, parentEl)) parentEl = parentEl.parentElement
|
||||
|
||||
if (parentBlock.checkFn(parentEl)) {
|
||||
if (parentEl.matches(parentBlock.selector)) {
|
||||
moveChildren(parentEl, parentEl.parentElement, parentEl)
|
||||
parentEl.parentElement.removeChild(parentEl)
|
||||
} else if (elementIsParentBlock(parentEl)) {
|
||||
|
@ -195,7 +198,7 @@ function setupParentBlockButton (button, parentBlock, contentEl) {
|
|||
|
||||
const elementIsTypes = types => element => {
|
||||
for (const type of Object.values(types)) {
|
||||
if (type.checkFn(element)) return true
|
||||
if (element.matches(type.selector)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -288,7 +291,12 @@ function cleanNode (node, contentEl) {
|
|||
child.parentNode.removeChild(child)
|
||||
|
||||
for (const mark of Object.values(marks)) {
|
||||
if (mark.checkFn(child) && child.nextSibling && mark.checkFn(child.nextSibling)) {
|
||||
if (
|
||||
child.matches(mark.selector)
|
||||
&& child.nextSibling
|
||||
&& (child.nextSibling instanceof Element)
|
||||
&& child.nextSibling.matches(mark.selector)
|
||||
) {
|
||||
moveChildren(child.nextSibling, child, null)
|
||||
child.nextSibling.parentNode.removeChild(child.nextSibling)
|
||||
}
|
||||
|
@ -346,39 +354,25 @@ function setupEditor (editorEl) {
|
|||
el.classList.remove("selected-unactive")
|
||||
}
|
||||
|
||||
let parentEl = range.commonAncestorContainer
|
||||
if (parentEl.nodeType !== Node.ELEMENT_TYPE) parentEl = parentEl.parentElement
|
||||
|
||||
for (const [name, type] of Object.entries(typesWithProperties)) {
|
||||
let i = 0
|
||||
const results = parentEl.querySelectorAll(type.selector)
|
||||
|
||||
let result
|
||||
while (true) {
|
||||
try {
|
||||
result = findRecursiveChild(
|
||||
el => type.checkFn(el)
|
||||
&& !(el.classList.contains("selected")
|
||||
|| el.classList.contains("selected-unactive")),
|
||||
range.commonAncestorContainer
|
||||
)
|
||||
} catch (err) {
|
||||
// Permission denied or something...
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Property_access_denied
|
||||
console.log("Error raro", err)
|
||||
break
|
||||
}
|
||||
|
||||
if (result) {
|
||||
if (results.length) {
|
||||
for (const el of results) {
|
||||
if (!sel.containsNode(el)) continue
|
||||
if (i === 0) {
|
||||
type.updateInput(result, editorEl)
|
||||
result.classList.add("selected")
|
||||
type.updateInput(el, editorEl)
|
||||
el.classList.add("selected")
|
||||
} else {
|
||||
result.classList.add("selected-unactive")
|
||||
el.classList.add("selected-unactive")
|
||||
}
|
||||
i++
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
type.disableInput(editorEl)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,6 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
/*.selected, .selected-unactive {
|
||||
outline-offset: 1pt;
|
||||
}*/
|
||||
.selected { outline: #f206f9 solid medium; }
|
||||
.selected-unactive { outline: gray solid medium; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue