1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
$.fn.textNodes = function() { var ret = []; this.each( function() { var fn = arguments.callee; $(this).contents().each( function() { if ( this.nodeType == 3 || $.nodeName(this, "br") ) ret.push( this ); else fn.apply( $(this) ); }); }); return $(ret); } // example: wrap all text nodes in a span $("body").textNodes().wrap("<span/>");
Refactorings
No refactoring yet !
jp.stacey
June 29, 2008, June 29, 2008 21:32, permalink
From what you say, you only need the descendants, not the starting node(s). So you can get it a bit smaller (and a little bit quicker) by removing one of your two function() blocks. How does this look to you?
You might get even quicker by using this.childNodes (which is what jQuery's contents() function uses internally), as long as you don't need to worry about iframes.
1 2 3 4 5 6 7 8 9 10
$.fn.textNodes = function() { var ret = []; this.contents().each( function() { var fn = arguments.callee; if ( this.nodeType == 3 || $.nodeName(this, "br") ) ret.push( this ); else $(this).contents().each(fn); }); return $(ret); }
Eineki
June 30, 2008, June 30, 2008 10:43, permalink
Let me say that I'm rather new to jquery and my suggestions are probably naif.
Why don't you use something like this?
It is too slow?
1 2 3
$.fn.textNodes = function() { return this.find(*).filter(function(index) { return (this.nodeType==3)||(this.nodeName="br")}).andSelf(); }
jed
July 8, 2008, July 08, 2008 16:27, permalink
@jp.stacey
Good catch. I did some informal profiling, and here's what I got on average:
(1) my original code: ~4100ms
(2) your refactor: ~2800ms
(3) your refactor w/ childNodes and no arguments.callee variable: ~2600ms
Not too shabby, thanks for your help!
@Eineki
Unfortunately, this.find(*) does not return text nodes.
1 2 3 4 5 6 7 8 9
$.fn.textNodes = function() { var ret = []; $.each(this[0].childNodes, function() { if ( this.nodeType == 3 || $.nodeName(this, "br") ) ret.push( this ); else $.each(this.childNodes, arguments.callee); }); return $(ret); }
Artur Honzawa
August 25, 2008, August 25, 2008 16:52, permalink
Care to profile this version? I've skipped the jQuery library altogether, should be faster.
1 2 3 4 5 6 7 8 9 10 11 12 13
$.fn.textNodes = function() { var ret = []; (function(el){ if (!el) return; if ((el.nodeType == 3)||(el.nodeName =="BR")) ret.push(el); else for (var i=0; i < el.childNodes.length; ++i) arguments.callee(el.childNodes[i]); })(this[0]); return $(ret); }
Artur Honzawa
August 25, 2008, August 25, 2008 17:18, permalink
Oops. The "if (!el) return;" is not necessary.
This function returns a jQuery object containing all descendent text nodes (and <br/> line breaks) within the context node. I'm looking to make this function as fast as possible, since I need to call it very frequently.