- From: Leo Deng <myst.dg@gmail.com>
- Date: Fri, 10 Aug 2012 15:40:11 +0800
- To: www-dom@w3.org
Hello, According to DOM4, when an author creates a TreeWalker object, the return value of the acceptNode() method would be one of the following three: FILTER_ACCEPT the current node passes the filter (and the descendant would still be traversed). FILTER_REJECT the current node doesn't pass the filter, and the descendant would not be traversed. FILTER_SKIP the current node doesn't pass the filter, but continue traversing the decendants. All three values can't describe the "the current node passes the filter, but the descendants would not be traversed" state. In other words, there's a missing value: FILTER_ACCEPT FILTER_REJECT FILTER_SKIP FILTER_? passes the YES NO NO YES filter descendants YES NO YES NO traversed Consider a use case when an author wants to select any <div> element in an element with id "myid" such that it's not a descendant of an element matching ".any". With TreeWalker, the following JavaScript code can achieve this. var selected = []; var domWalker = document.createTreeWalker( document.getElementById('myid'), NodeFilter.SHOW_ELEMENT, { acceptNode: function(node) { if((node.parentNode.classList.contains('any')) { return NodeFilter.FILTER_REJECT; } else if(node.tagName == 'DIV') { return NodeFilter.FILTER_ACCEPT; } else { return NodeFilter.FILTER_SKIP; } } }, false ); while(domWalker.nextNode()) { selected.push(domWalker.currentNode); } For a node matching "div.any", when UA traverses it, among all three possible return value of acceptNode(), only FILTER_ACCEPT indicates that this node passes the filter. However, FILTER_ACCEPT couldn't stop UA from traversing its children, so when its children is being traversed, the code has to determine if the parent node is matching ".any" to determine if acceptNode() can return a FILTER_REJECT here. If acceptNode() can return a value representing "the current node passeds the filter, but the descendants would not be traversed", say, FILTER_FINISH, then when UA traverses a node that passes the filter, it may still decide not to traverse the children of the node. Therefore, there's no longer a need to use *the characteristics of the parent node* to decide what the return value of acceptNode() for the current node is (which is also prone to error. For example, the above code throws when the element with id "myid" doesn't have a parent): var selected = []; var domWalker = document.createTreeWalker( document.getElementById('myid'), NodeFilter.SHOW_ELEMENT, { acceptNode: function(node) { if((node.parentNode.classList.contains('any')) { return node.tagName == 'DIV' ? NodeFilter.FILTER_FINISH : NodeFilter.FILTER_REJECT; } else { return node.tagName == 'DIV' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; } } }, false ); while(domWalker.nextNode()) { selected.push(domWalker.currentNode); } FILTER_FINISH would be equivalent to FILTER_ACCEPT when used for a filter of a NodeIterator. Cheer, Leo
Received on Sunday, 12 August 2012 16:24:37 UTC