parar de usar checkFn, reemplazar con selectores

This commit is contained in:
void 2020-11-09 16:07:20 -03:00
parent 774cfdbf76
commit 5f8c368541
3 changed files with 61 additions and 76 deletions

View file

@ -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

View file

@ -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
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
}
const results = parentEl.querySelectorAll(type.selector)
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) {
} else {
type.disableInput(editorEl)
}
}

View file

@ -13,9 +13,6 @@
padding: 0;
}
/*.selected, .selected-unactive {
outline-offset: 1pt;
}*/
.selected { outline: #f206f9 solid medium; }
.selected-unactive { outline: gray solid medium; }