Submit your widget

on-page text highlighting Search with jQuery

Created 13 years ago   Views 26282   downloads 5375    Author jonraasch
on-page text highlighting Search with jQuery
View DemoDownload
128
Share |

Websites often have search boxes to allow users to find content from their archives. But what if you want to find content on the given page? Information Architects had on-page text search that provides a great user experience. Let’s recreate this using jQuery.

Mark-Up and Interaction

First let’s build an input box for the search:

<input type="text" id="text-search" />

Next we’ll need jQuery to attach a listener to track changes to the input box:

$(function() {
    $('#text-search').bind('keyup change', function(ev) {
        // pull in the new value
        var searchTerm = $(this).val();
    )};
});

Here we bound our function to both the keyup and change events. This ensures that our operation fires regardless of whether the user types or pastes the text.

Now, let’s turn to Highlight, a useful and lightweight jQuery plug-in that handles text highlighting. After including the plug-in source, let’s add a highlight() call to our [removed]

$(function() {
    $('#text-search').bind('keyup change', function(ev) {
        // pull in the new value
        var searchTerm = $(this).val();

        // disable highlighting if empty
        if ( searchTerm ) {
            // highlight the new term
            $('body').highlight( searchTerm );
        }
    });
});

In addition to highlighting the given text, we’ve also added a check to make sure the search term isn’t empty (which causes an infinite loop).

This snippet highlights the search query throughout the page, but we can also limit the scope to a given id:

$('#myId').highlight( searchTerm );

Or we can search only within a certain element:

$('p').highlight( searchTerm );

This text highlighting by default is case insensitive. If you’d prefer case-sensitive highlighting, remove the .toUpperCase() on both lines 21 and 41 of the Highlight plug-in.

Styling the Highlighted Text

Now that the JavaScript is attached, we’ll need to style our highlighted items. The Highlight plug-in wraps the highlighted terms in <span class="highlight"></span>, which we can style with CSS.

First, let’s change the background color and then add rounded corners and a drop-shadow for all browsers except IE:

.highlight {
    background-color: #fff34d;
    -moz-border-radius: 5px; /* FF1+ */
    -webkit-border-radius: 5px; /* Saf3-4 */
    border-radius: 5px; /* Opera 10.5, IE 9, Saf5, Chrome */
    -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); /* FF3.5+ */
    -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); /* Saf3.0+, Chrome */
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); /* Opera 10.5+, IE 9.0 */
}

Although the highlighting is now visible, it still appears a bit tight around the text and could use some padding. But we’ll have to be careful not to adjust the layout of text. These spans are inline elements, and if we simply add padding, the text will shift around on the page. So, let’s include padding with a negative margin to compensate:

.highlight {
    padding:1px 4px;
    margin:0 -4px;
}

Finishing the Interaction

Last but not least, let’s make sure to remove the highlighted text whenever the user edits text in the input box:

$(function() {
    $('#text-search').bind('keyup change', function(ev) {
        // pull in the new value
        var searchTerm = $(this).val();

        // remove any old highlighted terms
        $('body').removeHighlight();

        // disable highlighting if empty
        if ( searchTerm ) {
            // highlight the new term
            $('body').highlight( searchTerm );
        }
    });
});

Here we added a call to remove any text highlighting, which is performed outside of the empty field check. This ensures that the highlight is also removed if the user clears the field.

Although removeHighlight() works well in most browsers, it will crash IE6. This is due to an IE6 bug with node.normalize().

We can get the Highlight plug-in working in IE6 by rewriting this function. Simply replace lines 45-53 of highlight.js with the following:

jQuery.fn.removeHighlight = function() {
 function newNormalize(node) {
    for (var i = 0, children = node.childNodes, nodeCount = children.length; i < nodeCount; i++) {
        var child = children[i];
        if (child.nodeType == 1) {
            newNormalize(child);
            continue;
        }
        if (child.nodeType != 3) { continue; }
        var next = child.nextSibling;
        if (next == null || next.nodeType != 3) { continue; }
        var combined_text = child.nodeValue + next.nodeValue;
        new_node = node.ownerDocument.createTextNode(combined_text);
        node.insertBefore(new_node, child);
        node.removeChild(child);
        node.removeChild(next);
        i--;
        nodeCount--;
    }
 }

 return this.find("span.highlight").each(function() {
    var thisParent = this[removed];
    thisParent.replaceChild(this.firstChild, this);
    newNormalize(thisParent);
 }).end();
};

his new function replaces the standard Javascript normalize() with a custom function that works in all browsers.