Question

I'd like to take the code found here: http://www.jslab.dk/articles/non.recursive.preorder.traversal.part2

// HTML element
var root = document.documentElement;

recursivePreorder(root);

// Recusively find and handle all text nodes
function recursivePreorder(node) {  
  // If node is a text node
  if (node.type == 3) {
    // Do something with node
  }
  // else recurse for each child node
  else {
    for(var i=0; i<node.childNodes.length; i++)
      recursivePreorder(node.childNodes[i]);
  }
}

and convert it into clean jQuery.

Any idea? I know recursion requires argument.callee since the callbacks in jQuery are anonymous, but I'm too new to JQuery to take it any further.

Thanks!

Was it helpful?

Solution

As Code Duck pointed out, jQuery traverses nodes in source-order, depth-first - or, as you call it, pre-order. However, contents only gets immediate children nodes, not descendants. Try this:

$(document).contents ().each (function processNodes ()
{
    if (this.nodeType == 3)
        doSomething (this); // do something with text node
    else
        $(this).contents ().each (processNodes);
});

As an aside, arguments.callee is marked for deprecation, hence the named (as opposed to anonymous) function

OTHER TIPS

Unless this is a homework assignment and you're forced to go through all the loopy madness, there's surely an easier way with jQuery to accomplish whatever you're trying to do...

jQuery has a pretty robust set of selectors that will allow you to just select and return a collection of all of a specified type of element within a page or element (ex. all of the paragraph tags in a given div tag). They'll be returned to you in the order they appear in the DOM (which is pretty much what you get with the above). Alternatively, you can use a filter like suggested above.

If you need to do this in some specific order, then I would suggest using selectors or filters to grab the element you want to start at and then loop through its children recursively. jQuery has a built in function to return the children of a given element.

As a jQuery plugin: (also adds a break feature (like jQuery.each), and an option for pre or post-order; YMMV with post-order)

$.fn.walk = function(visit, post_order) {
    if(this.length === 0) { return; }
    this.each(function(i) {
        if (!post_order) {
            if (visit.call(this, i, this) === false) { return false; }
        }
        $j(this).children().walk(visit, post_order);
        if (post_order) { return visit.call(this, i, this); }
    });
}

I think it's as simple as

var collection=$(document).contents().filter(function() { return this.nodeType == 3; });

Then, you're could either run your commands on the collection set using $.each, or if you want to run a jQuery method on the set, you could not assign it to a variable and chain the method onto the end.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top