tags:

views:

154

answers:

3

I have spent two days on this, so I will be disheartened if there is a simple answer. I am trying to put a span tag around every letter in a div, while leaving the rest of the tags intact.

<div id="div">
    <p>
      Of course some of the <strong>text is in other tags</strong> and <strong>some 
      is  in <em>nested tags</em>, etc.</strong>
    </p>
</div>

I get very close, but something always trips me up in the end.

+2  A: 

I got it! This may not be the optimal solution, but it works! Also note that because of the extra tags, whitespace may get messed up. This also wraps tabs but that's easy to fix too.

function wrap(target) {
    var newtarget = $("<div></div>");
    nodes = target.contents().clone(); // the clone is critical!
    nodes.each(function() {
        if (this.nodeType == 3) { // text
            var newhtml = "";
            var text = this.wholeText; // maybe "textContent" is better?
            for (var i=0; i < text.length; i++) {
                if (text[i] == ' ') newhtml += " ";
                else newhtml += "<span>" + text[i] + "</span>";
            }
            newtarget.append($(newhtml));
        }
        else { // recursion FTW!
            $(this).html(wrap($(this)));
            newtarget.append($(this));
        }
    });
    return newtarget.html();
}

Usage:

$("#div").html(wrap($("#div")));
Tesserex
This doesn't seem to work for me - I can see that it correctly builds up the newhtml string in a debugger, but `$(this).html(newhtml)` doesn't result in any change to the output...
Ryley
I fixed it! Maybe more people can find ways to optimize?
Tesserex
I also just tested it on a saved copy of the jQuery api page. It took a second, but it worked, the page appearance didn't change, everything is intact. Seems to work.
Tesserex
I think that wholeText has some compatibility issues, but I might be able to use this as a springboard. I think the recursion will help me. I was trying to stay away from textNode==3, but I suppose it is pretty safe on all browsers. I will work on it tomorrow. I also need the whitespace wrapped, but that is easy enough.
Rob
A: 
function init(target) {
var newtarget = $('<div></div>'); 
nodes = target.contents().clone(); // the clone is critical! 
nodes.each(function(i,v) { 
    if (v.nodeType == 3) { // text
        if($.trim($(this).text()).length>0){
            var letters=$(this).text().split('');
            for (var j = 0; j < letters.length; j++) {
                newtarget.append('<span class="letter">'+letters[j]+'</span>')
            }
        }
    } 
    else { // recursion FTW! 
        newtarget.append($(this)); 
        $(this).html(init($(this))); 
    } 
});
return newtarget.html(); 

}

This works fairly well. However, ie (7 anyway), strips out all of the spaces. Also, should I remove newtarget from the dom at the end of the function? And what about the clone? Should that be removed?

Rob
+1  A: 

You might want to have a look at my plugin, TextGrad, which allows to do exactly that with the "spanize" method added in jQuery object.

http://github.com/subtenante/TextGrad

Edit:

I forgot (!) I have a demo there :

http://www.si-les-idees-suffisaient.net/jquery/textgrad.html

subtenante