“use strict”;
const DOMException = require(“../../web-idl/DOMException”); const idlUtils = require(“../generated/utils”); const conversions = require(“webidl-conversions”);
// FIXME: Once NodeFilter is ported to IDL method, uncomment these. const FILTER_ACCEPT = 1; // NodeFilter.FILTER_ACCEPT; const FILTER_REJECT = 2; // NodeFilter.FILTER_REJECT; const FILTER_SKIP = 3; // NodeFilter.FILTER_SKIP; const FIRST = false; const LAST = true; const NEXT = false; const PREVIOUS = true;
function isNull(o) {
return o === null || typeof o === "undefined";
}
class TreeWalkerImpl {
constructor(args, privateData) { this.root = privateData.root; this.whatToShow = privateData.whatToShow; this.filter = privateData.filter; this.currentNode = this.root; } get currentNode() { return this._currentNode; } set currentNode(node) { if (isNull(node)) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot set currentNode to null"); } this._currentNode = node; } parentNode() { let node = this._currentNode; while (!isNull(node) && node !== this.root) { node = node.parentNode; if (!isNull(node) && this._filterNode(node) === FILTER_ACCEPT) { return (this._currentNode = node); } } return null; } firstChild() { return this._traverseChildren(FIRST); } lastChild() { return this._traverseChildren(LAST); } previousSibling() { return this._traverseSiblings(PREVIOUS); } nextSibling() { return this._traverseSiblings(NEXT); } previousNode() { let node = this._currentNode; while (node !== this.root) { let sibling = node.previousSibling; while (!isNull(sibling)) { node = sibling; let result = this._filterNode(node); while (result !== FILTER_REJECT && node.hasChildNodes()) { node = node.lastChild; result = this._filterNode(node); } if (result === FILTER_ACCEPT) { return (this._currentNode = node); } sibling = node.previousSibling; } if (node === this.root || isNull(node.parentNode)) { return null; } node = node.parentNode; if (this._filterNode(node) === FILTER_ACCEPT) { return (this._currentNode = node); } } return null; } nextNode() { let node = this._currentNode; let result = FILTER_ACCEPT; for (;;) { while (result !== FILTER_REJECT && node.hasChildNodes()) { node = node.firstChild; result = this._filterNode(node); if (result === FILTER_ACCEPT) { return (this._currentNode = node); } } do { if (node === this.root) { return null; } const sibling = node.nextSibling; if (!isNull(sibling)) { node = sibling; break; } node = node.parentNode; } while (!isNull(node)); if (isNull(node)) { return null; } result = this._filterNode(node); if (result === FILTER_ACCEPT) { return (this._currentNode = node); } } } toString() { return "[object TreeWalker]"; } _filterNode(node) { const n = node.nodeType - 1; if (!((1 << n) & this.whatToShow)) { return FILTER_SKIP; } const filter = this.filter; if (isNull(filter)) { return FILTER_ACCEPT; } let result; if (typeof filter === "function") { result = filter(idlUtils.wrapperForImpl(node)); } else { result = filter.acceptNode(idlUtils.wrapperForImpl(node)); } result = conversions["unsigned short"](result); return result; } _traverseChildren(type) { let node = this._currentNode; node = type === FIRST ? node.firstChild : node.lastChild; if (isNull(node)) { return null; } main: for (;;) { const result = this._filterNode(node); if (result === FILTER_ACCEPT) { return (this._currentNode = node); } if (result === FILTER_SKIP) { const child = type === FIRST ? node.firstChild : node.lastChild; if (!isNull(child)) { node = child; continue; } } for (;;) { const sibling = type === FIRST ? node.nextSibling : node.previousSibling; if (!isNull(sibling)) { node = sibling; continue main; } const parent = node.parentNode; if (isNull(parent) || parent === this.root || parent === this._currentNode) { return null; } node = parent; } } } _traverseSiblings(type) { let node = this._currentNode; if (node === this.root) { return null; } for (;;) { let sibling = type === NEXT ? node.nextSibling : node.previousSibling; while (!isNull(sibling)) { node = sibling; const result = this._filterNode(node); if (result === FILTER_ACCEPT) { return (this._currentNode = node); } sibling = type === NEXT ? node.firstChild : node.lastChild; if (result === FILTER_REJECT || isNull(sibling)) { sibling = type === NEXT ? node.nextSibling : node.previousSibling; } } node = node.parentNode; if (isNull(node) || node === this.root) { return null; } if (this._filterNode(node) === FILTER_ACCEPT) { return null; } } }
}
module.exports = {
implementation: TreeWalkerImpl
};