jQuery is a powerful library which simplifies working with JavaScript. Using CSS-like selectors it allows you to grab DOM elements on a page and run some operations on it. As you might’ve guessed the power is not only in what kind of operations you may perform but also how efficiently you are able to select the elements that you’re interested in. jQuery ships with quite a few filters among which Content Filters: selectors which allow you to select DOM elements based on the text they contain. And while the standard filters allow you to do some basic comparisons they are not powerful enough in more advanced scenarios.

:contains filter flaw no. 1

One of the standard filters for selecting elements based on their content is the :contains(text) filter. It matches all elements which contain the given text. Its major flaw is that it’s case-sensitive by default. Personally, most of the time I don’t need a text comparison to be case-sensitive. It is in general more intuitive for the end-users to find the text they type no matter the casing. Quite a few people on the Internet agree with me on this one. It was only a matter of time when the case-insensitive version of the :contains filter appeared on the Internet. An example of the alternative version is:

jQuery.extend(
    jQuery.expr[':'], {
        Contains: "jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0"
    }
);

By converting both the selected text and the text that you’re looking for to upper case before matching you can simulate a case-insensitive search. The only difference between using the case-sensitive and case-insensitive version as defined above is the capital letter C in the filter’s name. Of course you could change it to anything else what would make sense to you and other people working with your code.

:contains filter flaw no. 2

As you might’ve noticed in the JavaScript snippet above, the contains filter uses indexOf method of string to check whether the given string contains a particular piece of text or not. While this method is sufficient in most situations you may face scenarios when a simple match is not enough. Using Regular Expressions might be just the answer you’ve been looking for.

It’s quite surprising that jQuery doesn’t ship with support for Regular Expressions. I would definitely agree that they aren’t an answer to everything and you should use them wisely. But if you want to use them, and you have a good reason to do so, they are not there. Luckily it’s not that difficult to extend jQuery with an extra Regular Expressions-based Content Filter.

jQuery.extend(
    jQuery.expr[':'], {
        regex: function(a, i, m, r) {
            var r = new RegExp(m[3], 'i');
            return r.test(jQuery(a).text());
        }
    }
);

Believe it or not, but the few lines of code above is all you need to extend jQuery with support for regular expression text matches. What the above does is to define a new filter called regex. Each time the filter is called, it creates a new Regular Expression using the value passed as the parameter of the filter. Additionally the expression will use a case-insensitive match (you could remove it by deleting the i from the second parameter of RegExp constructor). If the text of the current DOM object matches the expression the object will be added to the array of matches.

You can use the regex filter as follows:

$("p:regex('[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}')")

The example above would return all paragraphs which contain an e-mail address.

Summary

jQuery is a very powerful JavaScript library: not only because of the standard functions it provides but also thanks to its extensibility. Where the out-of-the-box functionality is not enough, you can easily write your own functions to get the job done. An example of extensibility is extending jQuery with a regex Content Filter. Together with the contains Content Filter it provides a powerful mechanism for retrieving DOM elements.

Technorati Tags: ,