I'm writing a function in JavaScript which, when given an element, can look for the previous or next node, assuming a depth-first order traversal. If the next element is out of bounds, it should return null.
I could of course use document.querySelectorAll('*')
, find the index of the element, and then move forwards/backwards by one. But this approach seems like overkill, since I would think it would be inefficient to get the entire DOM tree as a depth-first searched structure, when I could theoretically traverse by one element using local information.
I can't shake the feeling that I'm repeating much of the logic. Can anyone tell if there's a better refactored version I'm not seeing?
//returns previous element in a depth-first search traversal
//returns null if at the start of the tree
TreeWalker.prototype.getPreviousElement = function(element) {
var previousElement;
if(element.previousElementSibling === null) {
var parent = element.parentElement;
if($(parent).is(this.rootSelector)) {
previousElement = null;
} else {
previousElement = parent;
}
} else {
var beforeBranch = element.previousElementSibling;
previousElement = this.cycleToPreviousBranch(beforeBranch);
}
return previousElement;
};
TreeWalker.prototype.cycleToPreviousBranch = function(element) {
var previousElement;
if(element.children.length === 0) {
previousElement = element;
} else {
var lastChild = element.lastElementChild;
previousElement = this.cycleToPreviousBranch(lastChild);
}
return previousElement;
};
//returns next element in a depth-first search traversal
//returns null if at the end of the tree
TreeWalker.prototype.getNextElement = function(element) {
var nextElement;
if(element.children.length > 0) {
nextElement = element.children[0];
} else {
nextElement = this.cycleToNextBranch(element);
}
return nextElement;
};
TreeWalker.prototype.cycleToNextBranch = function(element) {
var nextElement;
if(element.nextElementSibling !== null) {
nextElement = element.nextElementSibling;
} else {
var parent = element.parentElement;
if($(parent).is(this.rootSelector)) {
nextElement = null;
} else {
nextElement = this.cycleToNextBranch(parent);
}
}
return nextElement;
};
if($(parent).is(this.rootSelector))
checks. For example,getNextElement()
could be much simpler without seeing that incycleToNextBranch()
. So, part of simplifying the code requires understand why you're doing this? It is also these checks that makes your code something other than a plain traverser. – jfriend00 Apr 28 at 4:12