mirror of
https://github.com/fastmail/Squire.git
synced 2024-12-23 07:43:52 -05:00
597024eecb
Just return a boolean for the TreeWalker filter fn. This diverges from the spec, but since the goal of this implementation is not to fully implement the spec and we're never going to use a native implementation, this doesn't matter and the code is easier to read when the function is just returning a boolean like any normal filter function.
90 lines
2.3 KiB
JavaScript
90 lines
2.3 KiB
JavaScript
/*jshint strict:false */
|
|
|
|
/*
|
|
Native TreeWalker is buggy in IE and Opera:
|
|
* IE9/10 sometimes throw errors when calling TreeWalker#nextNode or
|
|
TreeWalker#previousNode. No way to feature detect this.
|
|
* Some versions of Opera have a bug in TreeWalker#previousNode which makes
|
|
it skip to the wrong node.
|
|
|
|
Rather than risk further bugs, it's easiest just to implement our own
|
|
(subset) of the spec in all browsers.
|
|
*/
|
|
|
|
var typeToBitArray = {
|
|
// ELEMENT_NODE
|
|
1: 1,
|
|
// ATTRIBUTE_NODE
|
|
2: 2,
|
|
// TEXT_NODE
|
|
3: 4,
|
|
// COMMENT_NODE
|
|
8: 128,
|
|
// DOCUMENT_NODE
|
|
9: 256,
|
|
// DOCUMENT_FRAGMENT_NODE
|
|
11: 1024
|
|
};
|
|
|
|
function TreeWalker ( root, nodeType, filter ) {
|
|
this.root = this.currentNode = root;
|
|
this.nodeType = nodeType;
|
|
this.filter = filter;
|
|
}
|
|
|
|
TreeWalker.prototype.nextNode = function () {
|
|
var current = this.currentNode,
|
|
root = this.root,
|
|
nodeType = this.nodeType,
|
|
filter = this.filter,
|
|
node;
|
|
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 ( ( typeToBitArray[ node.nodeType ] & nodeType ) &&
|
|
filter( node ) ) {
|
|
this.currentNode = node;
|
|
return node;
|
|
}
|
|
current = node;
|
|
}
|
|
};
|
|
|
|
TreeWalker.prototype.previousNode = function () {
|
|
var current = this.currentNode,
|
|
root = this.root,
|
|
nodeType = this.nodeType,
|
|
filter = this.filter,
|
|
node;
|
|
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 ( ( typeToBitArray[ node.nodeType ] & nodeType ) &&
|
|
filter( node ) ) {
|
|
this.currentNode = node;
|
|
return node;
|
|
}
|
|
current = node;
|
|
}
|
|
};
|