5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-22 19:56:21 +00:00

toolbar auxiliar

This commit is contained in:
void 2020-11-13 17:35:12 -03:00
parent 5f8c368541
commit ef66f6ad5a
4 changed files with 100 additions and 43 deletions

View file

@ -1,3 +1,15 @@
function setAuxiliaryToolbar (editorEl, toolbarName) {
const toolbarEl = editorEl.querySelector(`*[data-editor-auxiliary-toolbar]`)
for (const otherEl of toolbarEl.childNodes) {
if (otherEl.nodeType !== Node.ELEMENT_NODE) continue
otherEl.classList.remove("editor-auxiliary-tool-active")
}
if (toolbarName) {
const auxEl = editorEl.querySelector(`*[data-editor-auxiliary="${toolbarName}"]`)
auxEl.classList.add("editor-auxiliary-tool-active")
}
}
const marks = { const marks = {
bold: { bold: {
selector: "strong", selector: "strong",
@ -146,6 +158,8 @@ const typesWithProperties = {
mark: { mark: {
selector: marks.mark.selector, selector: marks.mark.selector,
updateInput (el, editorEl) { updateInput (el, editorEl) {
setAuxiliaryToolbar(editorEl, "mark")
const markColorInputEl = editorEl.querySelector(`*[data-prop="mark-color"]`) const markColorInputEl = editorEl.querySelector(`*[data-prop="mark-color"]`)
markColorInputEl.disabled = false markColorInputEl.disabled = false
markColorInputEl.value = el.style.backgroundColor ? rgb2hex(el.style.backgroundColor) : "#f206f9" markColorInputEl.value = el.style.backgroundColor ? rgb2hex(el.style.backgroundColor) : "#f206f9"
@ -166,6 +180,8 @@ const typesWithProperties = {
img: { img: {
selector: blocks.img.selector, selector: blocks.img.selector,
updateInput (el, editorEl) { updateInput (el, editorEl) {
setAuxiliaryToolbar(editorEl, "img")
const imgFileEl = editorEl.querySelector(`*[data-prop="img-file"]`) const imgFileEl = editorEl.querySelector(`*[data-prop="img-file"]`)
imgFileEl.disabled = false imgFileEl.disabled = false
// XXX: No se puede cambiar el texto, ¡esto puede ser confuso! // XXX: No se puede cambiar el texto, ¡esto puede ser confuso!
@ -217,6 +233,8 @@ const typesWithProperties = {
audio: { audio: {
selector: blocks.audio.selector, selector: blocks.audio.selector,
updateInput (el, editorEl) { updateInput (el, editorEl) {
setAuxiliaryToolbar(editorEl, "audio")
const audioFileEl = editorEl.querySelector(`*[data-prop="audio-file"]`) const audioFileEl = editorEl.querySelector(`*[data-prop="audio-file"]`)
audioFileEl.disabled = false audioFileEl.disabled = false
// XXX: No se puede cambiar el texto, ¡esto puede ser confuso! // XXX: No se puede cambiar el texto, ¡esto puede ser confuso!
@ -254,6 +272,8 @@ const typesWithProperties = {
video: { video: {
selector: blocks.video.selector, selector: blocks.video.selector,
updateInput (el, editorEl) { updateInput (el, editorEl) {
setAuxiliaryToolbar(editorEl, "video")
const videoFileEl = editorEl.querySelector(`*[data-prop="video-file"]`) const videoFileEl = editorEl.querySelector(`*[data-prop="video-file"]`)
videoFileEl.disabled = false videoFileEl.disabled = false
// XXX: No se puede cambiar el texto, ¡esto puede ser confuso! // XXX: No se puede cambiar el texto, ¡esto puede ser confuso!
@ -291,6 +311,8 @@ const typesWithProperties = {
pdf: { pdf: {
selector: blocks.pdf.selector, selector: blocks.pdf.selector,
updateInput (el, editorEl) { updateInput (el, editorEl) {
setAuxiliaryToolbar(editorEl, "pdf")
const pdfFileEl = editorEl.querySelector(`*[data-prop="pdf-file"]`) const pdfFileEl = editorEl.querySelector(`*[data-prop="pdf-file"]`)
pdfFileEl.disabled = false pdfFileEl.disabled = false
// XXX: No se puede cambiar el texto, ¡esto puede ser confuso! // XXX: No se puede cambiar el texto, ¡esto puede ser confuso!

View file

@ -346,6 +346,11 @@ function setupEditor (editorEl) {
const sel = window.getSelection() const sel = window.getSelection()
const range = sel.getRangeAt(0) 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 // Borrar todas las selecciones
for (const el of contentEl.querySelectorAll(".selected")) { for (const el of contentEl.querySelectorAll(".selected")) {
el.classList.remove("selected") el.classList.remove("selected")
@ -354,8 +359,7 @@ function setupEditor (editorEl) {
el.classList.remove("selected-unactive") el.classList.remove("selected-unactive")
} }
let parentEl = range.commonAncestorContainer setAuxiliaryToolbar(editorEl)
if (parentEl.nodeType !== Node.ELEMENT_TYPE) parentEl = parentEl.parentElement
for (const [name, type] of Object.entries(typesWithProperties)) { for (const [name, type] of Object.entries(typesWithProperties)) {
let i = 0 let i = 0
@ -420,6 +424,12 @@ function setupEditor (editorEl) {
type.setupInput(editorEl, contentEl) type.setupInput(editorEl, contentEl)
} }
document.addEventListener(editorBtn("mark"), () => setAuxiliaryToolbar(editorEl, "mark"))
document.addEventListener(editorBtn("img"), () => setAuxiliaryToolbar(editorEl, "img"))
document.addEventListener(editorBtn("audio"), () => setAuxiliaryToolbar(editorEl, "audio"))
document.addEventListener(editorBtn("video"), () => setAuxiliaryToolbar(editorEl, "video"))
document.addEventListener(editorBtn("pdf"), () => setAuxiliaryToolbar(editorEl, "pdf"))
cleanContent(contentEl) cleanContent(contentEl)
htmlEl.value = contentEl.innerHTML htmlEl.value = contentEl.innerHTML
} }

View file

@ -23,6 +23,27 @@
margin: 0 auto; margin: 0 auto;
} }
.editor-toolbar {
position: sticky;
top: 0px;
background: white;
}
.editor-primary-toolbar, .editor-auxiliary-toolbar {
display: block;
overflow-x: auto;
white-space: nowrap;
}
.editor-auxiliary-toolbar {
& > * {
display: none;
}
.editor-auxiliary-tool-active {
display: block;
}
}
ol, ul { margin: 0; } ol, ul { margin: 0; }
.editor-content { .editor-content {

View file

@ -1,52 +1,56 @@
= form_with do = form_with do
.editor .editor
%button{:data => {:button => "bold"}} Bold .editor-toolbar
%button{:data => {:button => "italic"}} Italic .editor-primary-toolbar
%button{:data => {:button => "deleted"}} Deleted %button.btn{:data => {:button => "bold"}} Bold
%button{:data => {:button => "underline"}} Underline %button.btn{:data => {:button => "italic"}} Italic
%button{:data => {:button => "mark"}} Mark %button.btn{:data => {:button => "deleted"}} Deleted
%button{:data => {:button => "h1"}} H1 %button.btn{:data => {:button => "underline"}} Underline
%button{:data => {:button => "h2"}} H2 %button.btn{:data => {:button => "mark"}} Subrayar
%button{:data => {:button => "h3"}} H3 %button.btn{:data => {:button => "h1"}} H1
%button{:data => {:button => "h4"}} H4 %button.btn{:data => {:button => "h2"}} H2
%button{:data => {:button => "h5"}} H5 %button.btn{:data => {:button => "h3"}} H3
%button{:data => {:button => "h6"}} H6 %button.btn{:data => {:button => "h4"}} H4
%button{:data => {:button => "ul"}} Lista desordenada %button.btn{:data => {:button => "h5"}} H5
%button{:data => {:button => "ol"}} Lista ordenada %button.btn{:data => {:button => "h6"}} H6
%button{:data => {:button => "left"}} Left %button.btn{:data => {:button => "ul"}} Lista desordenada
%button{:data => {:button => "center"}} Center %button.btn{:data => {:button => "ol"}} Lista ordenada
%button{:data => {:button => "right"}} Right %button.btn{:data => {:button => "left"}} Left
%br/ %button.btn{:data => {:button => "center"}} Center
// TODO: generar IDs para labels %button.btn{:data => {:button => "right"}} Right
%button.btn{:data => {:button => "img"}} Imágen
%button.btn{:data => {:button => "video"}} Video
%button.btn{:data => {:button => "audio"}} Audio
%button.btn{:data => {:button => "pdf"}} PDF
// TODO: generar IDs para labels
%label{:for => "mark-color"} Color de resaltado: // HAML cringe
%input{:type => "color", :data => {:prop => "mark-color"}}/ .editor-auxiliary-toolbar{:data => {:editor => {:auxiliary => {:toolbar => ""}}}}
%br/ %div{:data => {:editor => {:auxiliary => "mark"}}}
%label{:for => "mark-color"} Color de resaltado:
%input{:type => "color", :data => {:prop => "mark-color"}}/
%label{:for => "img-file"} Archivo de la imágen: %div{:data => {:editor => {:auxiliary => "img"}}}
%input{:type => "file", :data => {:prop => "img-file"}}/ %label{:for => "img-file"} Archivo de la imágen:
%label{:for => "img-alt"} Descripción de imágen: %input{:type => "file", :data => {:prop => "img-file"}}/
%input{:placeholder => "Un álbum", :type => "text", :data => {:prop => "img-alt"}}/ %label{:for => "img-alt"} Descripción de imágen:
%button{:data => {:button => "img"}} Insertar imágen %input{:placeholder => "Un álbum", :type => "text", :data => {:prop => "img-alt"}}/
%br/
%label{:for => "audio-file"} Archivo de la audio: %div{:data => {:editor => {:auxiliary => "audio"}}}
%input{:type => "file", :data => {:prop => "audio-file"}}/ %label{:for => "audio-file"} Archivo de la audio:
%button{:data => {:button => "audio"}} Insertar audio %input{:type => "file", :data => {:prop => "audio-file"}}/
%br/
%label{:for => "video-file"} Archivo de la video: %div{:data => {:editor => {:auxiliary => "video"}}}
%input{:type => "file", :data => {:prop => "video-file"}}/ %label{:for => "video-file"} Archivo de la video:
%button{:data => {:button => "video"}} Insertar video %input{:type => "file", :data => {:prop => "video-file"}}/
%br/
%label{:for => "pdf-file"} Archivo de la PDF: %div{:data => {:editor => {:auxiliary => "pdf"}}}
%input{:type => "file", :data => {:prop => "pdf-file"}}/ %label{:for => "pdf-file"} Archivo de la PDF:
%button{:data => {:button => "pdf"}} Insertar PDF %input{:type => "file", :data => {:prop => "pdf-file"}}/
%br/
%label{:for => "link-href"} URL de link: %div{:data => {:editor => {:auxiliary => "link"}}}
%input{:type => "url", :data => {:prop => "link-href"}}/ %label{:for => "link-href"} URL de link:
%input{:type => "url", :data => {:prop => "link-href"}}/
.editor-content{:contenteditable => "true"} .editor-content{:contenteditable => "true"}
%h1 %h1