Question

I'm looking for a script to search and replace text either server-side or client-side.

While it's simple enough to replace all the text in a string with PHP or on the page with jQuery/Javascript, I haven't been able to figure out how to make the script ignore certain sections of text depending on the class of the parent element.

Consider the following case:

<div>
    <span>
        This keyword should be replaced.  
    </span>
    <span class="ignore"> 
        this keyword should be ignored.  
    </span>
    <span> 
        This keyword should be replaced.  
        <span class="ignore"> 
            this keyword should be ignored.  
        </span>
    </span>
    <span class="ignore">
        this keyword should be ignored because of class name.  
        <span> 
            this keyword should also be ignored because it's a child of an ignored element.  
        </span>
    </span>
</div>

If I wanted to replace the word "keyword" with "cow", the expected result should be:

<div>
    <span>
        This cow should be replaced.  
    </span>
    <span class="ignore"> 
        this keyword should be ignored.  
    </span>
    <span> 
        This cow should be replaced.  
        <span class="ignore"> 
            this keyword should be ignored.  
        </span>
    </span>
    <span class="ignore">
        this keyword should be ignored because of class name.  
        <span> 
            this keyword should also be ignored because it's a child of an ignored element.  
        </span>
    </span>
</div>

So far, the simplest logic I came up with is to 1. recursively inspecting each child node and 2. either replace the node text or 3. ignoring the node and its children if the class "ignore" is found.

I'm still trying to find the jQuery syntax to do this. Anyone who can help point me in the right direction or has any input, I would definitely appreciate it.

Thanks

Was it helpful?

Solution 2

Something like this

function replaceKeywords(keyword, newWord) {
    for (var i = 0; i < document.childNodes.length; i++) {
        checkNode(document.childNodes[i]);
    }
    function checkNode(node) {
        var nodeName = node.nodeName.toLowerCase();
        if (nodeName === 'script' || nodeName === 'style' || ~(node.className || "").indexOf('ignore')) { return; }
        if (node.nodeType === 3) {
            var text = node.nodeValue;
            var regEx = new RegExp(keyword, 'gi');
            var newText = text.replace(regEx, newWord);
            node.nodeValue = newText;
        }
        if (node.childNodes.length > 0) {
            for (var j = 0; j < node.childNodes.length; j++) {
                checkNode(node.childNodes[j]);
            }
        }
    }
}

//Use like
replaceKeywords('keyword','cow');

Uses javascript to walk the entire DOM tree, looking specifically for textNodes (nodeType 3) and uses a regex to replace the keyword with the newWord (ignoring case), then recursively through each nodes children. Ignores <script>, <style> and elements with the class of ignore.

OTHER TIPS

Although Ojay's solution also works, I ended up using a slight derivative of Arun P Johny's solution since the jQuery library was already linked in the header. It was more efficient than my original logic because no explicit recursion is needed.

I'll share it again here in case someone else has a similar need.

$('*').not('.ignore, .ignore *').contents().each(function () { //select all nodes except for those with the class ignore

    if (this.nodeType == 3) { //if this is a text node
        this.nodeValue = this.nodeValue.replace(/keyword/g, 'cow'); //replace text
    }
}) 

Thanks everyone for your prompt and professional input.

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