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