2021-04-28 18:48:50 +00:00
|
|
|
import * as ActiveStorage from "@rails/activestorage";
|
|
|
|
import { Editor } from "editor/editor";
|
|
|
|
import { EditorNode, getValidParentInSelection } from "editor/types";
|
2021-02-14 16:01:41 +00:00
|
|
|
import {
|
2021-04-28 18:48:50 +00:00
|
|
|
safeGetSelection,
|
|
|
|
safeGetRangeAt,
|
|
|
|
markNames,
|
|
|
|
parentBlockNames,
|
|
|
|
setAuxiliaryToolbar,
|
|
|
|
clearSelected,
|
|
|
|
} from "editor/utils";
|
|
|
|
|
|
|
|
function uploadFile(file: File): Promise<string> {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const upload = new ActiveStorage.DirectUpload(
|
|
|
|
file,
|
|
|
|
origin + "/rails/active_storage/direct_uploads"
|
|
|
|
);
|
|
|
|
|
|
|
|
upload.create((error: any, blob: any) => {
|
|
|
|
if (error) {
|
|
|
|
reject(error);
|
|
|
|
} else {
|
|
|
|
const url = `${origin}/rails/active_storage/blobs/${blob.signed_id}/${blob.filename}`;
|
|
|
|
resolve(url);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2021-02-14 16:01:41 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
function getAlt(multimediaInnerEl: HTMLElement): string | null {
|
|
|
|
switch (multimediaInnerEl.tagName) {
|
|
|
|
case "VIDEO":
|
|
|
|
case "AUDIO":
|
|
|
|
return multimediaInnerEl.getAttribute("aria-label");
|
|
|
|
case "IMG":
|
|
|
|
return (multimediaInnerEl as HTMLImageElement).alt;
|
|
|
|
case "IFRAME":
|
|
|
|
return multimediaInnerEl.title;
|
|
|
|
default:
|
|
|
|
throw new Error("no pude conseguir el alt");
|
|
|
|
}
|
2021-02-14 16:01:41 +00:00
|
|
|
}
|
2021-04-28 18:48:50 +00:00
|
|
|
function setAlt(multimediaInnerEl: HTMLElement, value: string): void {
|
|
|
|
switch (multimediaInnerEl.tagName) {
|
|
|
|
case "VIDEO":
|
|
|
|
case "AUDIO":
|
|
|
|
multimediaInnerEl.setAttribute("aria-label", value);
|
|
|
|
break;
|
|
|
|
case "IMG":
|
|
|
|
(multimediaInnerEl as HTMLImageElement).alt = value;
|
|
|
|
break;
|
|
|
|
case "IFRAME":
|
|
|
|
multimediaInnerEl.title = value;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Error("no pude setear el alt");
|
|
|
|
}
|
2021-02-14 16:01:41 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
function select(editor: Editor, el: HTMLElement): void {
|
|
|
|
clearSelected(editor);
|
|
|
|
el.dataset.editorSelected = "";
|
|
|
|
|
|
|
|
const innerEl = el.querySelector<HTMLElement>("[data-multimedia-inner]");
|
|
|
|
if (!innerEl) throw new Error("No hay multimedia válida");
|
|
|
|
if (innerEl.tagName === "P") {
|
|
|
|
editor.toolbar.auxiliary.multimedia.altEl.value = "";
|
|
|
|
editor.toolbar.auxiliary.multimedia.altEl.disabled = true;
|
|
|
|
} else {
|
|
|
|
editor.toolbar.auxiliary.multimedia.altEl.value = getAlt(innerEl) || "";
|
|
|
|
editor.toolbar.auxiliary.multimedia.altEl.disabled = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
setAuxiliaryToolbar(editor, editor.toolbar.auxiliary.multimedia.parentEl);
|
2021-03-22 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2021-02-14 16:01:41 +00:00
|
|
|
export const multimedia: EditorNode = {
|
2021-04-28 18:48:50 +00:00
|
|
|
selector: "figure[data-multimedia]",
|
|
|
|
allowedChildren: "ignore-children",
|
|
|
|
handleEmpty: "remove",
|
|
|
|
create: () => {
|
|
|
|
const figureEl = document.createElement("figure");
|
|
|
|
figureEl.dataset.multimedia = "";
|
|
|
|
figureEl.contentEditable = "false";
|
|
|
|
|
|
|
|
const placeholderEl = document.createElement("p");
|
|
|
|
placeholderEl.dataset.multimediaInner = "";
|
|
|
|
// TODO i18n
|
|
|
|
placeholderEl.append("¡Clickeame para subir un archivo!");
|
|
|
|
figureEl.appendChild(placeholderEl);
|
|
|
|
|
|
|
|
const descriptionEl = document.createElement("figcaption");
|
|
|
|
descriptionEl.contentEditable = "true";
|
|
|
|
// TODO i18n
|
|
|
|
descriptionEl.append("Escribí acá la descripción del archivo.");
|
|
|
|
figureEl.appendChild(descriptionEl);
|
|
|
|
|
|
|
|
return figureEl;
|
|
|
|
},
|
|
|
|
onClick(editor, el) {
|
|
|
|
if (!(el instanceof HTMLElement)) throw new Error("oh no");
|
|
|
|
select(editor, el);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
function createElementWithFile(url: string, type: string): HTMLElement {
|
|
|
|
if (type.match(/^image\/.+$/)) {
|
|
|
|
const el = document.createElement("img");
|
|
|
|
el.dataset.multimediaInner = "";
|
|
|
|
el.src = url;
|
|
|
|
return el;
|
|
|
|
} else if (type.match(/^video\/.+$/)) {
|
|
|
|
const el = document.createElement("video");
|
|
|
|
el.controls = true;
|
|
|
|
el.dataset.multimediaInner = "";
|
|
|
|
el.src = url;
|
|
|
|
return el;
|
|
|
|
} else if (type.match(/^audio\/.+$/)) {
|
|
|
|
const el = document.createElement("audio");
|
|
|
|
el.controls = true;
|
|
|
|
el.dataset.multimediaInner = "";
|
|
|
|
el.src = url;
|
|
|
|
return el;
|
|
|
|
} else if (type.match(/^application\/pdf$/)) {
|
|
|
|
const el = document.createElement("iframe");
|
|
|
|
el.dataset.multimediaInner = "";
|
|
|
|
el.src = url;
|
|
|
|
return el;
|
|
|
|
} else {
|
|
|
|
// TODO: chequear si el archivo es válido antes de subir
|
|
|
|
throw new Error("Tipo de archivo no reconocido");
|
|
|
|
}
|
2021-02-14 16:01:41 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
export function setupAuxiliaryToolbar(editor: Editor): void {
|
|
|
|
editor.toolbar.auxiliary.multimedia.uploadEl.addEventListener(
|
|
|
|
"click",
|
|
|
|
(event) => {
|
|
|
|
const files = editor.toolbar.auxiliary.multimedia.fileEl.files;
|
|
|
|
if (!files || !files.length)
|
|
|
|
throw new Error("no hay archivos para subir");
|
|
|
|
const file = files[0];
|
|
|
|
|
|
|
|
const selectedEl = editor.contentEl.querySelector<HTMLElement>(
|
|
|
|
"figure[data-editor-selected]"
|
|
|
|
);
|
|
|
|
if (!selectedEl)
|
|
|
|
throw new Error("No pude encontrar el elemento para setear el archivo");
|
|
|
|
|
|
|
|
selectedEl.dataset.editorLoading = "";
|
|
|
|
uploadFile(file)
|
|
|
|
.then((url) => {
|
|
|
|
const innerEl = selectedEl.querySelector("[data-multimedia-inner]");
|
|
|
|
if (!innerEl) throw new Error("No hay multimedia a reemplazar");
|
|
|
|
|
|
|
|
const el = createElementWithFile(url, file.type);
|
|
|
|
setAlt(el, editor.toolbar.auxiliary.multimedia.altEl.value);
|
|
|
|
selectedEl.replaceChild(el, innerEl);
|
|
|
|
|
|
|
|
select(editor, selectedEl);
|
|
|
|
|
|
|
|
delete selectedEl.dataset.editorError;
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
console.error(err);
|
|
|
|
// TODO: mostrar error
|
|
|
|
selectedEl.dataset.editorError = "";
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
delete selectedEl.dataset.editorLoading;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
editor.toolbar.auxiliary.multimedia.removeEl.addEventListener(
|
|
|
|
"click",
|
|
|
|
(event) => {
|
|
|
|
const selectedEl = editor.contentEl.querySelector<HTMLElement>(
|
|
|
|
"figure[data-editor-selected]"
|
|
|
|
);
|
|
|
|
if (!selectedEl)
|
|
|
|
throw new Error("No pude encontrar el elemento para borrar");
|
|
|
|
|
|
|
|
selectedEl.parentElement?.removeChild(selectedEl);
|
|
|
|
setAuxiliaryToolbar(editor, null);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
editor.toolbar.auxiliary.multimedia.altEl.addEventListener(
|
|
|
|
"input",
|
|
|
|
(event) => {
|
|
|
|
const selectedEl = editor.contentEl.querySelector<HTMLAnchorElement>(
|
|
|
|
"figure[data-editor-selected]"
|
|
|
|
);
|
|
|
|
if (!selectedEl)
|
|
|
|
throw new Error("No pude encontrar el multimedia para setear el alt");
|
|
|
|
|
|
|
|
const innerEl = selectedEl.querySelector<HTMLElement>(
|
|
|
|
"[data-multimedia-inner]"
|
|
|
|
);
|
|
|
|
if (!innerEl) throw new Error("No hay multimedia a para setear el alt");
|
|
|
|
|
|
|
|
setAlt(innerEl, editor.toolbar.auxiliary.multimedia.altEl.value);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
editor.toolbar.auxiliary.multimedia.altEl.addEventListener(
|
|
|
|
"keydown",
|
|
|
|
(event) => {
|
|
|
|
if (event.keyCode == 13) event.preventDefault();
|
|
|
|
}
|
|
|
|
);
|
2021-02-14 16:01:41 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
export function setupButtons(editor: Editor): void {
|
|
|
|
const buttonEl = editor.toolbarEl.querySelector(
|
|
|
|
'[data-editor-button="multimedia"]'
|
|
|
|
);
|
|
|
|
if (!buttonEl) throw new Error("No encontre el botón de multimedia");
|
|
|
|
buttonEl.addEventListener("click", (event) => {
|
|
|
|
event.preventDefault();
|
2021-02-14 16:01:41 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
const list = getValidParentInSelection({ editor, type: "multimedia" });
|
2021-02-14 16:01:41 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
const el = multimedia.create(editor);
|
|
|
|
list[0].insertBefore(el, list[1].nextElementSibling);
|
|
|
|
select(editor, el);
|
2021-02-14 16:01:41 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
return false;
|
|
|
|
});
|
2021-02-14 16:01:41 +00:00
|
|
|
}
|