File: /var/www/zaklada/html/node_modules/jsdom/lib/jsdom/living/node-iterator.js
"use strict";
const domSymbolTree = require("./helpers/internal-constants").domSymbolTree;
const defineGetter = require("../utils").defineGetter;
const INTERNAL = Symbol("NodeIterator internal");
module.exports = function (core) {
// https://dom.spec.whatwg.org/#interface-nodeiterator
function NodeIteratorInternal(document, root, whatToShow, filter) {
this.active = true;
this.document = document;
this.root = root;
this.referenceNode = root;
this.pointerBeforeReferenceNode = true;
this.whatToShow = whatToShow;
this.filter = filter;
}
NodeIteratorInternal.prototype.throwIfNotActive = function () {
// (only thrown for getters/methods that are affected by removing steps)
if (!this.active) {
throw Error("This NodeIterator is no longer active. " +
"More than " + this.document._activeNodeIteratorsMax +
" iterators are being used concurrently. " +
"You can increase the 'concurrentNodeIterators' option to " +
"make this error go away."
);
// Alternatively, you can pester Ecma to add support for weak references,
// the DOM standard assumes the implementor has control over object life cycles.
}
};
NodeIteratorInternal.prototype.traverse = function (next) {
let node = this.referenceNode;
let beforeNode = this.pointerBeforeReferenceNode;
do {
if (next) {
if (!beforeNode) {
node = domSymbolTree.following(node, { root: this.root });
if (!node) {
return null;
}
}
beforeNode = false;
} else { // previous
if (beforeNode) {
node = domSymbolTree.preceding(node, { root: this.root });
if (!node) {
return null;
}
}
beforeNode = true;
}
}
while (this.filterNode(node) !== core.NodeFilter.FILTER_ACCEPT);
this.pointerBeforeReferenceNode = beforeNode;
this.referenceNode = node;
return node;
};
NodeIteratorInternal.prototype.filterNode = function (node) {
const n = node.nodeType - 1;
if (!(this.whatToShow & (1 << n))) {
return core.NodeFilter.FILTER_SKIP;
}
let ret = core.NodeFilter.FILTER_ACCEPT;
const filter = this.filter;
if (typeof filter === "function") {
ret = filter(node);
} else if (filter && typeof filter.acceptNode === "function") {
ret = filter.acceptNode(node);
}
if (ret === true) {
return core.NodeFilter.FILTER_ACCEPT;
} else if (ret === false) {
return core.NodeFilter.FILTER_REJECT;
}
return ret;
};
NodeIteratorInternal.prototype.runRemovingSteps = function (oldNode, oldParent, oldPreviousSibling) {
if (oldNode.contains(this.root)) {
return;
}
// If oldNode is not an inclusive ancestor of the referenceNode
// attribute value, terminate these steps.
if (!oldNode.contains(this.referenceNode)) {
return;
}
if (this.pointerBeforeReferenceNode) {
// Let nextSibling be oldPreviousSibling’s next sibling, if oldPreviousSibling is non-null,
// and oldParent’s first child otherwise.
const nextSibling = oldPreviousSibling ?
oldPreviousSibling.nextSibling :
oldParent.firstChild;
// If nextSibling is non-null, set the referenceNode attribute to nextSibling
// and terminate these steps.
if (nextSibling) {
this.referenceNode = nextSibling;
return;
}
// Let next be the first node following oldParent (excluding any children of oldParent).
const next = domSymbolTree.following(oldParent, { skipChildren: true });
// If root is an inclusive ancestor of next, set the referenceNode
// attribute to next and terminate these steps.
if (this.root.contains(next)) {
this.referenceNode = next;
return;
}
// Otherwise, set the pointerBeforeReferenceNode attribute to false.
this.pointerBeforeReferenceNode = false;
// Note: Steps are not terminated here.
}
// Set the referenceNode attribute to the last inclusive descendant in tree order of oldPreviousSibling,
// if oldPreviousSibling is non-null, and to oldParent otherwise.
this.referenceNode = oldPreviousSibling ?
domSymbolTree.lastInclusiveDescendant(oldPreviousSibling) :
oldParent;
};
core.Document._removingSteps.push((document, oldNode, oldParent, oldPreviousSibling) => {
for (let i = 0; i < document._activeNodeIterators.length; ++i) {
const internal = document._activeNodeIterators[i];
internal.runRemovingSteps(oldNode, oldParent, oldPreviousSibling);
}
});
core.Document.prototype.createNodeIterator = function (root, whatToShow, filter) {
if (!root) {
throw new TypeError("Not enough arguments to Document.createNodeIterator.");
}
if (filter === undefined) {
filter = null;
}
if (filter !== null &&
typeof filter !== "function" &&
typeof filter.acceptNode !== "function") {
throw new TypeError("Argument 3 of Document.createNodeIterator should be a function or implement NodeFilter.");
}
const document = root._ownerDocument;
whatToShow = whatToShow === undefined ?
core.NodeFilter.SHOW_ALL :
(whatToShow & core.NodeFilter.SHOW_ALL) >>> 0; // >>> makes sure the result is unsigned
filter = filter || null;
const it = Object.create(core.NodeIterator.prototype);
const internal = new NodeIteratorInternal(document, root, whatToShow, filter);
it[INTERNAL] = internal;
document._activeNodeIterators.push(internal);
while (document._activeNodeIterators.length > document._activeNodeIteratorsMax) {
const internalOther = document._activeNodeIterators.shift();
internalOther.active = false;
}
return it;
};
core.NodeIterator = function NodeIterator() {
throw new TypeError("Illegal constructor");
};
defineGetter(core.NodeIterator.prototype, "root", function () {
return this[INTERNAL].root;
});
defineGetter(core.NodeIterator.prototype, "referenceNode", function () {
const internal = this[INTERNAL];
internal.throwIfNotActive();
return internal.referenceNode;
});
defineGetter(core.NodeIterator.prototype, "pointerBeforeReferenceNode", function () {
const internal = this[INTERNAL];
internal.throwIfNotActive();
return internal.pointerBeforeReferenceNode;
});
defineGetter(core.NodeIterator.prototype, "whatToShow", function () {
return this[INTERNAL].whatToShow;
});
defineGetter(core.NodeIterator.prototype, "filter", function () {
return this[INTERNAL].filter;
});
core.NodeIterator.prototype.previousNode = function () {
const internal = this[INTERNAL];
internal.throwIfNotActive();
return internal.traverse(false);
};
core.NodeIterator.prototype.nextNode = function () {
const internal = this[INTERNAL];
internal.throwIfNotActive();
return internal.traverse(true);
};
core.NodeIterator.prototype.detach = function () {
// noop
};
core.NodeIterator.prototype.toString = function () {
return "[object NodeIterator]";
};
};