A Javascript CSS3 Selector and Matcher not using XPath

NWMatcher 1.1.1.js is the latest update on Google Code, it is at SVN r71 (20090516). It is highly suggested to upgrade to 1.1.1

NWMatcher development and sources can be downloaded from GitHub, they contain both Prototype and jQuery selector test units.

Version 1.1.1 is the current release since all the features and bug fixes are now included. Freezed 1.1.1 is available on Google Code SVN !

The caching system have been reworked to avoid DOM manipulation slow down when using Mutation Events.

Many bugs have been fixed to make this work on older Safari 2.0.x and Mozilla 1.7.

Straight to the TESTS

A modified SLICKSPEED TEST allowing for variable number of iterations.

The original SLICKSPEED TEST courtesy of the Mootools team.

Numbers doesn't always show the truth, however great job.

Testing NWMatcher with official Prototype 1.6.0.3 selector test unit.

Testing NWMatcher with official jQuery 1.3.2 selector test unit.

Despite being a W3C CSS specification, as of today, "document order" is not implemented in most frameworks/libraries.

NWMatcher has been the first selector engine to implement "document ordered" result sets. This is really important to extract document TOC's or serialize submitted form fields. Currently, it seems the only other selector engine implementing "document ordered" is Dean Edwards Base2 (that I am aware of) Some unit tests in Prototype and jQuery had to be modified to account for "document order".

Updates: it seems that John Resig has finally added this to jQuery 1.3.2, Sly 1.0rc from Harald Kirschner was also fixed to return "document ordered" result sets.

Why another one ?

A very long story, to be as short as possible I needed faster and more compact code to:

Test if the element match the criteria written as CSS selector.

At that time most frameworks/libraries only provided a similar approach, too slow for my needs:

Go through all matching elements and see if element is there.

Some time stolen to my main project and some extra sleepless nights allowed me to finally "close the circle" and publish a quite capable Event Manager that is now using NWMatcher to its full potential for event delegation (as was initially planned).

Is there something new ?

Sure there is. You may have not noticed yet, but as an extra to what standard selector engines offers, by coupling NWEvents and NWMatcher you get methods that let you solve the "onload" problem most times. Look here for more info on this new way to handle the problem: This is something like Behaviors, but events can be attached earlier, no need to wait "onload" and only one event is attached for each group of elements and future dynamically inserted elements if they match the group criteria (selector).

When I started this, there where few choices fast enough for my needs, one was the very basic getElementsBySelector() written by Simon Willison the other one was CSSQuery by Dean Edwards. After testing both engines I realized that speed was a big problem and should left all the goodies of Dean CSSQuery and just stay with the simpler one. Less CSS selectors compatibility but at least with Simon getElementBySelector() I could easily setup a proof of concept and see it working, slowly on the worst cases but still working.

The final touch up

In the last years I have been caught so much by the unobtrusive web programming and started to implement the "Event Delegation" pattern in the most common and raw way in Javascript. About mid 2007 this was working just well for most CSS2 selectors, but I wished a boost in performance and I wanted to have more CSS2 and newer CSS3 selector to be also available for event delegation. I asked for help to Peter Michaux. He patiently listened to my ideas, debated with me on that and provided me a first skeleton of compiled selectors.

Event Delegation applied to Javascript is the fastest and more scalable pattern for any type of Javascript application, from the smallest scriptlets to complex frameworks up to the biggest RIA applications. Web UI responsiveness can only be greatly improved if we can count on fast and stable events and delegates.

NWMatcher aims to be one of the building stones of this scenario and NWEvents is the door to event delegation using reliable events combined with fast and reliable selectors.

This is by no means the last word on this, my code can be improved both in syntax and speed, there are surely bugs still around that I will try to correct with help of testers.

Testing NWMatcher with and without caching

NWMatcher provides a way for the user to configure the state of it's internal caching system, ENABLED or DISABLED. Even if we tell NWMatcher to do caching, it will still do it's best to detect the DOM has changed by using Mutation Events. This is true on all browsers but IE, so the caching system is disabled by default on IE. You may enable it using setCache().

By default the cache is "enabled" on Firefox, Safari (Webkit bug #8191), Opera, Konqueror, this gives the best results in speed still being able to be notified and flush the cache when the document changes.

Important details on how to use it

NWMatcher has been written with compatibility in mind. To achieve that goal I avoided to use too many native methods, this also due to the many bugs that affect the standard DOM methods especially on Internet Explorer (ex: getElementById, getElementsByTagName).

The singleton provides only four usable methods. They are:


    // return boolean true/false
    NW.Dom.match(element, selector);

    // return array of elements
    NW.Dom.select(selector, from);

    // enable document cache, no return value
    NW.Dom.setCache(true, document);

    // flush document cache, no return value
    NW.Dom.expireCache(document);

Of the four methods, you would probably just need to use two, the "select()" and the "match()" methods, respectively for getting collections or just checking a single element.

The caching can be set programmatically by calling:


    // pass true to enable or false to disable
    NW.Dom.setCache(false, document);

The current cache can be forced to expire by calling:


    // no return value
    NW.Dom.expireCache(document);

Objectives for this code:

Tested compatibility

Some testing have been done on different browsers and platform OS (Linux/Mac/Windows) on phones and palm devices. I haven't found browsers failing completely yet, some have weak UNICODE support (Opera and Safari 2), I will keep the list updated with incoming info.

Older browsers

Newer browsers

Bugs ?

Yes there are. Well hidden though, couldn't find them all yet...Want to help ?

Credits

Peter Michaux Peter Blog - initial code template for compiled CSS selectors

Samuel Lebeau (Xilinus) - Prototype adapter, syntax suggestions and patches

E. Leith (LavaScript) - bug reports, suggestions and great debugging in his library

John-David Dalton (@jdalton) - several patches and the idea of including a sensitivity map

Ken D. Snyder (PUlp) - for including NWMatcher in his own PUlp framework project

Jeff Watkins (Apple Store) - for being the first to include NWMatcher in Coherent JS (Apple Store framework)


Diego Perini