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