mirror of
https://github.com/fastmail/Squire.git
synced 2024-12-22 15:23:29 -05:00
fe0dfdf6c4
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>
116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
type NODE_TYPE = 1 | 4 | 5;
|
|
const SHOW_ELEMENT = 1; // NodeFilter.SHOW_ELEMENT;
|
|
const SHOW_TEXT = 4; // NodeFilter.SHOW_TEXT;
|
|
const SHOW_ELEMENT_OR_TEXT = 5; // SHOW_ELEMENT|SHOW_TEXT;
|
|
|
|
const always = (): true => true;
|
|
|
|
class TreeIterator<T extends Node> {
|
|
root: Node;
|
|
currentNode: Node;
|
|
nodeType: NODE_TYPE;
|
|
filter: (n: T) => boolean;
|
|
|
|
constructor(root: Node, nodeType: NODE_TYPE, filter?: (n: T) => boolean) {
|
|
this.root = root;
|
|
this.currentNode = root;
|
|
this.nodeType = nodeType;
|
|
this.filter = filter || always;
|
|
}
|
|
|
|
isAcceptableNode(node: Node): boolean {
|
|
const nodeType = node.nodeType;
|
|
const nodeFilterType =
|
|
nodeType === Node.ELEMENT_NODE
|
|
? SHOW_ELEMENT
|
|
: nodeType === Node.TEXT_NODE
|
|
? SHOW_TEXT
|
|
: 0;
|
|
return !!(nodeFilterType & this.nodeType) && this.filter(node as T);
|
|
}
|
|
|
|
nextNode(): T | null {
|
|
const root = this.root;
|
|
let current: Node | null = this.currentNode;
|
|
let node: Node | null;
|
|
while (true) {
|
|
node = current.firstChild;
|
|
while (!node && current) {
|
|
if (current === root) {
|
|
break;
|
|
}
|
|
node = current.nextSibling;
|
|
if (!node) {
|
|
current = current.parentNode;
|
|
}
|
|
}
|
|
if (!node) {
|
|
return null;
|
|
}
|
|
|
|
if (this.isAcceptableNode(node)) {
|
|
this.currentNode = node;
|
|
return node as T;
|
|
}
|
|
current = node;
|
|
}
|
|
}
|
|
|
|
previousNode(): T | null {
|
|
const root = this.root;
|
|
let current: Node | null = this.currentNode;
|
|
let node: Node | null;
|
|
while (true) {
|
|
if (current === root) {
|
|
return null;
|
|
}
|
|
node = current.previousSibling;
|
|
if (node) {
|
|
while ((current = node.lastChild)) {
|
|
node = current;
|
|
}
|
|
} else {
|
|
node = current.parentNode;
|
|
}
|
|
if (!node) {
|
|
return null;
|
|
}
|
|
if (this.isAcceptableNode(node)) {
|
|
this.currentNode = node;
|
|
return node as T;
|
|
}
|
|
current = node;
|
|
}
|
|
}
|
|
|
|
// Previous node in post-order.
|
|
previousPONode(): T | null {
|
|
const root = this.root;
|
|
let current: Node | null = this.currentNode;
|
|
let node: Node | null;
|
|
while (true) {
|
|
node = current.lastChild;
|
|
while (!node && current) {
|
|
if (current === root) {
|
|
break;
|
|
}
|
|
node = current.previousSibling;
|
|
if (!node) {
|
|
current = current.parentNode;
|
|
}
|
|
}
|
|
if (!node) {
|
|
return null;
|
|
}
|
|
if (this.isAcceptableNode(node)) {
|
|
this.currentNode = node;
|
|
return node as T;
|
|
}
|
|
current = node;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---
|
|
|
|
export { TreeIterator, SHOW_ELEMENT, SHOW_TEXT, SHOW_ELEMENT_OR_TEXT };
|