2021-04-13 10:57:08 +02:00
|
|
|
// Copyright: Ankitects Pty Ltd and contributors
|
|
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
2021-02-09 04:38:04 +01:00
|
|
|
|
2021-03-09 14:02:41 +01:00
|
|
|
import type { EditingArea } from "./editingArea";
|
2021-03-08 20:40:23 +01:00
|
|
|
|
2021-01-30 17:54:07 +01:00
|
|
|
export function nodeIsElement(node: Node): node is Element {
|
|
|
|
return node.nodeType === Node.ELEMENT_NODE;
|
|
|
|
}
|
|
|
|
|
|
|
|
const INLINE_TAGS = [
|
|
|
|
"A",
|
|
|
|
"ABBR",
|
|
|
|
"ACRONYM",
|
|
|
|
"AUDIO",
|
|
|
|
"B",
|
|
|
|
"BDI",
|
|
|
|
"BDO",
|
|
|
|
"BIG",
|
|
|
|
"BR",
|
|
|
|
"BUTTON",
|
|
|
|
"CANVAS",
|
|
|
|
"CITE",
|
|
|
|
"CODE",
|
|
|
|
"DATA",
|
|
|
|
"DATALIST",
|
|
|
|
"DEL",
|
|
|
|
"DFN",
|
|
|
|
"EM",
|
|
|
|
"EMBED",
|
|
|
|
"I",
|
|
|
|
"IFRAME",
|
|
|
|
"IMG",
|
|
|
|
"INPUT",
|
|
|
|
"INS",
|
|
|
|
"KBD",
|
|
|
|
"LABEL",
|
|
|
|
"MAP",
|
|
|
|
"MARK",
|
|
|
|
"METER",
|
|
|
|
"NOSCRIPT",
|
|
|
|
"OBJECT",
|
|
|
|
"OUTPUT",
|
|
|
|
"PICTURE",
|
|
|
|
"PROGRESS",
|
|
|
|
"Q",
|
|
|
|
"RUBY",
|
|
|
|
"S",
|
|
|
|
"SAMP",
|
|
|
|
"SCRIPT",
|
|
|
|
"SELECT",
|
|
|
|
"SLOT",
|
|
|
|
"SMALL",
|
|
|
|
"SPAN",
|
|
|
|
"STRONG",
|
|
|
|
"SUB",
|
|
|
|
"SUP",
|
|
|
|
"SVG",
|
|
|
|
"TEMPLATE",
|
|
|
|
"TEXTAREA",
|
|
|
|
"TIME",
|
|
|
|
"U",
|
|
|
|
"TT",
|
|
|
|
"VAR",
|
|
|
|
"VIDEO",
|
|
|
|
"WBR",
|
|
|
|
];
|
|
|
|
|
|
|
|
export function nodeIsInline(node: Node): boolean {
|
|
|
|
return !nodeIsElement(node) || INLINE_TAGS.includes(node.tagName);
|
|
|
|
}
|
2021-03-08 20:40:23 +01:00
|
|
|
|
|
|
|
export function caretToEnd(currentField: EditingArea): void {
|
|
|
|
const range = document.createRange();
|
|
|
|
range.selectNodeContents(currentField.editable);
|
|
|
|
range.collapse(false);
|
|
|
|
const selection = currentField.getSelection();
|
|
|
|
selection.removeAllRanges();
|
|
|
|
selection.addRange(range);
|
|
|
|
}
|
2021-04-20 03:24:08 +02:00
|
|
|
|
2021-05-26 01:21:33 +02:00
|
|
|
const getAnchorParent =
|
|
|
|
<T extends Element>(predicate: (element: Element) => element is T) =>
|
|
|
|
(currentField: DocumentOrShadowRoot): T | null => {
|
|
|
|
const anchor = currentField.getSelection()?.anchorNode;
|
2021-04-20 03:24:08 +02:00
|
|
|
|
2021-05-26 01:21:33 +02:00
|
|
|
if (!anchor) {
|
|
|
|
return null;
|
|
|
|
}
|
2021-04-20 03:24:08 +02:00
|
|
|
|
2021-05-26 01:21:33 +02:00
|
|
|
let anchorParent: T | null = null;
|
|
|
|
let element = nodeIsElement(anchor) ? anchor : anchor.parentElement;
|
2021-04-20 03:24:08 +02:00
|
|
|
|
2021-05-26 01:21:33 +02:00
|
|
|
while (element) {
|
|
|
|
anchorParent = anchorParent || (predicate(element) ? element : null);
|
|
|
|
element = element.parentElement;
|
|
|
|
}
|
2021-04-20 03:24:08 +02:00
|
|
|
|
2021-05-26 01:21:33 +02:00
|
|
|
return anchorParent;
|
|
|
|
};
|
2021-04-20 03:24:08 +02:00
|
|
|
|
|
|
|
const isListItem = (element: Element): element is HTMLLIElement =>
|
|
|
|
window.getComputedStyle(element).display === "list-item";
|
|
|
|
const isParagraph = (element: Element): element is HTMLParamElement =>
|
|
|
|
element.tagName === "P";
|
2021-04-20 03:55:59 +02:00
|
|
|
const isBlockElement = (
|
|
|
|
element: Element
|
|
|
|
): element is HTMLLIElement & HTMLParamElement =>
|
2021-04-21 14:40:16 +02:00
|
|
|
isListItem(element) || isParagraph(element);
|
2021-04-20 03:24:08 +02:00
|
|
|
|
|
|
|
export const getListItem = getAnchorParent(isListItem);
|
|
|
|
export const getParagraph = getAnchorParent(isParagraph);
|
2021-04-20 03:55:59 +02:00
|
|
|
export const getBlockElement = getAnchorParent(isBlockElement);
|
2021-04-28 23:31:45 +02:00
|
|
|
|
|
|
|
export function appendInParentheses(text: string, appendix: string): string {
|
|
|
|
return `${text} (${appendix})`;
|
|
|
|
}
|