Skip to content

Instantly share code, notes, and snippets.

@boof
Created July 19, 2011 17:09
Show Gist options
  • Save boof/1093111 to your computer and use it in GitHub Desktop.
Save boof/1093111 to your computer and use it in GitHub Desktop.
[WIP] Pure JavaScript implementation of "Document Object Model Traversal".
(function(window, document) {
if ( !window.NodeFilter ) {
var NodeFilter = function() {};
NodeFilter.FILTER_ACCEPT = 1;
NodeFilter.FILTER_REJECT = 2;
NodeFilter.FILTER_SKIP = 3;
NodeFilter.SHOW_ALL = 0xFFFFFFFF;
NodeFilter.SHOW_ELEMENT = 0x00000001;
NodeFilter.SHOW_ATTRIBUTE = 0x00000002;
NodeFilter.SHOW_TEXT = 0x00000004;
NodeFilter.SHOW_CDATA_SECTION = 0x00000008;
NodeFilter.SHOW_ENTITY_REFERENCE = 0x00000010;
NodeFilter.SHOW_ENTITY = 0x00000020;
NodeFilter.SHOW_PROCESSING_INSTRUCTION = 0x00000040;
NodeFilter.SHOW_COMMENT = 0x00000080;
NodeFilter.SHOW_DOCUMENT = 0x00000100;
NodeFilter.SHOW_DOCUMENT_TYPE = 0x00000200;
NodeFilter.SHOW_DOCUMENT_FRAGMENT = 0x00000400;
NodeFilter.SHOW_NOTATION = 0x00000800;
NodeFilter.prototype.acceptNode = function(n) {
return NodeFilter.FILTER_ACCEPT;
};
window.NodeFilter = NodeFilter;
}
if ( !document.createTreeWalker ) {
/*
* http://codesearch.google.com/#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/dom/TreeWalker.cpp
* http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html
*/
function TreeWalker(root, whatToShow, filter, entityReferenceExpansion) {
// RADAR
// This is imho not necessary 'cause IE<9 doesn't support overwriting
// property setters on non-DOM objects and other browsers have already
// TreeWalker support.
// Maybe TreeWalker can be implemented as DOM object?
// Note: For IE we use Object.defineProperty!
var currentNode;
this.__defineSetter__('currentNode', function(node) {
if ( node === null ) { throw( DOMException.NOT_SUPPORTED_ERR ); }
return currentNode = node;
});
this.__defineGetter__('currentNode', function() {
return currentNode;
});
this.parentNode = function() {
var node, filterResult = NodeFilter.FILTER_ACCEPT;
while ( node !== root ) {
node = this.currentNode.parentNode;
if ( !node ) { return null; }
if ( typeof(filter) == 'function' ) try {
filterResult = filter.acceptNode( node );
} catch (e) {
return null;
}
if ( filterResult === NodeFilter.FILTER_ACCEPT ) {
return currentNode = node;
}
}
return null;
};
this.firstChild = function() {
for (var node = node.firstChild, filterResult = NodeFilter.FILTER_ACCEPT; node;) {
if ( typeof(filter) == 'function' ) try {
filterResult = filter.acceptNode( node );
} catch (e) {
return null;
}
switch ( filterResult ) {
case NodeFilter.FILTER_ACCEPT: return currentNode = node;
case NodeFilter.FILTER_SKIP:
if ( node.firstChild ) {
node = node.firstChild;
continue;
}
break;
case NodeFilter.FILTER_REJECT: break;
}
do {
if ( node.nextSibling ) {
node = node.nextSibling;
break;
}
node = node.parentNode;
if ( node === root || node === currentNode ) {
return null;
}
} while ( node )
}
return null;
};
this.lastChild = function() {};
};
(function(fn) {
fn.previousSibling = function() {};
fn.nextSibling = function() {};
fn.previousNode = function() {
var node;
node = this.previousSibling();
if ( node ) { return this.lastChild() || node; }
node = this.parentNode();
if ( node ) { return this.previousNode(); }
return node;
};
fn.nextNode = function() {
var node;
node = this.firstChild() || this.nextSibling();
if ( node ) { return node; }
node = this.parentNode();
if ( node ) { return this.nextNode(); }
return node;
};
})(TreeWalker.prototype)
document.createTreeWalker = TreeWalker;
}
})(window, document);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment