2

I want to make a word bold in given paragraph. Here is a javascript code.

        var hlWord = "idm";
        var nregex = new RegExp(hlWord,"gi");
        var div = document.getElementById("SR").innerHTML;
        var rword = div.replace(nregex,"<b>"+hlWord+"</b>");
        document.getElementById("SR").innerHTML = rword;  

Here is a HTML code.

<div id="SR">
Download here free idm.
<a href="http://www.anywebsite.com/idm">click here to download</a>
</div>  

This is work well and make all idm bold but here is a problem that it also change url to like this

<a href="http://www.anywebsite.com/<b>idm</b>">click here to download</a>  

This is not a valid url.This is the problem that this code make the url damaged. Please tell me how can I avoid this.
Thanks...

1
  • I don't know how deep your example goes but for your posted example, you could just use var nregex = /idm/i;. Commented Apr 15, 2013 at 3:59

2 Answers 2

0

You can iterate through all the text nodes with the methods in this thread, change them and replace them with new bold ones.

var hlWord = "idm";
var nregex = new RegExp(hlWord,"gi");

var sr = document.getElementById('SR');

function escape_html(html) {
    return html.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}

(function findTextNodes(current) {
    // make a shadow copy of the child nodes.
    var current_children = Array.prototype.slice.call(current.childNodes);
    for(var i = 0; i < current_children.length; i++) {
        var child = current.childNodes[i];
        // text node
        if(child.nodeType == 3) {
            var value = escape_html(child.nodeValue);
            var html = value.replace(nregex, '<b>' + hlWord + '</b>');
            if (html != value) {
                var node = document.createElement('div');
                node.innerHTML = html;
                // make a shadow copy of the child nodes.
                var childNodes = Array.prototype.slice.call(node.childNodes);
                // replace the plain text node with the bold segments
                for (var j = 0; j < childNodes.length; j++) {
                    var c = childNodes[j];
                    current.insertBefore(c, child);
                }
                current.removeChild(child);
            }
        }
        else {
            findTextNodes(child);
        }
    }
})(sr);

Check the code example at jsFiddle.

UPDATE:

  • Passerby pointed out that innerHTML should be used carefully. Escape text nodeValue before processing.
Sign up to request clarification or add additional context in comments.

6 Comments

Though rare, but some text have meaning as HTML code, so directly modifying innerHTML may lead to unexpected result: jsfiddle.net/r9Qrr/3
If you're going to use someone else's code, at least reference it: stackoverflow.com/questions/3963872/…
@Passerby You're right. The text nodeValue needs to be escaped before processing replacement.
@lan I didn't reference that thread. I searched for text node traversal and found another thread which was posted earlier that the one you listed, and I had attached the link this thread in the first paragraph the first time I posted my answer.
@ArieShaw I don't think so, your code is almost exactly the same as the one I found and provided. And you never included anything in the first time you posted the answer - I can see your edit history and I remember your original answer. Nothing was added until I said something. Anyways, it doesn't matter, you made a great solution
|
0

After some try-and-fail, I made a working demo that may be more complicated than you might have think:

http://jsfiddle.net/4VKNk/

var cache=[];
var reg=/idm/gi;
var id=function(ID){return document.getElementById(ID);}
function walkElement(ele){
    if(ele.childNodes.length>0){
        for(var i=0;i<ele.childNodes.length;i++){
            walkElement(ele.childNodes[i]);
        }
    }else if(ele.nodeType==3){//text node
        if(reg.test(ele.nodeValue)){
            cache.push(ele);
        }
    }
}
id("test").onclick=function(){
    cache=[];
    walkElement(id("SR"));
    while(cache.length>0){
        var ele=cache.shift();
        var val=ele.nodeValue;
        var pnt=ele.parentNode;
        var nextSibling=ele.nextSibling;
        var i=0;
        var r,tmp;
        pnt.removeChild(ele);
        while(r=reg.exec(val)){
            tmp=document.createTextNode(val.substring(i,r.index));
            if(nextSibling){
                pnt.insertBefore(tmp,nextSibling);
                tmp=document.createElement("strong");
                tmp.appendChild(document.createTextNode("idm"));
                pnt.insertBefore(tmp,nextSibling);
            }else{
                pnt.appendChild(tmp);
                tmp=document.createElement("strong");
                tmp.appendChild(document.createTextNode("idm"));
                pnt.appendChild(tmp);
            }
            i=reg.lastIndex;
        }
        if(i<val.length-1){
            tmp=document.createTextNode(val.substring(i,val.length));
            if(nextSibling){
                pnt.insertBefore(tmp,nextSibling);
            }else{
                pnt.appendChild(tmp);
            }
        }
    }
};

I took the approach of DOM manipulation.

Explanation:

  1. Walk through the whole DOM tree under target element, and cache all TEXT_NODE (nodeType==3);
  2. Use RegExp.exec() method to get the index of each match;
  3. While you find a match, add back the text that come before it, and then add a highlight element (<strong>) that contains the match; continue this step;
  4. If we still have text left, add it back.

The reason I need to cache the TEXT_NODEs first, is that if we directly modify it in walkElement, it will change childNodes.length of its parent, and break the process.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.