Make it so that you can pass in event data to .click(), et. al. Fixes #6187.
[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                 if ( elem.removeEventListener ) {
529                         elem.removeEventListener( type, handle, false );
530                 }
531         } : 
532         function( elem, type, handle ) {
533                 if ( elem.detachEvent ) {
534                         elem.detachEvent( "on" + type, handle );
535                 }
536         };
537
538 jQuery.Event = function( src ) {
539         // Allow instantiation without the 'new' keyword
540         if ( !this.preventDefault ) {
541                 return new jQuery.Event( src );
542         }
543
544         // Event object
545         if ( src && src.type ) {
546                 this.originalEvent = src;
547                 this.type = src.type;
548         // Event type
549         } else {
550                 this.type = src;
551         }
552
553         // timeStamp is buggy for some events on Firefox(#3843)
554         // So we won't rely on the native value
555         this.timeStamp = now();
556
557         // Mark it as fixed
558         this[ expando ] = true;
559 };
560
561 function returnFalse() {
562         return false;
563 }
564 function returnTrue() {
565         return true;
566 }
567
568 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
569 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
570 jQuery.Event.prototype = {
571         preventDefault: function() {
572                 this.isDefaultPrevented = returnTrue;
573
574                 var e = this.originalEvent;
575                 if ( !e ) {
576                         return;
577                 }
578                 
579                 // if preventDefault exists run it on the original event
580                 if ( e.preventDefault ) {
581                         e.preventDefault();
582                 }
583                 // otherwise set the returnValue property of the original event to false (IE)
584                 e.returnValue = false;
585         },
586         stopPropagation: function() {
587                 this.isPropagationStopped = returnTrue;
588
589                 var e = this.originalEvent;
590                 if ( !e ) {
591                         return;
592                 }
593                 // if stopPropagation exists run it on the original event
594                 if ( e.stopPropagation ) {
595                         e.stopPropagation();
596                 }
597                 // otherwise set the cancelBubble property of the original event to true (IE)
598                 e.cancelBubble = true;
599         },
600         stopImmediatePropagation: function() {
601                 this.isImmediatePropagationStopped = returnTrue;
602                 this.stopPropagation();
603         },
604         isDefaultPrevented: returnFalse,
605         isPropagationStopped: returnFalse,
606         isImmediatePropagationStopped: returnFalse
607 };
608
609 // Checks if an event happened on an element within another element
610 // Used in jQuery.event.special.mouseenter and mouseleave handlers
611 var withinElement = function( event ) {
612         // Check if mouse(over|out) are still within the same parent element
613         var parent = event.relatedTarget;
614
615         // Firefox sometimes assigns relatedTarget a XUL element
616         // which we cannot access the parentNode property of
617         try {
618                 // Traverse up the tree
619                 while ( parent && parent !== this ) {
620                         parent = parent.parentNode;
621                 }
622
623                 if ( parent !== this ) {
624                         // set the correct event type
625                         event.type = event.data;
626
627                         // handle event if we actually just moused on to a non sub-element
628                         jQuery.event.handle.apply( this, arguments );
629                 }
630
631         // assuming we've left the element since we most likely mousedover a xul element
632         } catch(e) { }
633 },
634
635 // In case of event delegation, we only need to rename the event.type,
636 // liveHandler will take care of the rest.
637 delegate = function( event ) {
638         event.type = event.data;
639         jQuery.event.handle.apply( this, arguments );
640 };
641
642 // Create mouseenter and mouseleave events
643 jQuery.each({
644         mouseenter: "mouseover",
645         mouseleave: "mouseout"
646 }, function( orig, fix ) {
647         jQuery.event.special[ orig ] = {
648                 setup: function( data ) {
649                         jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
650                 },
651                 teardown: function( data ) {
652                         jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
653                 }
654         };
655 });
656
657 // submit delegation
658 if ( !jQuery.support.submitBubbles ) {
659
660         jQuery.event.special.submit = {
661                 setup: function( data, namespaces ) {
662                         if ( this.nodeName.toLowerCase() !== "form" ) {
663                                 jQuery.event.add(this, "click.specialSubmit", function( e ) {
664                                         var elem = e.target, type = elem.type;
665
666                                         if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
667                                                 return trigger( "submit", this, arguments );
668                                         }
669                                 });
670          
671                                 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
672                                         var elem = e.target, type = elem.type;
673
674                                         if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
675                                                 return trigger( "submit", this, arguments );
676                                         }
677                                 });
678
679                         } else {
680                                 return false;
681                         }
682                 },
683
684                 teardown: function( namespaces ) {
685                         jQuery.event.remove( this, ".specialSubmit" );
686                 }
687         };
688
689 }
690
691 // change delegation, happens here so we have bind.
692 if ( !jQuery.support.changeBubbles ) {
693
694         var formElems = /textarea|input|select/i,
695
696         changeFilters,
697
698         getVal = function( elem ) {
699                 var type = elem.type, val = elem.value;
700
701                 if ( type === "radio" || type === "checkbox" ) {
702                         val = elem.checked;
703
704                 } else if ( type === "select-multiple" ) {
705                         val = elem.selectedIndex > -1 ?
706                                 jQuery.map( elem.options, function( elem ) {
707                                         return elem.selected;
708                                 }).join("-") :
709                                 "";
710
711                 } else if ( elem.nodeName.toLowerCase() === "select" ) {
712                         val = elem.selectedIndex;
713                 }
714
715                 return val;
716         },
717
718         testChange = function testChange( e ) {
719                 var elem = e.target, data, val;
720
721                 if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
722                         return;
723                 }
724
725                 data = jQuery.data( elem, "_change_data" );
726                 val = getVal(elem);
727
728                 // the current data will be also retrieved by beforeactivate
729                 if ( e.type !== "focusout" || elem.type !== "radio" ) {
730                         jQuery.data( elem, "_change_data", val );
731                 }
732                 
733                 if ( data === undefined || val === data ) {
734                         return;
735                 }
736
737                 if ( data != null || val ) {
738                         e.type = "change";
739                         return jQuery.event.trigger( e, arguments[1], elem );
740                 }
741         };
742
743         jQuery.event.special.change = {
744                 filters: {
745                         focusout: testChange, 
746
747                         click: function( e ) {
748                                 var elem = e.target, type = elem.type;
749
750                                 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
751                                         return testChange.call( this, e );
752                                 }
753                         },
754
755                         // Change has to be called before submit
756                         // Keydown will be called before keypress, which is used in submit-event delegation
757                         keydown: function( e ) {
758                                 var elem = e.target, type = elem.type;
759
760                                 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
761                                         (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
762                                         type === "select-multiple" ) {
763                                         return testChange.call( this, e );
764                                 }
765                         },
766
767                         // Beforeactivate happens also before the previous element is blurred
768                         // with this event you can't trigger a change event, but you can store
769                         // information/focus[in] is not needed anymore
770                         beforeactivate: function( e ) {
771                                 var elem = e.target;
772                                 jQuery.data( elem, "_change_data", getVal(elem) );
773                         }
774                 },
775
776                 setup: function( data, namespaces ) {
777                         if ( this.type === "file" ) {
778                                 return false;
779                         }
780
781                         for ( var type in changeFilters ) {
782                                 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
783                         }
784
785                         return formElems.test( this.nodeName );
786                 },
787
788                 teardown: function( namespaces ) {
789                         jQuery.event.remove( this, ".specialChange" );
790
791                         return formElems.test( this.nodeName );
792                 }
793         };
794
795         changeFilters = jQuery.event.special.change.filters;
796 }
797
798 function trigger( type, elem, args ) {
799         args[0].type = type;
800         return jQuery.event.handle.apply( elem, args );
801 }
802
803 // Create "bubbling" focus and blur events
804 if ( document.addEventListener ) {
805         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
806                 jQuery.event.special[ fix ] = {
807                         setup: function() {
808                                 this.addEventListener( orig, handler, true );
809                         }, 
810                         teardown: function() { 
811                                 this.removeEventListener( orig, handler, true );
812                         }
813                 };
814
815                 function handler( e ) { 
816                         e = jQuery.event.fix( e );
817                         e.type = fix;
818                         return jQuery.event.handle.call( this, e );
819                 }
820         });
821 }
822
823 jQuery.each(["bind", "one"], function( i, name ) {
824         jQuery.fn[ name ] = function( type, data, fn ) {
825                 // Handle object literals
826                 if ( typeof type === "object" ) {
827                         for ( var key in type ) {
828                                 this[ name ](key, data, type[key], fn);
829                         }
830                         return this;
831                 }
832                 
833                 if ( jQuery.isFunction( data ) ) {
834                         fn = data;
835                         data = undefined;
836                 }
837
838                 var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
839                         jQuery( this ).unbind( event, handler );
840                         return fn.apply( this, arguments );
841                 }) : fn;
842
843                 if ( type === "unload" && name !== "one" ) {
844                         this.one( type, data, fn );
845
846                 } else {
847                         for ( var i = 0, l = this.length; i < l; i++ ) {
848                                 jQuery.event.add( this[i], type, handler, data );
849                         }
850                 }
851
852                 return this;
853         };
854 });
855
856 jQuery.fn.extend({
857         unbind: function( type, fn ) {
858                 // Handle object literals
859                 if ( typeof type === "object" && !type.preventDefault ) {
860                         for ( var key in type ) {
861                                 this.unbind(key, type[key]);
862                         }
863
864                 } else {
865                         for ( var i = 0, l = this.length; i < l; i++ ) {
866                                 jQuery.event.remove( this[i], type, fn );
867                         }
868                 }
869
870                 return this;
871         },
872         
873         delegate: function( selector, types, data, fn ) {
874                 return this.live( types, data, fn, selector );
875         },
876         
877         undelegate: function( selector, types, fn ) {
878                 if ( arguments.length === 0 ) {
879                                 return this.unbind( "live" );
880                 
881                 } else {
882                         return this.die( types, null, fn, selector );
883                 }
884         },
885         
886         trigger: function( type, data ) {
887                 return this.each(function() {
888                         jQuery.event.trigger( type, data, this );
889                 });
890         },
891
892         triggerHandler: function( type, data ) {
893                 if ( this[0] ) {
894                         var event = jQuery.Event( type );
895                         event.preventDefault();
896                         event.stopPropagation();
897                         jQuery.event.trigger( event, data, this[0] );
898                         return event.result;
899                 }
900         },
901
902         toggle: function( fn ) {
903                 // Save reference to arguments for access in closure
904                 var args = arguments, i = 1;
905
906                 // link all the functions, so any of them can unbind this click handler
907                 while ( i < args.length ) {
908                         jQuery.proxy( fn, args[ i++ ] );
909                 }
910
911                 return this.click( jQuery.proxy( fn, function( event ) {
912                         // Figure out which function to execute
913                         var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
914                         jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
915
916                         // Make sure that clicks stop
917                         event.preventDefault();
918
919                         // and execute the function
920                         return args[ lastToggle ].apply( this, arguments ) || false;
921                 }));
922         },
923
924         hover: function( fnOver, fnOut ) {
925                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
926         }
927 });
928
929 var liveMap = {
930         focus: "focusin",
931         blur: "focusout",
932         mouseenter: "mouseover",
933         mouseleave: "mouseout"
934 };
935
936 jQuery.each(["live", "die"], function( i, name ) {
937         jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
938                 var type, i = 0, match, namespaces, preType,
939                         selector = origSelector || this.selector,
940                         context = origSelector ? this : jQuery( this.context );
941
942                 if ( jQuery.isFunction( data ) ) {
943                         fn = data;
944                         data = undefined;
945                 }
946
947                 types = (types || "").split(" ");
948
949                 while ( (type = types[ i++ ]) != null ) {
950                         match = rnamespaces.exec( type );
951                         namespaces = "";
952
953                         if ( match )  {
954                                 namespaces = match[0];
955                                 type = type.replace( rnamespaces, "" );
956                         }
957
958                         if ( type === "hover" ) {
959                                 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
960                                 continue;
961                         }
962
963                         preType = type;
964
965                         if ( type === "focus" || type === "blur" ) {
966                                 types.push( liveMap[ type ] + namespaces );
967                                 type = type + namespaces;
968
969                         } else {
970                                 type = (liveMap[ type ] || type) + namespaces;
971                         }
972
973                         if ( name === "live" ) {
974                                 // bind live handler
975                                 context.each(function(){
976                                         jQuery.event.add( this, liveConvert( type, selector ),
977                                                 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
978                                 });
979
980                         } else {
981                                 // unbind live handler
982                                 context.unbind( liveConvert( type, selector ), fn );
983                         }
984                 }
985                 
986                 return this;
987         }
988 });
989
990 function liveHandler( event ) {
991         var stop, maxLevel, elems = [], selectors = [],
992                 related, match, handleObj, elem, j, i, l, data, close,
993                 events = jQuery.data( this, "events" );
994
995         // Make sure we avoid non-left-click bubbling in Firefox (#3861)
996         if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
997                 return;
998         }
999
1000         event.liveFired = this;
1001
1002         var live = events.live.slice(0);
1003
1004         for ( j = 0; j < live.length; j++ ) {
1005                 handleObj = live[j];
1006
1007                 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1008                         selectors.push( handleObj.selector );
1009
1010                 } else {
1011                         live.splice( j--, 1 );
1012                 }
1013         }
1014
1015         match = jQuery( event.target ).closest( selectors, event.currentTarget );
1016
1017         for ( i = 0, l = match.length; i < l; i++ ) {
1018                 close = match[i];
1019
1020                 for ( j = 0; j < live.length; j++ ) {
1021                         handleObj = live[j];
1022
1023                         if ( close.selector === handleObj.selector ) {
1024                                 elem = close.elem;
1025                                 related = null;
1026
1027                                 // Those two events require additional checking
1028                                 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1029                                         event.type = handleObj.preType;
1030                                         related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1031                                 }
1032
1033                                 if ( !related || related !== elem ) {
1034                                         elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1035                                 }
1036                         }
1037                 }
1038         }
1039
1040         for ( i = 0, l = elems.length; i < l; i++ ) {
1041                 match = elems[i];
1042
1043                 if ( maxLevel && match.level > maxLevel ) {
1044                         break;
1045                 }
1046
1047                 event.currentTarget = match.elem;
1048                 event.data = match.handleObj.data;
1049                 event.handleObj = match.handleObj;
1050
1051                 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1052
1053                 if ( ret === false || event.isPropagationStopped() ) {
1054                         maxLevel = match.level;
1055
1056                         if ( ret === false ) {
1057                                 stop = false;
1058                         }
1059                 }
1060         }
1061
1062         return stop;
1063 }
1064
1065 function liveConvert( type, selector ) {
1066         return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
1067 }
1068
1069 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1070         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1071         "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1072
1073         // Handle event binding
1074         jQuery.fn[ name ] = function( data, fn ) {
1075                 return data || fn ?
1076                         this.bind( name, fn ? data : null, fn || data ) :
1077                         this.trigger( name );
1078         };
1079
1080         if ( jQuery.attrFn ) {
1081                 jQuery.attrFn[ name ] = true;
1082         }
1083 });
1084
1085 // Prevent memory leaks in IE
1086 // Window isn't included so as not to unbind existing unload events
1087 // More info:
1088 //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
1089 if ( window.attachEvent && !window.addEventListener ) {
1090         window.attachEvent("onunload", function() {
1091                 for ( var id in jQuery.cache ) {
1092                         if ( jQuery.cache[ id ].handle ) {
1093                                 // Try/Catch is to handle iframes being unloaded, see #4280
1094                                 try {
1095                                         jQuery.event.remove( jQuery.cache[ id ].handle.elem );
1096                                 } catch(e) {}
1097                         }
1098                 }
1099         });
1100 }