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