Wednesday, February 20, 2008

jQuery.Listen 1.0 released

I updated jQuery.Listen and it got to it's first stable version. This release includes mostly features. A few optimizations and a couple of structural changes.
As specified in the change list, the licensing changed from GPL to GPL+MIT.

Optimizations

  • Reduced the code size, this release (with all its features) is smaller than the previous one.
  • Added many optimizations for minified code size.
  • Improved the cleaning done on window.onload to avoid memory leaks.

Fixes

  • The [].splice.call(arguments,..) wasn't working in my Opera.

Changes

  • $.listen is not used for stopping/restarting the indexers.
    use $(..).indexer(...).(start|stop)() instead.
  • Changed the licensing from GPL to GPL+MIT.

Features

  • Added Jörn Zaefferer's approach of focusin/focusout. You can now safely listen for blur and focus events.
  • Added $(..).indexer( event_name ) to get access to the indexers of the first matched element and $.indexer(..) to the global indexer.
  • $.listen.fixes is a hash that maps event/fixedEvent. If you add a fix at $.event.special, add it to this hash and it will work automatically.
  • It's possible to instruct indexers to emulate the natural bubbling like this: $(..).indexer( ... ).bubbles = true, use with discretion, will hit on perfomance.
  • Added support for multiple events separated with spaces.
Kudos to Jörn Zaefferer for lending me the code that now allows listening for focus and blur!

Links

Downloads

I really advice using the minified versions. The code is optimized to those releases. Source versions should only serve to learn.

13 comments:

veekter said...

Thanks for the release!

Now there are just 2 things I need:
1. Is there a way to cancel a keydown event, when a certain key is pressed. I tried returning false, but that didn't work.

2. I tried to listen to a mouseover on a tr, but it doesn't pick it up. This is what I did:
$("table.itemtable").listen('mouseover', '.itemline', function() {});
itemline is the class of the tr. Should I be doing it some other way?

Ariel Flesler said...

Hi veekter
You can call event.preventDefault(). event is the first argument received by the handlers. I should add support for return false toom I'll do soon.

As for 2, it should work, do you have it online? I'll try that locally as well.

Cheers

Ariel Flesler said...

@veekter
  Added a new release (1.0.2) where added the 'return false' feature.

Also modified the demo a bit and the selectors have classes, also tried class-only selectors and they worked well.

Check the demo and see if you find any difference.
One question, do your tables actually have a class 'itemtable' ?

Diego Perini said...

Ariel,
thank you to let me know that a jQuery.Listen plugin exists, I wasn't informed about it.

I only knew LiveQuery! but from what you describe your method may give better results.

You have come to know that selectors are the base for this to work also with some mouse events.

For this reason I suggest you also have a look at my selector engine:

NWMatcher Engine

which uses a "match()" method that does not need to traverse the DOM so the selector matching is extremely fast.

My framework agnostic "Event Manager" depend on it to be able to offer event delegates, here is a small example:

Delegation Example

I will give a look at your code a.t.p, and do some performance testing with simple selectors.

My question is, does your code still depend on an "onload" or similar ?

Ariel Flesler said...

Hi Diego
  I actually checked the NWEvents today, but in a hurry. I'll read it again in a minute.

As for the onload.. the answer is no.
The plugin can be used at any time, the only requirement (obviously) is that the listener is rendered.

That's why there's a "global" call(listener), that you use with $.listen specifying no element.
Then the document is used, this is safely accessible from the head of course.

I was really hoping to extend the selectors support. I'll only do it, if it doesn't mean to lose the present scalability (virtually 100%).

Cheers

Ariel Flesler said...

Diego
I checked NWMatcher. I firstly tried SlickSpeed( :P ) and the results are really impressing!
I needed a few minutes to find the source code(!).

Anyway, I checked the code, it's not easy to understand because of the one-letter-variables, but I get the idea, selector caching.
I'm intrigued by the snapshots you create, that seems interesting, I'll have to reread a few times.

Just a note: you emphasized that your .match() doesn't traverse the DOM.
Well, I don't think any framework does. At least jQuery's .is() only uses filtering, no DOM walking.

I really liked your code. Thanks.

Cheers Diego

Diego Perini said...

Ariel,
you are right, what I meant is that there are really a lot of calls and loops in the .is() method, no DOM walk really. But is still very slow, the worst being .merge() which checks for IE each time it is called.

I thought LiveQuery! was the only one doing such things in jQuery. Your .listen() method however have a different approach, you don't need an "onload" event either. Clever !!!

Within the limitations you were bound to work with, you surely have done a great job for jQuery. These are the kind of useful things needed in a library, probably the most important.

My objectives where to not depend on anything else but native javascript.

At he time I shifted from simple CSS to full CSS3 support mid last year I published NWEvents and NWMatcher on GoogleCode.

NWEvents was already working without CSS selectors by just comparing properties of the event target element with those supplied during the event registration enclosed in an object like this:

{
id: '#items',
className: 'header',
nodeName: 'div'
}

I don't know if these few lines are enough to explain what I mean, however I am currently hacking the example you sent me to give you feedback.

Notice that NWMatcher is optional, just if you want full CSS2/3 syntax to apply functionality to elements. NWMatcher has a user configurable caching system, but caching is only used for the "select()" method.

Sorry for being so short with variable names, I hope the extended comments and annotations I left in the source code can temporarily help mitigate my shortness of documentation :-)

Ariel Flesler said...

Hi Diego
It's ok, I understood the code. You know many compressors actually shrink vars' names right ? I always make source versions very verbose and I deeply optimize minified(production) versions.

Anyway, you surely missed jQuery.Intercept. I think that was my first published plugin for jQuery. It precedes jQuery.Listen. I realized it would be slow with many selectors, and inspired me to find a scalable technique.

Your early NWEvents version seems similar to Listen. Supporting ids/tags/classes. I'd love to extend the support... *sigh*

I suppose jQuery.Listen's problem is the lack of advertising, at the same time, LiveQuery is extremely popular and easy to use. I suppose this is not a plugin for everyone.

Well, please keep me informed of your testing and benchmarking.
Cheers

Diego Perini said...

That method in NWEvents just support whatever property you pass in to check, also custom properties not just id/tag/class.

Another difference is that I use the "document.documentElement" (the HTML node) instead of the "document", I thought this was better since it is one level less to reach, nobody uses it so it is traffic free and it is the only nodeType==1 that will be available since the start of javascript.-

But I would like to do more tests now that I have more choices to look at ;-)

Nitesh said...

Hi Ariel
Thanks a lot for making such a good plugin.
I have 2 questions:
1. What does indexer do?
2. Is there a way for me to chain event handlers, i.e., if i have assigned 3 handlers to a 'click' event, number 2 would run only if number 1 was true, and similarly 3 would run if 2 returned true.

Nitesh said...

Hi Ariel
Sorry, one more question

How do I delegate an event at the document or body level...?

Ariel Flesler said...

Hi nitesh

1. $.fn.indexer gives you access to the indexer object that is used. You don't usually need it.
You can use the method .stop() to unbind the handlers. I'll try to document it some more.

2. No, that's not possible with jQuery either. Instead, bind one single function, and do the logic inside that function.

3. $.listen() uses the document, you can also do $(document).listen() or $('body').listen().

Cheers

André said...

Hi Ariel, impressive wrk.

Seems there is an issue with Opera 10.53 though. Doesn't seem to trigger on class selectors.

For instance this WILL work,
$.listen('click', '#myID', function(e){
opera.postError('!')
})

However, this will not,
$.listen('click', 'a.myClass', function(e){
opera.postError('!')
})

Perhaps I'm missing something here?