I am surprised there isn't some cookbook code ready that enumerates or searches along the preceding-axis in a DOM with javascript the way that XPath can do it. And of course, the following-axis as well.
Example problem is: I have a text node, and I want to find the preceding text node.
Obviously the precedingSibling is insufficient, because there could be none, or it could be an element.
I have implemented that several times for myself, but am too lazy to try to find my code. Instead I prefer doing it over again. But also like to compare notes, and surprised that nobody seems to ask about it, or show off theirs.
So here is a function signature with some beginning scribble:
Node.prototype.findPrevious function(foundPr = x => x, giveUpPr = () => false) {
node = this;
while(true) {
let previousSibling = node.previousSibling;
if(!previousSibling) // no previousSibling means we need to go up
while(true) {
const parent = node.parentNode;
previousSibling = parent.previousSibling;
if(parent.previousSibling)
break;
node = parent;
if(!node || giveUpPr(node))
return null;
}
// now we have the nearest previous sibling (or we gave up already)
node = previousSibling;
// but we aren't done, we have to go down now
// now finally we have the last previous item
while(true) {
let lastChild = node.lastChild;
if(!lastChild)
break;
node = lastChild;
}
// now our node is the deepest lastChild that doesn't have any more children
// now only can we check our found predicate:
if(foundPr(node))
return node;
// and if not we go to the beginning
}
};
I guess I just wrote the code instead of explaining what it would do. And the cool thing is that the same logic works the other way around for findNext:
Node.prototype.findNext = function(foundPr = x => x, giveUpPr = () => false) {
let node = this;
while(true) {
let nextSibling = node.nextSibling;
if(!nextSibling) // no nextSibling means we need to go up
while(true) {
const parent = node.parentNode;
nextSibling = parent.nextSibling;
if(nextSibling)
break;
node = parent;
if(!node || giveUpPr(node))
return null;
}
// now we have the nearest next sibling (or we gave up already)
node = nextSibling;
// but we aren't done, we have to go down now
// now finally we have the first next item
while(true) {
let firstChild = node.firstChild;
if(!firstChild)
break;
node = firstChild;
}
// now our node is the deepest firstChild that doesn't have any more children
// now only can we check our found predicate:
if(foundPr(node))
return node;
// and if not we go to the beginning trying the nextSibling
}
};
But isn't there some built-in solution already?