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