1

How can I (efficiently - not slowing the computer [cpu]) highlight a specific part of a page?

Lets say that my page is as so:

<html>
<head>
</head>
<body>
"My generic words would be selected here" !.
<script>
//highlight code here
var textToHighlight = 'selected here" !';
//what sould I write here?
</script>
</body>
</html>

My idea is to "clone" all the body into a variable and find via indexOf the specified text, change(insert a span with a background-color) the "cloned" string and replace the "real" body with the "cloned" one.
I just think that it isn't efficient.
Do you have any other ideas? (be creative :) )

3 Answers 3

5

I've adapted the following from my answers to several similar questions on SO (example). It's designed to be reusable and has proved to be so. It traverses the DOM within a container node you specify, searching each text node for the specified text and using DOM methods to split the text node and surround the relevant chunk of text in a styled <span> element.

Demo: http://jsfiddle.net/HqjZa/

Code:

// Reusable generic function
function surroundInElement(el, regex, surrounderCreateFunc) {
    // script and style elements are left alone
    if (!/^(script|style)$/.test(el.tagName)) {
        var child = el.lastChild;
        while (child) {
            if (child.nodeType == 1) {
                surroundInElement(child, regex, surrounderCreateFunc);
            } else if (child.nodeType == 3) {
                surroundMatchingText(child, regex, surrounderCreateFunc);
            }
            child = child.previousSibling;
        }
    }
}

// Reusable generic function
function surroundMatchingText(textNode, regex, surrounderCreateFunc) {
    var parent = textNode.parentNode;
    var result, surroundingNode, matchedTextNode, matchLength, matchedText;
    while ( textNode && (result = regex.exec(textNode.data)) ) {
        matchedTextNode = textNode.splitText(result.index);
        matchedText = result[0];
        matchLength = matchedText.length;
        textNode = (matchedTextNode.length > matchLength) ?
            matchedTextNode.splitText(matchLength) : null;
        surroundingNode = surrounderCreateFunc(matchedTextNode.cloneNode(true));
        parent.insertBefore(surroundingNode, matchedTextNode);
        parent.removeChild(matchedTextNode);
    }
}

// This function does the surrounding for every matched piece of text
// and can be customized  to do what you like
function createSpan(matchedTextNode) {
    var el = document.createElement("span");
    el.style.backgroundColor = "yellow";
    el.appendChild(matchedTextNode);
    return el;
}

// The main function
function wrapText(container, text) {
    surroundInElement(container, new RegExp(text, "g"), createSpan);
}

wrapText(document.body, "selected here");
Sign up to request clarification or add additional context in comments.

3 Comments

My problem is that I don't know the parent node. so in that aspect it wont be that efficient.
@agam360: You don't need to know the parent node, only an ancestor node. You need that for an innerHTML solution too, and my solution will generally outperform one based on innerHTML, as well as being more robust (think of an attribute containing the search term, for example).
How do you cleanup anything which was wrapped, before wrapping again? see demo
1
<html>
<head>
</head>
<body>
<p id="myText">"My generic words would be selected here" !.</p>
<script>
//highlight code here
var textToHighlight = 'selected here" !';
var text = document.getElementById("myText").innerHTML
document.getElementById("myText").innerHTML = text.replace(textToHighlight, '<span style="color:red">'+textToHighlight+'</span>');
//what sould I write here?
</script>
</body>
</html>

4 Comments

What are your efficiency concerns? Efficient by itself doesn't provide enough information.
@SelimOber, I mean by efficient: - Low CPU consumption
There are two methods for your operation: 1 - with regulare expression => required many resources (CPU-heavy) 2 - looking for a string and replace without Regex (see my example) => perfomant but not limited to complex strings Sorry for my Englich
The bigger problem is the inefficiency of replacing the whole innerHTML of a potential complex element, which will dwarf any inefficiency of using a regular expression. The alternative is DOM traversal.
0

Use this in combination with this and you should be pretty ok. (It is almost better than trying to implement selection / selection-highlighting logic yourself.)

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.