Set background to none on our mock body and remove its contents to avoid a crash...
[jquery.git] / src / event.js
blob05e79d3583761cda0f5d5da01463accb35051659
1 (function( jQuery ) {
3 var hasOwn = Object.prototype.hasOwnProperty,
4         rnamespaces = /\.(.*)$/,
5         rformElems = /^(?:textarea|input|select)$/i,
6         rperiod = /\./g,
7         rspaces = / /g,
8         rescape = /[^\w\s.|`]/g,
9         fcleanup = function( nm ) {
10                 return nm.replace(rescape, "\\$&");
11         };
14  * A number of helper functions used for managing events.
15  * Many of the ideas behind this code originated from
16  * Dean Edwards' addEvent library.
17  */
18 jQuery.event = {
20         // Bind an event to an element
21         // Original by Dean Edwards
22         add: function( elem, types, handler, data ) {
23                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
24                         return;
25                 }
27                 if ( handler === false ) {
28                         handler = returnFalse;
29                 } else if ( !handler ) {
30                         // Fixes bug #7229. Fix recommended by jdalton
31                         return;
32                 }
34                 var handleObjIn, handleObj;
36                 if ( handler.handler ) {
37                         handleObjIn = handler;
38                         handler = handleObjIn.handler;
39                 }
41                 // Make sure that the function being executed has a unique ID
42                 if ( !handler.guid ) {
43                         handler.guid = jQuery.guid++;
44                 }
46                 // Init the element's event structure
47                 var elemData = jQuery._data( elem );
49                 // If no elemData is found then we must be trying to bind to one of the
50                 // banned noData elements
51                 if ( !elemData ) {
52                         return;
53                 }
55                 var events = elemData.events,
56                         eventHandle = elemData.handle;
58                 if ( !events ) {
59                         elemData.events = events = {};
60                 }
62                 if ( !eventHandle ) {
63                         elemData.handle = eventHandle = function( e ) {
64                                 // Discard the second event of a jQuery.event.trigger() and
65                                 // when an event is called after a page has unloaded
66                                 return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
67                                         jQuery.event.handle.apply( eventHandle.elem, arguments ) :
68                                         undefined;
69                         };
70                 }
72                 // Add elem as a property of the handle function
73                 // This is to prevent a memory leak with non-native events in IE.
74                 eventHandle.elem = elem;
76                 // Handle multiple events separated by a space
77                 // jQuery(...).bind("mouseover mouseout", fn);
78                 types = types.split(" ");
80                 var type, i = 0, namespaces;
82                 while ( (type = types[ i++ ]) ) {
83                         handleObj = handleObjIn ?
84                                 jQuery.extend({}, handleObjIn) :
85                                 { handler: handler, data: data };
87                         // Namespaced event handlers
88                         if ( type.indexOf(".") > -1 ) {
89                                 namespaces = type.split(".");
90                                 type = namespaces.shift();
91                                 handleObj.namespace = namespaces.slice(0).sort().join(".");
93                         } else {
94                                 namespaces = [];
95                                 handleObj.namespace = "";
96                         }
98                         handleObj.type = type;
99                         if ( !handleObj.guid ) {
100                                 handleObj.guid = handler.guid;
101                         }
103                         // Get the current list of functions bound to this event
104                         var handlers = events[ type ],
105                                 special = jQuery.event.special[ type ] || {};
107                         // Init the event handler queue
108                         if ( !handlers ) {
109                                 handlers = events[ type ] = [];
111                                 // Check for a special event handler
112                                 // Only use addEventListener/attachEvent if the special
113                                 // events handler returns false
114                                 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
115                                         // Bind the global event handler to the element
116                                         if ( elem.addEventListener ) {
117                                                 elem.addEventListener( type, eventHandle, false );
119                                         } else if ( elem.attachEvent ) {
120                                                 elem.attachEvent( "on" + type, eventHandle );
121                                         }
122                                 }
123                         }
125                         if ( special.add ) {
126                                 special.add.call( elem, handleObj );
128                                 if ( !handleObj.handler.guid ) {
129                                         handleObj.handler.guid = handler.guid;
130                                 }
131                         }
133                         // Add the function to the element's handler list
134                         handlers.push( handleObj );
136                         // Keep track of which events have been used, for event optimization
137                         jQuery.event.global[ type ] = true;
138                 }
140                 // Nullify elem to prevent memory leaks in IE
141                 elem = null;
142         },
144         global: {},
146         // Detach an event or set of events from an element
147         remove: function( elem, types, handler, pos ) {
148                 // don't do events on text and comment nodes
149                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
150                         return;
151                 }
153                 if ( handler === false ) {
154                         handler = returnFalse;
155                 }
157                 var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
158                         elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
159                         events = elemData && elemData.events;
161                 if ( !elemData || !events ) {
162                         return;
163                 }
165                 // types is actually an event object here
166                 if ( types && types.type ) {
167                         handler = types.handler;
168                         types = types.type;
169                 }
171                 // Unbind all events for the element
172                 if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
173                         types = types || "";
175                         for ( type in events ) {
176                                 jQuery.event.remove( elem, type + types );
177                         }
179                         return;
180                 }
182                 // Handle multiple events separated by a space
183                 // jQuery(...).unbind("mouseover mouseout", fn);
184                 types = types.split(" ");
186                 while ( (type = types[ i++ ]) ) {
187                         origType = type;
188                         handleObj = null;
189                         all = type.indexOf(".") < 0;
190                         namespaces = [];
192                         if ( !all ) {
193                                 // Namespaced event handlers
194                                 namespaces = type.split(".");
195                                 type = namespaces.shift();
197                                 namespace = new RegExp("(^|\\.)" +
198                                         jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
199                         }
201                         eventType = events[ type ];
203                         if ( !eventType ) {
204                                 continue;
205                         }
207                         if ( !handler ) {
208                                 for ( j = 0; j < eventType.length; j++ ) {
209                                         handleObj = eventType[ j ];
211                                         if ( all || namespace.test( handleObj.namespace ) ) {
212                                                 jQuery.event.remove( elem, origType, handleObj.handler, j );
213                                                 eventType.splice( j--, 1 );
214                                         }
215                                 }
217                                 continue;
218                         }
220                         special = jQuery.event.special[ type ] || {};
222                         for ( j = pos || 0; j < eventType.length; j++ ) {
223                                 handleObj = eventType[ j ];
225                                 if ( handler.guid === handleObj.guid ) {
226                                         // remove the given handler for the given type
227                                         if ( all || namespace.test( handleObj.namespace ) ) {
228                                                 if ( pos == null ) {
229                                                         eventType.splice( j--, 1 );
230                                                 }
232                                                 if ( special.remove ) {
233                                                         special.remove.call( elem, handleObj );
234                                                 }
235                                         }
237                                         if ( pos != null ) {
238                                                 break;
239                                         }
240                                 }
241                         }
243                         // remove generic event handler if no more handlers exist
244                         if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
245                                 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
246                                         jQuery.removeEvent( elem, type, elemData.handle );
247                                 }
249                                 ret = null;
250                                 delete events[ type ];
251                         }
252                 }
254                 // Remove the expando if it's no longer used
255                 if ( jQuery.isEmptyObject( events ) ) {
256                         var handle = elemData.handle;
257                         if ( handle ) {
258                                 handle.elem = null;
259                         }
261                         delete elemData.events;
262                         delete elemData.handle;
264                         if ( jQuery.isEmptyObject( elemData ) ) {
265                                 jQuery.removeData( elem, undefined, true );
266                         }
267                 }
268         },
269         
270         // Events that are safe to short-circuit if no handlers are attached.
271         // Native DOM events should not be added, they may have inline handlers.
272         customEvent: {
273                 "getData": true,
274                 "setData": true,
275                 "changeData": true
276         },
278         trigger: function( event, data, elem, onlyHandlers ) {
279                 // Event object or event type
280                 var type = event.type || event,
281                         namespaces = [],
282                         exclusive;
284                 if ( type.indexOf("!") >= 0 ) {
285                         // Exclusive events trigger only for the exact event (no namespaces)
286                         type = type.slice(0, -1);
287                         exclusive = true;
288                 }
290                 if ( type.indexOf(".") >= 0 ) {
291                         // Namespaced trigger; create a regexp to match event type in handle()
292                         namespaces = type.split(".");
293                         type = namespaces.shift();
294                         namespaces.sort();
295                 }
297                 if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
298                         // No jQuery handlers for this event type, and it can't have inline handlers
299                         return;
300                 }
302                 // Caller can pass in an Event, Object, or just an event type string
303                 event = typeof event === "object" ?
304                         // jQuery.Event object
305                         event[ jQuery.expando ] ? event :
306                         // Object literal
307                         new jQuery.Event( type, event ) :
308                         // Just the event type (string)
309                         new jQuery.Event( type );
311                 event.type = type;
312                 event.exclusive = exclusive;
313                 event.namespace = namespaces.join(".");
314                 event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
315                 
316                 // triggerHandler() and global events don't bubble or run the default action
317                 if ( onlyHandlers || !elem ) {
318                         event.preventDefault();
319                         event.stopPropagation();
320                 }
322                 // Handle a global trigger
323                 if ( !elem ) {
324                         // TODO: Stop taunting the data cache; remove global events and always attach to document
325                         jQuery.each( jQuery.cache, function() {
326                                 // internalKey variable is just used to make it easier to find
327                                 // and potentially change this stuff later; currently it just
328                                 // points to jQuery.expando
329                                 var internalKey = jQuery.expando,
330                                         internalCache = this[ internalKey ];
331                                 if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
332                                         jQuery.event.trigger( event, data, internalCache.handle.elem );
333                                 }
334                         });
335                         return;
336                 }
338                 // Don't do events on text and comment nodes
339                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
340                         return;
341                 }
343                 // Clean up the event in case it is being reused
344                 event.result = undefined;
345                 event.target = elem;
347                 // Clone any incoming data and prepend the event, creating the handler arg list
348                 data = data ? jQuery.makeArray( data ) : [];
349                 data.unshift( event );
351                 var cur = elem,
352                         // IE doesn't like method names with a colon (#3533, #8272)
353                         ontype = type.indexOf(":") < 0 ? "on" + type : "";
355                 // Fire event on the current element, then bubble up the DOM tree
356                 do {
357                         var handle = jQuery._data( cur, "handle" );
359                         event.currentTarget = cur;
360                         if ( handle ) {
361                                 handle.apply( cur, data );
362                         }
364                         // Trigger an inline bound script
365                         if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
366                                 event.result = false;
367                                 event.preventDefault();
368                         }
370                         // Bubble up to document, then to window
371                         cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
372                 } while ( cur && !event.isPropagationStopped() );
374                 // If nobody prevented the default action, do it now
375                 if ( !event.isDefaultPrevented() ) {
376                         var old,
377                                 special = jQuery.event.special[ type ] || {};
379                         if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
380                                 !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
382                                 // Call a native DOM method on the target with the same name name as the event.
383                                 // Can't use an .isFunction)() check here because IE6/7 fails that test.
384                                 // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
385                                 try {
386                                         if ( ontype && elem[ type ] ) {
387                                                 // Don't re-trigger an onFOO event when we call its FOO() method
388                                                 old = elem[ ontype ];
390                                                 if ( old ) {
391                                                         elem[ ontype ] = null;
392                                                 }
394                                                 jQuery.event.triggered = type;
395                                                 elem[ type ]();
396                                         }
397                                 } catch ( ieError ) {}
399                                 if ( old ) {
400                                         elem[ ontype ] = old;
401                                 }
403                                 jQuery.event.triggered = undefined;
404                         }
405                 }
406                 
407                 return event.result;
408         },
410         handle: function( event ) {
411                 event = jQuery.event.fix( event || window.event );
412                 // Snapshot the handlers list since a called handler may add/remove events.
413                 var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
414                         run_all = !event.exclusive && !event.namespace,
415                         args = Array.prototype.slice.call( arguments, 0 );
417                 // Use the fix-ed Event rather than the (read-only) native event
418                 args[0] = event;
419                 event.currentTarget = this;
421                 for ( var j = 0, l = handlers.length; j < l; j++ ) {
422                         var handleObj = handlers[ j ];
424                         // Triggered event must 1) be non-exclusive and have no namespace, or
425                         // 2) have namespace(s) a subset or equal to those in the bound event.
426                         if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
427                                 // Pass in a reference to the handler function itself
428                                 // So that we can later remove it
429                                 event.handler = handleObj.handler;
430                                 event.data = handleObj.data;
431                                 event.handleObj = handleObj;
433                                 var ret = handleObj.handler.apply( this, args );
435                                 if ( ret !== undefined ) {
436                                         event.result = ret;
437                                         if ( ret === false ) {
438                                                 event.preventDefault();
439                                                 event.stopPropagation();
440                                         }
441                                 }
443                                 if ( event.isImmediatePropagationStopped() ) {
444                                         break;
445                                 }
446                         }
447                 }
448                 return event.result;
449         },
451         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(" "),
453         fix: function( event ) {
454                 if ( event[ jQuery.expando ] ) {
455                         return event;
456                 }
458                 // store a copy of the original event object
459                 // and "clone" to set read-only properties
460                 var originalEvent = event;
461                 event = jQuery.Event( originalEvent );
463                 for ( var i = this.props.length, prop; i; ) {
464                         prop = this.props[ --i ];
465                         event[ prop ] = originalEvent[ prop ];
466                 }
468                 // Fix target property, if necessary
469                 if ( !event.target ) {
470                         // Fixes #1925 where srcElement might not be defined either
471                         event.target = event.srcElement || document;
472                 }
474                 // check if target is a textnode (safari)
475                 if ( event.target.nodeType === 3 ) {
476                         event.target = event.target.parentNode;
477                 }
479                 // Add relatedTarget, if necessary
480                 if ( !event.relatedTarget && event.fromElement ) {
481                         event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
482                 }
484                 // Calculate pageX/Y if missing and clientX/Y available
485                 if ( event.pageX == null && event.clientX != null ) {
486                         var eventDocument = event.target.ownerDocument || document,
487                                 doc = eventDocument.documentElement,
488                                 body = eventDocument.body;
490                         event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
491                         event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
492                 }
494                 // Add which for key events
495                 if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
496                         event.which = event.charCode != null ? event.charCode : event.keyCode;
497                 }
499                 // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
500                 if ( !event.metaKey && event.ctrlKey ) {
501                         event.metaKey = event.ctrlKey;
502                 }
504                 // Add which for click: 1 === left; 2 === middle; 3 === right
505                 // Note: button is not normalized, so don't use it
506                 if ( !event.which && event.button !== undefined ) {
507                         event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
508                 }
510                 return event;
511         },
513         // Deprecated, use jQuery.guid instead
514         guid: 1E8,
516         // Deprecated, use jQuery.proxy instead
517         proxy: jQuery.proxy,
519         special: {
520                 ready: {
521                         // Make sure the ready event is setup
522                         setup: jQuery.bindReady,
523                         teardown: jQuery.noop
524                 },
526                 live: {
527                         add: function( handleObj ) {
528                                 jQuery.event.add( this,
529                                         liveConvert( handleObj.origType, handleObj.selector ),
530                                         jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
531                         },
533                         remove: function( handleObj ) {
534                                 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
535                         }
536                 },
538                 beforeunload: {
539                         setup: function( data, namespaces, eventHandle ) {
540                                 // We only want to do this special case on windows
541                                 if ( jQuery.isWindow( this ) ) {
542                                         this.onbeforeunload = eventHandle;
543                                 }
544                         },
546                         teardown: function( namespaces, eventHandle ) {
547                                 if ( this.onbeforeunload === eventHandle ) {
548                                         this.onbeforeunload = null;
549                                 }
550                         }
551                 }
552         }
555 jQuery.removeEvent = document.removeEventListener ?
556         function( elem, type, handle ) {
557                 if ( elem.removeEventListener ) {
558                         elem.removeEventListener( type, handle, false );
559                 }
560         } :
561         function( elem, type, handle ) {
562                 if ( elem.detachEvent ) {
563                         elem.detachEvent( "on" + type, handle );
564                 }
565         };
567 jQuery.Event = function( src, props ) {
568         // Allow instantiation without the 'new' keyword
569         if ( !this.preventDefault ) {
570                 return new jQuery.Event( src, props );
571         }
573         // Event object
574         if ( src && src.type ) {
575                 this.originalEvent = src;
576                 this.type = src.type;
578                 // Events bubbling up the document may have been marked as prevented
579                 // by a handler lower down the tree; reflect the correct value.
580                 this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
581                         src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
583         // Event type
584         } else {
585                 this.type = src;
586         }
588         // Put explicitly provided properties onto the event object
589         if ( props ) {
590                 jQuery.extend( this, props );
591         }
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();
597         // Mark it as fixed
598         this[ jQuery.expando ] = true;
601 function returnFalse() {
602         return false;
604 function returnTrue() {
605         return true;
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;
614                 var e = this.originalEvent;
615                 if ( !e ) {
616                         return;
617                 }
619                 // if preventDefault exists run it on the original event
620                 if ( e.preventDefault ) {
621                         e.preventDefault();
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;
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
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;
657         // Firefox sometimes assigns relatedTarget a XUL element
658         // which we cannot access the parentNode property of
659         try {
661                 // Chrome does something similar, the parentNode property
662                 // can be accessed but is null.
663                 if ( parent && parent !== document && !parent.parentNode ) {
664                         return;
665                 }
666                 // Traverse up the tree
667                 while ( parent && parent !== this ) {
668                         parent = parent.parentNode;
669                 }
671                 if ( parent !== this ) {
672                         // set the correct event type
673                         event.type = event.data;
675                         // handle event if we actually just moused on to a non sub-element
676                         jQuery.event.handle.apply( this, arguments );
677                 }
679         // assuming we've left the element since we most likely mousedover a xul element
680         } catch(e) { }
683 // In case of event delegation, we only need to rename the event.type,
684 // liveHandler will take care of the rest.
685 delegate = function( event ) {
686         event.type = event.data;
687         jQuery.event.handle.apply( this, arguments );
690 // Create mouseenter and mouseleave events
691 jQuery.each({
692         mouseenter: "mouseover",
693         mouseleave: "mouseout"
694 }, function( orig, fix ) {
695         jQuery.event.special[ orig ] = {
696                 setup: function( data ) {
697                         jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
698                 },
699                 teardown: function( data ) {
700                         jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
701                 }
702         };
705 // submit delegation
706 if ( !jQuery.support.submitBubbles ) {
708         jQuery.event.special.submit = {
709                 setup: function( data, namespaces ) {
710                         if ( !jQuery.nodeName( this, "form" ) ) {
711                                 jQuery.event.add(this, "click.specialSubmit", function( e ) {
712                                         var elem = e.target,
713                                                 type = elem.type;
715                                         if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
716                                                 trigger( "submit", this, arguments );
717                                         }
718                                 });
720                                 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
721                                         var elem = e.target,
722                                                 type = elem.type;
724                                         if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
725                                                 trigger( "submit", this, arguments );
726                                         }
727                                 });
729                         } else {
730                                 return false;
731                         }
732                 },
734                 teardown: function( namespaces ) {
735                         jQuery.event.remove( this, ".specialSubmit" );
736                 }
737         };
741 // change delegation, happens here so we have bind.
742 if ( !jQuery.support.changeBubbles ) {
744         var changeFilters,
746         getVal = function( elem ) {
747                 var type = elem.type, val = elem.value;
749                 if ( type === "radio" || type === "checkbox" ) {
750                         val = elem.checked;
752                 } else if ( type === "select-multiple" ) {
753                         val = elem.selectedIndex > -1 ?
754                                 jQuery.map( elem.options, function( elem ) {
755                                         return elem.selected;
756                                 }).join("-") :
757                                 "";
759                 } else if ( jQuery.nodeName( elem, "select" ) ) {
760                         val = elem.selectedIndex;
761                 }
763                 return val;
764         },
766         testChange = function testChange( e ) {
767                 var elem = e.target, data, val;
769                 if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
770                         return;
771                 }
773                 data = jQuery._data( elem, "_change_data" );
774                 val = getVal(elem);
776                 // the current data will be also retrieved by beforeactivate
777                 if ( e.type !== "focusout" || elem.type !== "radio" ) {
778                         jQuery._data( elem, "_change_data", val );
779                 }
781                 if ( data === undefined || val === data ) {
782                         return;
783                 }
785                 if ( data != null || val ) {
786                         e.type = "change";
787                         e.liveFired = undefined;
788                         jQuery.event.trigger( e, arguments[1], elem );
789                 }
790         };
792         jQuery.event.special.change = {
793                 filters: {
794                         focusout: testChange,
796                         beforedeactivate: testChange,
798                         click: function( e ) {
799                                 var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
801                                 if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
802                                         testChange.call( this, e );
803                                 }
804                         },
806                         // Change has to be called before submit
807                         // Keydown will be called before keypress, which is used in submit-event delegation
808                         keydown: function( e ) {
809                                 var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
811                                 if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
812                                         (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
813                                         type === "select-multiple" ) {
814                                         testChange.call( this, e );
815                                 }
816                         },
818                         // Beforeactivate happens also before the previous element is blurred
819                         // with this event you can't trigger a change event, but you can store
820                         // information
821                         beforeactivate: function( e ) {
822                                 var elem = e.target;
823                                 jQuery._data( elem, "_change_data", getVal(elem) );
824                         }
825                 },
827                 setup: function( data, namespaces ) {
828                         if ( this.type === "file" ) {
829                                 return false;
830                         }
832                         for ( var type in changeFilters ) {
833                                 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
834                         }
836                         return rformElems.test( this.nodeName );
837                 },
839                 teardown: function( namespaces ) {
840                         jQuery.event.remove( this, ".specialChange" );
842                         return rformElems.test( this.nodeName );
843                 }
844         };
846         changeFilters = jQuery.event.special.change.filters;
848         // Handle when the input is .focus()'d
849         changeFilters.focus = changeFilters.beforeactivate;
852 function trigger( type, elem, args ) {
853         // Piggyback on a donor event to simulate a different one.
854         // Fake originalEvent to avoid donor's stopPropagation, but if the
855         // simulated event prevents default then we do the same on the donor.
856         // Don't pass args or remember liveFired; they apply to the donor event.
857         var event = jQuery.extend( {}, args[ 0 ] );
858         event.type = type;
859         event.originalEvent = {};
860         event.liveFired = undefined;
861         jQuery.event.handle.call( elem, event );
862         if ( event.isDefaultPrevented() ) {
863                 args[ 0 ].preventDefault();
864         }
867 // Create "bubbling" focus and blur events
868 if ( !jQuery.support.focusinBubbles ) {
869         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
871                 // Attach a single capturing handler while someone wants focusin/focusout
872                 var attaches = 0;
874                 jQuery.event.special[ fix ] = {
875                         setup: function() {
876                                 if ( attaches++ === 0 ) {
877                                         document.addEventListener( orig, handler, true );
878                                 }
879                         },
880                         teardown: function() {
881                                 if ( --attaches === 0 ) {
882                                         document.removeEventListener( orig, handler, true );
883                                 }
884                         }
885                 };
887                 function handler( donor ) {
888                         // Donor event is always a native one; fix it and switch its type.
889                         // Let focusin/out handler cancel the donor focus/blur event.
890                         var e = jQuery.event.fix( donor );
891                         e.type = fix;
892                         e.originalEvent = {};
893                         jQuery.event.trigger( e, null, e.target );
894                         if ( e.isDefaultPrevented() ) {
895                                 donor.preventDefault();
896                         }
897                 }
898         });
901 jQuery.each(["bind", "one"], function( i, name ) {
902         jQuery.fn[ name ] = function( type, data, fn ) {
903                 var handler;
905                 // Handle object literals
906                 if ( typeof type === "object" ) {
907                         for ( var key in type ) {
908                                 this[ name ](key, data, type[key], fn);
909                         }
910                         return this;
911                 }
913                 if ( arguments.length === 2 || data === false ) {
914                         fn = data;
915                         data = undefined;
916                 }
918                 if ( name === "one" ) {
919                         handler = function( event ) {
920                                 jQuery( this ).unbind( event, handler );
921                                 return fn.apply( this, arguments );
922                         };
923                         handler.guid = fn.guid || jQuery.guid++;
924                 } else {
925                         handler = fn;
926                 }
928                 if ( type === "unload" && name !== "one" ) {
929                         this.one( type, data, fn );
931                 } else {
932                         for ( var i = 0, l = this.length; i < l; i++ ) {
933                                 jQuery.event.add( this[i], type, handler, data );
934                         }
935                 }
937                 return this;
938         };
941 jQuery.fn.extend({
942         unbind: function( type, fn ) {
943                 // Handle object literals
944                 if ( typeof type === "object" && !type.preventDefault ) {
945                         for ( var key in type ) {
946                                 this.unbind(key, type[key]);
947                         }
949                 } else {
950                         for ( var i = 0, l = this.length; i < l; i++ ) {
951                                 jQuery.event.remove( this[i], type, fn );
952                         }
953                 }
955                 return this;
956         },
958         delegate: function( selector, types, data, fn ) {
959                 return this.live( types, data, fn, selector );
960         },
962         undelegate: function( selector, types, fn ) {
963                 if ( arguments.length === 0 ) {
964                         return this.unbind( "live" );
966                 } else {
967                         return this.die( types, null, fn, selector );
968                 }
969         },
971         trigger: function( type, data ) {
972                 return this.each(function() {
973                         jQuery.event.trigger( type, data, this );
974                 });
975         },
977         triggerHandler: function( type, data ) {
978                 if ( this[0] ) {
979                         return jQuery.event.trigger( type, data, this[0], true );
980                 }
981         },
983         toggle: function( fn ) {
984                 // Save reference to arguments for access in closure
985                 var args = arguments,
986                         guid = fn.guid || jQuery.guid++,
987                         i = 0,
988                         toggler = function( event ) {
989                                 // Figure out which function to execute
990                                 var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
991                                 jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
993                                 // Make sure that clicks stop
994                                 event.preventDefault();
996                                 // and execute the function
997                                 return args[ lastToggle ].apply( this, arguments ) || false;
998                         };
1000                 // link all the functions, so any of them can unbind this click handler
1001                 toggler.guid = guid;
1002                 while ( i < args.length ) {
1003                         args[ i++ ].guid = guid;
1004                 }
1006                 return this.click( toggler );
1007         },
1009         hover: function( fnOver, fnOut ) {
1010                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
1011         }
1014 var liveMap = {
1015         focus: "focusin",
1016         blur: "focusout",
1017         mouseenter: "mouseover",
1018         mouseleave: "mouseout"
1021 jQuery.each(["live", "die"], function( i, name ) {
1022         jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
1023                 var type, i = 0, match, namespaces, preType,
1024                         selector = origSelector || this.selector,
1025                         context = origSelector ? this : jQuery( this.context );
1027                 if ( typeof types === "object" && !types.preventDefault ) {
1028                         for ( var key in types ) {
1029                                 context[ name ]( key, data, types[key], selector );
1030                         }
1032                         return this;
1033                 }
1035                 if ( name === "die" && !types &&
1036                                         origSelector && origSelector.charAt(0) === "." ) {
1038                         context.unbind( origSelector );
1040                         return this;
1041                 }
1043                 if ( data === false || jQuery.isFunction( data ) ) {
1044                         fn = data || returnFalse;
1045                         data = undefined;
1046                 }
1048                 types = (types || "").split(" ");
1050                 while ( (type = types[ i++ ]) != null ) {
1051                         match = rnamespaces.exec( type );
1052                         namespaces = "";
1054                         if ( match )  {
1055                                 namespaces = match[0];
1056                                 type = type.replace( rnamespaces, "" );
1057                         }
1059                         if ( type === "hover" ) {
1060                                 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
1061                                 continue;
1062                         }
1064                         preType = type;
1066                         if ( liveMap[ type ] ) {
1067                                 types.push( liveMap[ type ] + namespaces );
1068                                 type = type + namespaces;
1070                         } else {
1071                                 type = (liveMap[ type ] || type) + namespaces;
1072                         }
1074                         if ( name === "live" ) {
1075                                 // bind live handler
1076                                 for ( var j = 0, l = context.length; j < l; j++ ) {
1077                                         jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
1078                                                 { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
1079                                 }
1081                         } else {
1082                                 // unbind live handler
1083                                 context.unbind( "live." + liveConvert( type, selector ), fn );
1084                         }
1085                 }
1087                 return this;
1088         };
1091 function liveHandler( event ) {
1092         var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
1093                 elems = [],
1094                 selectors = [],
1095                 events = jQuery._data( this, "events" );
1097         // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
1098         if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
1099                 return;
1100         }
1102         if ( event.namespace ) {
1103                 namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
1104         }
1106         event.liveFired = this;
1108         var live = events.live.slice(0);
1110         for ( j = 0; j < live.length; j++ ) {
1111                 handleObj = live[j];
1113                 if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
1114                         selectors.push( handleObj.selector );
1116                 } else {
1117                         live.splice( j--, 1 );
1118                 }
1119         }
1121         match = jQuery( event.target ).closest( selectors, event.currentTarget );
1123         for ( i = 0, l = match.length; i < l; i++ ) {
1124                 close = match[i];
1126                 for ( j = 0; j < live.length; j++ ) {
1127                         handleObj = live[j];
1129                         if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
1130                                 elem = close.elem;
1131                                 related = null;
1133                                 // Those two events require additional checking
1134                                 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
1135                                         event.type = handleObj.preType;
1136                                         related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
1138                                         // Make sure not to accidentally match a child element with the same selector
1139                                         if ( related && jQuery.contains( elem, related ) ) {
1140                                                 related = elem;
1141                                         }
1142                                 }
1144                                 if ( !related || related !== elem ) {
1145                                         elems.push({ elem: elem, handleObj: handleObj, level: close.level });
1146                                 }
1147                         }
1148                 }
1149         }
1151         for ( i = 0, l = elems.length; i < l; i++ ) {
1152                 match = elems[i];
1154                 if ( maxLevel && match.level > maxLevel ) {
1155                         break;
1156                 }
1158                 event.currentTarget = match.elem;
1159                 event.data = match.handleObj.data;
1160                 event.handleObj = match.handleObj;
1162                 ret = match.handleObj.origHandler.apply( match.elem, arguments );
1164                 if ( ret === false || event.isPropagationStopped() ) {
1165                         maxLevel = match.level;
1167                         if ( ret === false ) {
1168                                 stop = false;
1169                         }
1170                         if ( event.isImmediatePropagationStopped() ) {
1171                                 break;
1172                         }
1173                 }
1174         }
1176         return stop;
1179 function liveConvert( type, selector ) {
1180         return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
1183 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
1184         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
1185         "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
1187         // Handle event binding
1188         jQuery.fn[ name ] = function( data, fn ) {
1189                 if ( fn == null ) {
1190                         fn = data;
1191                         data = null;
1192                 }
1194                 return arguments.length > 0 ?
1195                         this.bind( name, data, fn ) :
1196                         this.trigger( name );
1197         };
1199         if ( jQuery.attrFn ) {
1200                 jQuery.attrFn[ name ] = true;
1201         }
1204 })( jQuery );