Further optimize the empty/remove/cleanData logic.
[jquery.git] / src / event.js
1 var fcleanup = function( nm ) {
2         return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
3                 return "\\" + ch;
4         });
5 };
6
7 /*
8  * A number of helper functions used for managing events.
9  * Many of the ideas behind this code originated from
10  * Dean Edwards' addEvent library.
11  */
12 jQuery.event = {
13
14         // Bind an event to an element
15         // Original by Dean Edwards
16         add: function( elem, types, handler, data ) {
17                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
18                         return;
19                 }
20
21                 // For whatever reason, IE has trouble passing the window object
22                 // around, causing it to be cloned in the process
23                 if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
24                         elem = window;
25                 }
26
27                 // Make sure that the function being executed has a unique ID
28                 if ( !handler.guid ) {
29                         handler.guid = jQuery.guid++;
30                 }
31
32                 // if data is passed, bind to handler
33                 if ( data !== undefined ) {
34                         // Create temporary function pointer to original handler
35                         var fn = handler;
36
37                         // Create unique handler function, wrapped around original handler
38                         handler = jQuery.proxy( fn );
39
40                         // Store data in unique handler
41                         handler.data = data;
42                 }
43
44                 // Init the element's event structure
45                 var elemData = jQuery.data( elem );
46
47                 // If no elemData is found then we must be trying to bind to one of the
48                 // banned noData elements
49                 if ( !elemData ) {
50                         return;
51                 }
52
53                 var events = elemData.events || (elemData.events = {}),
54                         handle = elemData.handle, eventHandle;
55
56                 if ( !handle ) {
57                         eventHandle = function() {
58                                 // Handle the second event of a trigger and when
59                                 // an event is called after a page has unloaded
60                                 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
61                                         jQuery.event.handle.apply( eventHandle.elem, arguments ) :
62                                         undefined;
63                         };
64
65                         handle = elemData.handle = eventHandle;
66                 }
67
68                 // Add elem as a property of the handle function
69                 // This is to prevent a memory leak with non-native
70                 // event in IE.
71                 handle.elem = elem;
72
73                 // Handle multiple events separated by a space
74                 // jQuery(...).bind("mouseover mouseout", fn);
75                 types = types.split(" ");
76
77                 var type, i = 0, namespaces;
78
79                 while ( (type = types[ i++ ]) ) {
80                         if ( i > 1 ) {
81                                 handler = jQuery.proxy( handler );
82
83                                 if ( data !== undefined ) {
84                                         handler.data = data;
85                                 }
86                         }
87
88                         // Namespaced event handlers
89                         if ( type.indexOf(".") > -1 ) {
90                                 namespaces = type.split(".");
91                                 type = namespaces.shift();
92                                 handler.type = namespaces.slice(0).sort().join(".");
93
94                         } else {
95                                 namespaces = [];
96                                 handler.type = "";
97                         }
98
99                         // Get the current list of functions bound to this event
100                         var handlers = events[ type ],
101                                 special = this.special[ type ] || {};
102
103                         // Init the event handler queue
104                         if ( !handlers ) {
105                                 handlers = events[ type ] = {};
106
107                                 // Check for a special event handler
108                                 // Only use addEventListener/attachEvent if the special
109                                 // events handler returns false
110                                 if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
111                                         // Bind the global event handler to the element
112                                         if ( elem.addEventListener ) {
113                                                 elem.addEventListener( type, handle, false );
114
115                                         } else if ( elem.attachEvent ) {
116                                                 elem.attachEvent( "on" + type, handle );
117                                         }
118                                 }
119                         }
120                         
121                         if ( special.add ) { 
122                                 var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers ); 
123                                 if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) { 
124                                         modifiedHandler.guid = modifiedHandler.guid || handler.guid; 
125                                         modifiedHandler.data = modifiedHandler.data || handler.data; 
126                                         modifiedHandler.type = modifiedHandler.type || handler.type; 
127                                         handler = modifiedHandler; 
128                                 } 
129                         } 
130                         
131                         // Add the function to the element's handler list
132                         handlers[ handler.guid ] = handler;
133
134                         // Keep track of which events have been used, for global triggering
135                         this.global[ type ] = true;
136                 }
137
138                 // Nullify elem to prevent memory leaks in IE
139                 elem = null;
140         },
141
142         global: {},
143
144         // Detach an event or set of events from an element
145         remove: function( elem, types, handler ) {
146                 // don't do events on text and comment nodes
147                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
148                         return;
149                 }
150
151                 var elemData = jQuery.data( elem );
152
153                 if ( !elemData ) {
154                         return;
155                 }
156
157                 var events = elemData.events, ret, type, fn;
158
159                 if ( events ) {
160                         // Unbind all events for the element
161                         if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
162                                 for ( type in events ) {
163                                         this.remove( elem, type + (types || "") );
164                                 }
165
166                         } else {
167                                 // types is actually an event object here
168                                 if ( types.type ) {
169                                         handler = types.handler;
170                                         types = types.type;
171                                 }
172
173                                 // Handle multiple events separated by a space
174                                 // jQuery(...).unbind("mouseover mouseout", fn);
175                                 types = types.split(" ");
176
177                                 var i = 0, all, namespaces, namespace;
178
179                                 while ( (type = types[ i++ ]) ) {
180                                         all = type.indexOf(".") < 0;
181                                         namespaces = null;
182
183                                         if ( !all ) {
184                                                 // Namespaced event handlers
185                                                 namespaces = type.split(".");
186                                                 type = namespaces.shift();
187
188                                                 namespace = new RegExp("(^|\\.)" + 
189                                                         jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)")
190
191                                         } else {
192                                                 namespaces = [];
193                                         }
194
195                                         var special = this.special[ type ] || {};
196
197                                         if ( events[ type ] ) {
198                                                 // remove the given handler for the given type
199                                                 if ( handler ) {
200                                                         fn = events[ type ][ handler.guid ];
201                                                         delete events[ type ][ handler.guid ];
202
203                                                 // remove all handlers for the given type
204                                                 } else {
205                                                         for ( var handle in events[ type ] ) {
206                                                                 // Handle the removal of namespaced events
207                                                                 if ( all || namespace.test( events[ type ][ handle ].type ) ) {
208                                                                         delete events[ type ][ handle ];
209                                                                 }
210                                                         }
211                                                 }
212
213                                                 if ( special.remove ) {
214                                                         special.remove.call( elem, namespaces, fn);
215                                                 }
216
217                                                 // remove generic event handler if no more handlers exist
218                                                 for ( ret in events[ type ] ) {
219                                                         break;
220                                                 }
221
222                                                 if ( !ret ) {
223                                                         if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
224                                                                 removeEvent( elem, type, elemData.handle );
225                                                         }
226
227                                                         ret = null;
228                                                         delete events[ type ];
229                                                 }
230                                         }
231                                 }
232                         }
233
234                         // Remove the expando if it's no longer used
235                         for ( ret in events ) {
236                                 break;
237                         }
238
239                         if ( !ret ) {
240                                 var handle = elemData.handle;
241                                 if ( handle ) {
242                                         handle.elem = null;
243                                 }
244
245                                 delete elemData.events;
246                                 delete elemData.handle;
247
248                                 if ( jQuery.isEmptyObject( elemData ) ) {
249                                         jQuery.removeData( elem );
250                                 }
251                         }
252                 }
253         },
254
255         // bubbling is internal
256         trigger: function( event, data, elem /*, bubbling */ ) {
257                 // Event object or event type
258                 var type = event.type || event,
259                         bubbling = arguments[3];
260
261                 if ( !bubbling ) {
262                         event = typeof event === "object" ?
263                                 // jQuery.Event object
264                                 event[expando] ? event :
265                                 // Object literal
266                                 jQuery.extend( jQuery.Event(type), event ) :
267                                 // Just the event type (string)
268                                 jQuery.Event(type);
269
270                         if ( type.indexOf("!") >= 0 ) {
271                                 event.type = type = type.slice(0, -1);
272                                 event.exclusive = true;
273                         }
274
275                         // Handle a global trigger
276                         if ( !elem ) {
277                                 // Don't bubble custom events when global (to avoid too much overhead)
278                                 event.stopPropagation();
279
280                                 // Only trigger if we've ever bound an event for it
281                                 if ( this.global[ type ] ) {
282                                         jQuery.each( jQuery.cache, function() {
283                                                 if ( this.events && this.events[type] ) {
284                                                         jQuery.event.trigger( event, data, this.handle.elem );
285                                                 }
286                                         });
287                                 }
288                         }
289
290                         // Handle triggering a single element
291
292                         // don't do events on text and comment nodes
293                         if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
294                                 return undefined;
295                         }
296
297                         // Clean up in case it is reused
298                         event.result = undefined;
299                         event.target = elem;
300
301                         // Clone the incoming data, if any
302                         data = jQuery.makeArray( data );
303                         data.unshift( event );
304                 }
305
306                 event.currentTarget = elem;
307
308                 // Trigger the event, it is assumed that "handle" is a function
309                 var handle = jQuery.data( elem, "handle" );
310                 if ( handle ) {
311                         handle.apply( elem, data );
312                 }
313
314                 var parent = elem.parentNode || elem.ownerDocument;
315
316                 // Trigger an inline bound script
317                 try {
318                         if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
319                                 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
320                                         event.result = false;
321                                 }
322                         }
323
324                 // prevent IE from throwing an error for some elements with some event types, see #3533
325                 } catch (e) {}
326
327                 if ( !event.isPropagationStopped() && parent ) {
328                         jQuery.event.trigger( event, data, parent, true );
329
330                 } else if ( !event.isDefaultPrevented() ) {
331                         var target = event.target, old,
332                                 isClick = jQuery.nodeName(target, "a") && type === "click",
333                                 special = jQuery.event.special[ type ] || {};
334
335                         if ( (!special._default || special._default.call( elem, event ) === false) && 
336                                 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
337
338                                 try {
339                                         if ( target[ type ] ) {
340                                                 // Make sure that we don't accidentally re-trigger the onFOO events
341                                                 old = target[ "on" + type ];
342
343                                                 if ( old ) {
344                                                         target[ "on" + type ] = null;
345                                                 }
346
347                                                 this.triggered = true;
348                                                 target[ type ]();
349                                         }
350
351                                 // prevent IE from throwing an error for some elements with some event types, see #3533
352                                 } catch (e) {}
353
354                                 if ( old ) {
355                                         target[ "on" + type ] = old;
356                                 }
357
358                                 this.triggered = false;
359                         }
360                 }
361         },
362
363         handle: function( event ) {
364                 // returned undefined or false
365                 var all, handlers;
366
367                 event = arguments[0] = jQuery.event.fix( event || window.event );
368                 event.currentTarget = this;
369
370                 // Namespaced event handlers
371                 var namespaces = event.type.split(".");
372                 event.type = namespaces.shift();
373
374                 // Cache this now, all = true means, any handler
375                 all = !namespaces.length && !event.exclusive;
376
377                 var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
378
379                 handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
380
381                 for ( var j in handlers ) {
382                         var handler = handlers[ j ];
383
384                         // Filter the functions by class
385                         if ( all || namespace.test(handler.type) ) {
386                                 // Pass in a reference to the handler function itself
387                                 // So that we can later remove it
388                                 event.handler = handler;
389                                 event.data = handler.data;
390
391                                 var ret = handler.apply( this, arguments );
392
393                                 if ( ret !== undefined ) {
394                                         event.result = ret;
395                                         if ( ret === false ) {
396                                                 event.preventDefault();
397                                                 event.stopPropagation();
398                                         }
399                                 }
400
401                                 if ( event.isImmediatePropagationStopped() ) {
402                                         break;
403                                 }
404
405                         }
406                 }
407
408                 return event.result;
409         },
410
411         props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
412
413         fix: function( event ) {
414                 if ( event[ expando ] ) {
415                         return event;
416                 }
417
418                 // store a copy of the original event object
419                 // and "clone" to set read-only properties
420                 var originalEvent = event;
421                 event = jQuery.Event( originalEvent );
422
423                 for ( var i = this.props.length, prop; i; ) {
424                         prop = this.props[ --i ];
425                         event[ prop ] = originalEvent[ prop ];
426                 }
427
428                 // Fix target property, if necessary
429                 if ( !event.target ) {
430                         event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
431                 }
432
433                 // check if target is a textnode (safari)
434                 if ( event.target.nodeType === 3 ) {
435                         event.target = event.target.parentNode;
436                 }
437
438                 // Add relatedTarget, if necessary
439                 if ( !event.relatedTarget && event.fromElement ) {
440                         event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
441                 }
442
443                 // Calculate pageX/Y if missing and clientX/Y available
444                 if ( event.pageX == null && event.clientX != null ) {
445                         var doc = document.documentElement, body = document.body;
446                         event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
447                         event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
448                 }
449
450                 // Add which for key events
451                 if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
452                         event.which = event.charCode || event.keyCode;
453                 }
454
455                 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
456                 if ( !event.metaKey && event.ctrlKey ) {
457                         event.metaKey = event.ctrlKey;
458                 }
459
460                 // Add which for click: 1 === left; 2 === middle; 3 === right
461                 // Note: button is not normalized, so don't use it
462                 if ( !event.which && event.button !== undefined ) {
463                         event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
464                 }
465
466                 return event;
467         },
468
469         // Deprecated, use jQuery.guid instead
470         guid: 1E8,
471
472         // Deprecated, use jQuery.proxy instead
473         proxy: jQuery.proxy,
474
475         special: {
476                 ready: {
477                         // Make sure the ready event is setup
478                         setup: jQuery.bindReady,
479                         teardown: jQuery.noop
480                 },
481
482                 live: {
483                         add: function( proxy, data, namespaces, live ) {
484                                 jQuery.extend( proxy, data || {} );
485
486                                 proxy.guid += data.selector + data.live; 
487                                 data.liveProxy = proxy;
488
489                                 jQuery.event.add( this, data.live, liveHandler, data ); 
490                                 
491                         },
492
493                         remove: function( namespaces ) {
494                                 if ( namespaces.length ) {
495                                         var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
496
497                                         jQuery.each( (jQuery.data(this, "events").live || {}), function() {
498                                                 if ( name.test(this.type) ) {
499                                                         remove++;
500                                                 }
501                                         });
502
503                                         if ( remove < 1 ) {
504                                                 jQuery.event.remove( this, namespaces[0], liveHandler );
505                                         }
506                                 }
507                         },
508                         special: {}
509                 },
510                 beforeunload: {
511                         setup: function( data, namespaces, fn ) {
512                                 // We only want to do this special case on windows
513                                 if ( this.setInterval ) {
514                                         this.onbeforeunload = fn;
515                                 }
516
517                                 return false;
518                         },
519                         teardown: function( namespaces, fn ) {
520                                 if ( this.onbeforeunload === fn ) {
521                                         this.onbeforeunload = null;
522                                 }
523                         }
524                 }
525         }
526 };
527
528 var removeEvent = document.removeEventListener ?
529         function( elem, type, handle ) {
530                 elem.removeEventListener( type, handle, false );
531         } : 
532         function( elem, type, handle ) {
533                 elem.detachEvent( "on" + type, handle );
534         };
535
536 jQuery.Event = function( src ) {
537         // Allow instantiation without the 'new' keyword
538         if ( !this.preventDefault ) {
539                 return new jQuery.Event( src );
540         }
541
542         // Event object
543         if ( src && src.type ) {
544                 this.originalEvent = src;
545                 this.type = src.type;
546         // Event type
547         } else {
548                 this.type = src;
549         }
550
551         // timeStamp is buggy for some events on Firefox(#3843)
552         // So we won't rely on the native value
553         this.timeStamp = now();
554
555         // Mark it as fixed
556         this[ expando ] = true;
557 };
558
559 function returnFalse() {
560         return false;
561 }
562 function returnTrue() {
563         return true;
564 }
565
566 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
567 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
568 jQuery.Event.prototype = {
569         preventDefault: function() {
570                 this.isDefaultPrevented = returnTrue;
571
572                 var e = this.originalEvent;
573                 if ( !e ) {
574                         return;
575                 }
576                 
577                 // if preventDefault exists run it on the original event
578                 if ( e.preventDefault ) {
579                         e.preventDefault();
580                 }
581                 // otherwise set the returnValue property of the original event to false (IE)
582                 e.returnValue = false;
583         },
584         stopPropagation: function() {
585                 this.isPropagationStopped = returnTrue;
586
587                 var e = this.originalEvent;
588                 if ( !e ) {
589                         return;
590                 }
591                 // if stopPropagation exists run it on the original event
592                 if ( e.stopPropagation ) {
593                         e.stopPropagation();
594                 }
595                 // otherwise set the cancelBubble property of the original event to true (IE)
596                 e.cancelBubble = true;
597         },
598         stopImmediatePropagation: function() {
599                 this.isImmediatePropagationStopped = returnTrue;
600                 this.stopPropagation();
601         },
602         isDefaultPrevented: returnFalse,
603         isPropagationStopped: returnFalse,
604         isImmediatePropagationStopped: returnFalse
605 };
606
607 // Checks if an event happened on an element within another element
608 // Used in jQuery.event.special.mouseenter and mouseleave handlers
609 var withinElement = function( event ) {
610         // Check if mouse(over|out) are still within the same parent element
611         var parent = event.relatedTarget;
612
613         // Traverse up the tree
614         while ( parent && parent !== this ) {
615                 // Firefox sometimes assigns relatedTarget a XUL element
616                 // which we cannot access the parentNode property of
617                 try {
618                         parent = parent.parentNode;
619
620                 // assuming we've left the element since we most likely mousedover a xul element
621                 } catch(e) {
622                         break;
623                 }
624         }
625
626         if ( parent !== this ) {
627                 // set the correct event type
628                 event.type = event.data;
629
630                 // handle event if we actually just moused on to a non sub-element
631                 jQuery.event.handle.apply( this, arguments );
632         }
633
634 },
635
636 // In case of event delegation, we only need to rename the event.type,
637 // liveHandler will take care of the rest.
638 delegate = function( event ) {
639         event.type = event.data;
640         jQuery.event.handle.apply( this, arguments );
641 };
642
643 // Create mouseenter and mouseleave events
644 jQuery.each({
645         mouseenter: "mouseover",
646         mouseleave: "mouseout"
647 }, function( orig, fix ) {
648         jQuery.event.special[ orig ] = {
649                 setup: function( data ) {
650                         jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
651                 },
652                 teardown: function( data ) {
653                         jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
654                 }
655         };
656 });
657
658 // submit delegation
659 if ( !jQuery.support.submitBubbles ) {
660
661 jQuery.event.special.submit = {
662         setup: function( data, namespaces, fn ) {
663                 if ( this.nodeName.toLowerCase() !== "form" ) {
664                         jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
665                                 var elem = e.target, type = elem.type;
666
667                                 if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
668                                         return trigger( "submit", this, arguments );
669                                 }
670                         });
671          
672                         jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
673                                 var elem = e.target, type = elem.type;
674
675                                 if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
676                                         return trigger( "submit", this, arguments );
677                                 }
678                         });
679
680                 } else {
681                         return false;
682                 }
683         },
684
685         remove: function( namespaces, fn ) {
686                 jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
687                 jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
688         }
689 };
690
691 }
692
693 // change delegation, happens here so we have bind.
694 if ( !jQuery.support.changeBubbles ) {
695
696 var formElems = /textarea|input|select/i;
697
698 function getVal( elem ) {
699         var type = elem.type, val = elem.value;
700
701         if ( type === "radio" || type === "checkbox" ) {
702                 val = elem.checked;
703
704         } else if ( type === "select-multiple" ) {
705                 val = elem.selectedIndex > -1 ?
706                         jQuery.map( elem.options, function( elem ) {
707                                 return elem.selected;
708                         }).join("-") :
709                         "";
710
711         } else if ( elem.nodeName.toLowerCase() === "select" ) {
712                 val = elem.selectedIndex;
713         }
714
715         return val;
716 }
717
718 function testChange( e ) {
719                 var elem = e.target, data, val;
720
721                 if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
722                         return;
723                 }
724
725                 data = jQuery.data( elem, "_change_data" );
726                 val = getVal(elem);
727
728                 // the current data will be also retrieved by beforeactivate
729                 if ( e.type !== "focusout" || elem.type !== "radio" ) {
730                         jQuery.data( elem, "_change_data", val );
731                 }
732                 
733                 if ( data === undefined || val === data ) {
734                         return;
735                 }
736
737                 if ( data != null || val ) {
738                         e.type = "change";
739                         return jQuery.event.trigger( e, arguments[1], elem );
740                 }
741 }
742
743 jQuery.event.special.change = {
744         filters: {
745                 focusout: testChange, 
746
747                 click: function( e ) {
748                         var elem = e.target, type = elem.type;
749
750                         if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
751                                 return testChange.call( this, e );
752                         }
753                 },
754
755                 // Change has to be called before submit
756                 // Keydown will be called before keypress, which is used in submit-event delegation
757                 keydown: function( e ) {
758                         var elem = e.target, type = elem.type;
759
760                         if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
761                                 (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
762                                 type === "select-multiple" ) {
763                                 return testChange.call( this, e );
764                         }
765                 },
766
767                 // Beforeactivate happens also before the previous element is blurred
768                 // with this event you can't trigger a change event, but you can store
769                 // information/focus[in] is not needed anymore
770                 beforeactivate: function( e ) {
771                         var elem = e.target;
772                         jQuery.data( elem, "_change_data", getVal(elem) );
773                 }
774         },
775         setup: function( data, namespaces, fn ) {
776                 for ( var type in changeFilters ) {
777                         jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
778                 }
779
780                 return formElems.test( this.nodeName );
781         },
782         remove: function( namespaces, fn ) {
783                 for ( var type in changeFilters ) {
784                         jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
785                 }
786
787                 return formElems.test( this.nodeName );
788         }
789 };
790
791 var changeFilters = jQuery.event.special.change.filters;
792
793 }
794
795 function trigger( type, elem, args ) {
796         args[0].type = type;
797         return jQuery.event.handle.apply( elem, args );
798 }
799
800 // Create "bubbling" focus and blur events
801 if ( document.addEventListener ) {
802         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
803                 jQuery.event.special[ fix ] = {
804                         setup: function() {
805                                 this.addEventListener( orig, handler, true );
806                         }, 
807                         teardown: function() { 
808                                 this.removeEventListener( orig, handler, true );
809                         }
810                 };
811
812                 function handler( e ) { 
813                         e = jQuery.event.fix( e );
814                         e.type = fix;
815                         return jQuery.event.handle.call( this, e );
816                 }
817         });
818 }
819
820 jQuery.each(["bind", "one"], function( i, name ) {
821         jQuery.fn[ name ] = function( type, data, fn ) {
822                 // Handle object literals
823                 if ( typeof type === "object" ) {
824                         for ( var key in type ) {
825                                 this[ name ](key, data, type[key], fn);
826                         }
827                         return this;
828                 }
829                 
830                 if ( jQuery.isFunction( data ) ) {
831                         fn = data;
832                         data = undefined;
833                 }
834
835                 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
836                         jQuery( this ).unbind( event, handler );
837                         return fn.apply( this, arguments );
838                 }) : fn;
839
840                 if ( type === "unload" && name !== "one" ) {
841                         this.one( type, data, fn );
842
843                 } else {
844                         for ( var i = 0, l = this.length; i < l; i++ ) {
845                                 jQuery.event.add( this[i], type, handler, data );
846                         }
847                 }
848
849                 return this;
850         };
851 });
852
853 jQuery.fn.extend({
854         unbind: function( type, fn ) {
855                 // Handle object literals
856                 if ( typeof type === "object" && !type.preventDefault ) {
857                         for ( var key in type ) {
858                                 this.unbind(key, type[key]);
859                         }
860
861                 } else {
862                         for ( var i = 0, l = this.length; i < l; i++ ) {
863                                 jQuery.event.remove( this[i], type, fn );
864                         }
865                 }
866
867                 return this;
868         },
869         trigger: function( type, data ) {
870                 return this.each(function() {
871                         jQuery.event.trigger( type, data, this );
872                 });
873         },
874
875         triggerHandler: function( type, data ) {
876                 if ( this[0] ) {
877                         var event = jQuery.Event( type );
878                         event.preventDefault();
879                         event.stopPropagation();
880                         jQuery.event.trigger( event, data, this[0] );
881                         return event.result;
882                 }
883         },
884
885         toggle: function( fn ) {
886                 // Save reference to arguments for access in closure
887                 var args = arguments, i = 1;
888
889                 // link all the functions, so any of them can unbind this click handler
890                 while ( i < args.length ) {
891                         jQuery.proxy( fn, args[ i++ ] );
892                 }
893
894                 return this.click( jQuery.proxy( fn, function( event ) {
895                         // Figure out which function to execute
896                         var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
897                         jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
898
899                         // Make sure that clicks stop
900                         event.preventDefault();
901
902                         // and execute the function
903                         return args[ lastToggle ].apply( this, arguments ) || false;
904                 }));
905         },
906
907         hover: function( fnOver, fnOut ) {
908                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
909         }
910 });
911
912 jQuery.each(["live", "die"], function( i, name ) {
913         jQuery.fn[ name ] = function( types, data, fn ) {
914                 var type, i = 0;
915
916                 if ( jQuery.isFunction( data ) ) {
917                         fn = data;
918                         data = undefined;
919                 }
920
921                 types = (types || "").split( /\s+/ );
922
923                 while ( (type = types[ i++ ]) != null ) {
924                         type = type === "focus" ? "focusin" : // focus --> focusin
925                                         type === "blur" ? "focusout" : // blur --> focusout
926                                         type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support
927                                         type;
928                         
929                         if ( name === "live" ) {
930                                 // bind live handler
931                                 jQuery( this.context ).bind( liveConvert( type, this.selector ), {
932                                         data: data, selector: this.selector, live: type
933                                 }, fn );
934
935                         } else {
936                                 // unbind live handler
937                                 jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
938                         }
939                 }
940                 
941                 return this;
942         }
943 });
944
945 function liveHandler( event ) {
946         var stop, elems = [], selectors = [], args = arguments,
947                 related, match, fn, elem, j, i, l, data,
948                 live = jQuery.extend({}, jQuery.data( this, "events" ).live);
949
950         // Make sure we avoid non-left-click bubbling in Firefox (#3861)
951         if ( event.button && event.type === "click" ) {
952                 return;
953         }
954
955         for ( j in live ) {
956                 fn = live[j];
957                 if ( fn.live === event.type ||
958                                 fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
959
960                         data = fn.data;
961                         if ( !(data.beforeFilter && data.beforeFilter[event.type] && 
962                                         !data.beforeFilter[event.type](event)) ) {
963                                 selectors.push( fn.selector );
964                         }
965                 } else {
966                         delete live[j];
967                 }
968         }
969
970         match = jQuery( event.target ).closest( selectors, event.currentTarget );
971
972         for ( i = 0, l = match.length; i < l; i++ ) {
973                 for ( j in live ) {
974                         fn = live[j];
975                         elem = match[i].elem;
976                         related = null;
977
978                         if ( match[i].selector === fn.selector ) {
979                                 // Those two events require additional checking
980                                 if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
981                                         related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
982                                 }
983
984                                 if ( !related || related !== elem ) {
985                                         elems.push({ elem: elem, fn: fn });
986                                 }
987                         }
988                 }
989         }
990
991         for ( i = 0, l = elems.length; i < l; i++ ) {
992                 match = elems[i];
993                 event.currentTarget = match.elem;
994                 event.data = match.fn.data;
995                 if ( match.fn.apply( match.elem, args ) === false ) {
996                         stop = false;
997                         break;
998                 }
999         }
1000
1001         return stop;
1002 }
1003
1004 function liveConvert( type, selector ) {
1005         return "live." + (type ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
1006 }
1007
1008 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1009         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1010         "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1011
1012         // Handle event binding
1013         jQuery.fn[ name ] = function( fn ) {
1014                 return fn ? this.bind( name, fn ) : this.trigger( name );
1015         };
1016
1017         if ( jQuery.attrFn ) {
1018                 jQuery.attrFn[ name ] = true;
1019         }
1020 });
1021
1022 // Prevent memory leaks in IE
1023 // Window isn't included so as not to unbind existing unload events
1024 // More info:
1025 //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1026 if ( window.attachEvent && !window.addEventListener ) {
1027         window.attachEvent("onunload", function() {
1028                 for ( var id in jQuery.cache ) {
1029                         if ( jQuery.cache[ id ].handle ) {
1030                                 // Try/Catch is to handle iframes being unloaded, see #4280
1031                                 try {
1032                                         jQuery.event.remove( jQuery.cache[ id ].handle.elem );
1033                                 } catch(e) {}
1034                         }
1035                 }
1036         });
1037 }