2021-04-28 18:48:50 +00:00
|
|
|
import { Editor } from "editor/editor";
|
|
|
|
import { EditorNode } from "editor/types";
|
2021-02-12 22:18:48 +00:00
|
|
|
import {
|
2021-04-28 18:48:50 +00:00
|
|
|
safeGetSelection,
|
|
|
|
safeGetRangeAt,
|
|
|
|
moveChildren,
|
|
|
|
markNames,
|
|
|
|
} from "editor/utils";
|
|
|
|
import { link } from "editor/types/link";
|
|
|
|
import { mark } from "editor/types/mark";
|
2021-02-12 15:57:23 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
function makeMark(name: string, tag: string): EditorNode {
|
|
|
|
return {
|
|
|
|
selector: tag,
|
|
|
|
allowedChildren: [...markNames.filter((n) => n !== name), "text"],
|
|
|
|
handleEmpty: "remove",
|
|
|
|
create: () => document.createElement(tag),
|
|
|
|
};
|
2021-02-12 15:57:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXX: si agregás algo acá, agregalo a markNames
|
|
|
|
export const marks: { [propName: string]: EditorNode } = {
|
2021-04-28 18:48:50 +00:00
|
|
|
bold: makeMark("bold", "strong"),
|
|
|
|
italic: makeMark("italic", "em"),
|
|
|
|
deleted: makeMark("deleted", "del"),
|
|
|
|
underline: makeMark("underline", "u"),
|
|
|
|
sub: makeMark("sub", "sub"),
|
|
|
|
super: makeMark("super", "sup"),
|
|
|
|
mark,
|
|
|
|
link,
|
|
|
|
small: makeMark("small", "small"),
|
|
|
|
};
|
2021-02-12 15:57:23 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
function recursiveFilterSelection(
|
|
|
|
node: Element,
|
|
|
|
selection: Selection,
|
|
|
|
selector: string
|
2021-02-12 15:57:23 +00:00
|
|
|
): Element[] {
|
2021-04-28 18:48:50 +00:00
|
|
|
let output: Element[] = [];
|
|
|
|
for (const child of [...node.children]) {
|
|
|
|
if (child.matches(selector) && selection.containsNode(child))
|
|
|
|
output.push(child);
|
|
|
|
output = [
|
|
|
|
...output,
|
|
|
|
...recursiveFilterSelection(child, selection, selector),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return output;
|
2021-02-12 15:57:23 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
export function setupButtons(editor: Editor): void {
|
|
|
|
for (const [name, type] of Object.entries(marks)) {
|
|
|
|
const buttonEl = editor.toolbarEl.querySelector(
|
|
|
|
`[data-editor-button="mark-${name}"]`
|
|
|
|
);
|
|
|
|
if (!buttonEl) continue;
|
|
|
|
buttonEl.addEventListener("click", (event) => {
|
|
|
|
event.preventDefault();
|
2021-02-12 15:57:23 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
const sel = safeGetSelection(editor);
|
|
|
|
if (!sel) return;
|
|
|
|
const range = safeGetRangeAt(sel);
|
|
|
|
if (!range) return;
|
2021-02-12 15:57:23 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
let parentEl = range.commonAncestorContainer;
|
|
|
|
while (!(parentEl instanceof Element)) {
|
|
|
|
if (!parentEl.parentElement) return;
|
|
|
|
parentEl = parentEl.parentElement;
|
|
|
|
}
|
2021-02-12 19:10:55 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
const existingMarks = recursiveFilterSelection(
|
|
|
|
parentEl,
|
|
|
|
sel,
|
|
|
|
type.selector
|
|
|
|
);
|
|
|
|
console.debug("marks encontradas:", existingMarks);
|
2021-02-12 15:57:23 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
if (existingMarks.length > 0) {
|
|
|
|
const mark = existingMarks[0];
|
|
|
|
if (!mark.parentElement) throw new Error(":/");
|
|
|
|
moveChildren(mark, mark.parentElement, mark);
|
|
|
|
mark.parentElement.removeChild(mark);
|
|
|
|
} else {
|
|
|
|
if (range.commonAncestorContainer === editor.contentEl)
|
|
|
|
// TODO: mostrar error
|
|
|
|
return console.error(
|
|
|
|
"No puedo marcar cosas a través de distintos bloques!"
|
|
|
|
);
|
2021-02-12 19:10:55 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
const tagEl = type.create(editor);
|
|
|
|
type.onClick && type.onClick(editor, tagEl);
|
2021-02-12 19:10:55 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
tagEl.appendChild(range.extractContents());
|
2021-02-12 15:57:23 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
range.insertNode(tagEl);
|
|
|
|
range.selectNode(tagEl);
|
|
|
|
}
|
2021-02-12 15:57:23 +00:00
|
|
|
|
2021-04-28 18:48:50 +00:00
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
2021-02-12 15:57:23 +00:00
|
|
|
}
|