0
Fork 0
mirror of https://github.com/fastmail/Squire.git synced 2024-12-22 15:23:29 -05:00
Squire/source/node/Category.ts
Neil Jenkins fe0dfdf6c4 Squire 2.0
This is a massive refactor to port Squire to TypeScript, fix a bunch of small
bugs and modernise our tooling. The development was done on an internal
repository, so apologies to anyone following externally for the commit dump;
updates from here should come as real commits again.

Co-authored-by: Joe Woods <woods@fastmailteam.com>
2023-01-23 13:18:29 +11:00

79 lines
1.9 KiB
TypeScript

import { ELEMENT_NODE, TEXT_NODE, DOCUMENT_FRAGMENT_NODE } from '../Constants';
// ---
const inlineNodeNames =
/^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|HR|I(?:FRAME|MG|NPUT|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|TIME|U|VAR|WBR)$/;
const leafNodeNames = new Set(['BR', 'HR', 'IFRAME', 'IMG', 'INPUT']);
const UNKNOWN = 0;
const INLINE = 1;
const BLOCK = 2;
const CONTAINER = 3;
// ---
let cache: WeakMap<Node, number> = new WeakMap();
const resetNodeCategoryCache = (): void => {
cache = new WeakMap();
};
// ---
const isLeaf = (node: Node): boolean => {
return leafNodeNames.has(node.nodeName);
};
const getNodeCategory = (node: Node): number => {
switch (node.nodeType) {
case TEXT_NODE:
return INLINE;
case ELEMENT_NODE:
case DOCUMENT_FRAGMENT_NODE:
if (cache.has(node)) {
return cache.get(node) as number;
}
break;
default:
return UNKNOWN;
}
let nodeCategory: number;
if (!Array.from(node.childNodes).every(isInline)) {
// Malformed HTML can have block tags inside inline tags. Need to treat
// these as containers rather than inline. See #239.
nodeCategory = CONTAINER;
} else if (inlineNodeNames.test(node.nodeName)) {
nodeCategory = INLINE;
} else {
nodeCategory = BLOCK;
}
cache.set(node, nodeCategory);
return nodeCategory;
};
const isInline = (node: Node): boolean => {
return getNodeCategory(node) === INLINE;
};
const isBlock = (node: Node): boolean => {
return getNodeCategory(node) === BLOCK;
};
const isContainer = (node: Node): boolean => {
return getNodeCategory(node) === CONTAINER;
};
// ---
export {
getNodeCategory,
isBlock,
isContainer,
isInline,
isLeaf,
leafNodeNames,
resetNodeCategoryCache,
};