Remove .hyphen property from tests (left behind in refactoring)
[jquery.git] / src / event.js
blob4b0040528dd0f8ddf762f80ff7a0a7158951f21f
1 var rformElems = /^(?:textarea|input|select)$/i,
2         rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/,
3         rkeyEvent = /^key/,
4         rmouseEvent = /^(?:mouse|contextmenu)|click/,
5         rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
7 /*
8  * Helper functions for managing events -- not part of the public interface.
9  * Props to Dean Edwards' addEvent library for many of the ideas.
10  */
11 jQuery.event = {
13         add: function( elem, types, handler, data, selector ) {
14                 var elemData, eventHandle, events,
15                         t, tns, type, namespaces, handleObj,
16                         handleObjIn, handlers, special;
18                 // Don't attach events to noData or text/comment nodes (allow plain objects tho)
19                 if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
20                         return;
21                 }
23                 // Caller can pass in an object of custom data in lieu of the handler
24                 if ( handler.handler ) {
25                         handleObjIn = handler;
26                         handler = handleObjIn.handler;
27                         selector = handleObjIn.selector;
28                 }
30                 // Make sure that the handler has a unique ID, used to find/remove it later
31                 if ( !handler.guid ) {
32                         handler.guid = jQuery.guid++;
33                 }
35                 // Init the element's event structure and main handler, if this is the first
36                 events = elemData.events;
37                 if ( !events ) {
38                         elemData.events = events = {};
39                 }
40                 eventHandle = elemData.handle;
41                 if ( !eventHandle ) {
42                         elemData.handle = eventHandle = function( e ) {
43                                 // Discard the second event of a jQuery.event.trigger() and
44                                 // when an event is called after a page has unloaded
45                                 return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
46                                         jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
47                                         undefined;
48                         };
49                         // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
50                         eventHandle.elem = elem;
51                 }
53                 // Handle multiple events separated by a space
54                 // jQuery(...).bind("mouseover mouseout", fn);
55                 types = jQuery.trim( types ).split( " " );
56                 for ( t = 0; t < types.length; t++ ) {
58                         tns = rtypenamespace.exec( types[t] ) || [];
59                         type = tns[1];
60                         namespaces = ( tns[2] || "" ).split( "." ).sort();
62                         // If event changes its type, use the special event handlers for the changed type
63                         special = jQuery.event.special[ type ] || {};
65                         // If selector defined, determine special event api type, otherwise given type
66                         type = ( selector ? special.delegateType : special.bindType ) || type;
68                         // Update special based on newly reset type
69                         special = jQuery.event.special[ type ] || {};
71                         // handleObj is passed to all event handlers
72                         handleObj = jQuery.extend({
73                                 type: type,
74                                 origType: tns[1],
75                                 data: data,
76                                 handler: handler,
77                                 guid: handler.guid,
78                                 selector: selector,
79                                 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
80                                 namespace: namespaces.join(".")
81                         }, handleObjIn );
83                         // Init the event handler queue if we're the first
84                         handlers = events[ type ];
85                         if ( !handlers ) {
86                                 handlers = events[ type ] = [];
87                                 handlers.delegateCount = 0;
89                                 // Only use addEventListener/attachEvent if the special events handler returns false
90                                 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
91                                         // Bind the global event handler to the element
92                                         if ( elem.addEventListener ) {
93                                                 elem.addEventListener( type, eventHandle, false );
95                                         } else if ( elem.attachEvent ) {
96                                                 elem.attachEvent( "on" + type, eventHandle );
97                                         }
98                                 }
99                         }
101                         if ( special.add ) {
102                                 special.add.call( elem, handleObj );
104                                 if ( !handleObj.handler.guid ) {
105                                         handleObj.handler.guid = handler.guid;
106                                 }
107                         }
109                         // Add to the element's handler list, delegates in front
110                         if ( selector ) {
111                                 handlers.splice( handlers.delegateCount++, 0, handleObj );
112                         } else {
113                                 handlers.push( handleObj );
114                         }
116                         // Keep track of which events have ever been used, for event optimization
117                         jQuery.event.global[ type ] = true;
118                 }
120                 // Nullify elem to prevent memory leaks in IE
121                 elem = null;
122         },
124         global: {},
126         // Detach an event or set of events from an element
127         remove: function( elem, types, handler, selector, mappedTypes ) {
129                 var t, tns, type, origType, namespaces, origCount,
130                         j, events, special, eventType, handleObj,
131                         elemData = jQuery.hasData( elem ) && jQuery._data( elem );
133                 if ( !elemData || !(events = elemData.events) ) {
134                         return;
135                 }
137                 // Once for each type.namespace in types; type may be omitted
138                 types = jQuery.trim( types ).split(" ");
139                 for ( t = 0; t < types.length; t++ ) {
140                         tns = rtypenamespace.exec( types[t] ) || [];
141                         type = origType = tns[1];
142                         namespaces = tns[2];
144                         // Unbind all events (on this namespace, if provided) for the element
145                         if ( !type ) {
146                                 for ( type in events ) {
147                                         jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
148                                 }
149                                 continue;
150                         }
152                         special = jQuery.event.special[ type ] || {};
153                         type = ( selector? special.delegateType : special.bindType ) || type;
154                         eventType = events[ type ] || [];
155                         origCount = eventType.length;
156                         namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
158                         // Remove matching events
159                         for ( j = 0; j < eventType.length; j++ ) {
160                                 handleObj = eventType[ j ];
162                                 if ( ( mappedTypes || origType === handleObj.origType ) &&
163                                         ( !handler || handler.guid === handleObj.guid ) &&
164                                         ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
165                                         ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
166                                         eventType.splice( j--, 1 );
168                                         if ( handleObj.selector ) {
169                                                 eventType.delegateCount--;
170                                         }
171                                         if ( special.remove ) {
172                                                 special.remove.call( elem, handleObj );
173                                         }
174                                 }
175                         }
177                         // Remove generic event handler if we removed something and no more handlers exist
178                         // (avoids potential for endless recursion during removal of special event handlers)
179                         if ( eventType.length === 0 && origCount !== eventType.length ) {
180                                 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
181                                         jQuery.removeEvent( elem, type, elemData.handle );
182                                 }
184                                 delete events[ type ];
185                         }
186                 }
188                 // Remove the expando if it's no longer used
189                 if ( jQuery.isEmptyObject( events ) ) {
190                         delete elemData.handle;
192                         // removeData also checks for emptiness and clears the expando if empty
193                         // so use it instead of delete
194                         jQuery._removeData( elem, "events" );
195                 }
196         },
198         // Events that are safe to short-circuit if no handlers are attached.
199         // Native DOM events should not be added, they may have inline handlers.
200         customEvent: {
201                 "getData": true,
202                 "setData": true,
203                 "changeData": true
204         },
206         trigger: function( event, data, elem, onlyHandlers ) {
207                 // Don't do events on text and comment nodes
208                 if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
209                         return;
210                 }
212                 // Event object or event type
213                 var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType,
214                         type = event.type || event,
215                         namespaces = event.namespace ? event.namespace.split(".") : [];
217                 // focus/blur morphs to focusin/out; ensure we're not firing them right now
218                 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
219                         return;
220                 }
222                 if ( type.indexOf( "!" ) >= 0 ) {
223                         // Exclusive events trigger only for the exact event (no namespaces)
224                         type = type.slice(0, -1);
225                         exclusive = true;
226                 }
228                 if ( type.indexOf( "." ) >= 0 ) {
229                         // Namespaced trigger; create a regexp to match event type in handle()
230                         namespaces = type.split(".");
231                         type = namespaces.shift();
232                         namespaces.sort();
233                 }
235                 if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
236                         // No jQuery handlers for this event type, and it can't have inline handlers
237                         return;
238                 }
240                 // Caller can pass in an Event, Object, or just an event type string
241                 event = typeof event === "object" ?
242                         // jQuery.Event object
243                         event[ jQuery.expando ] ? event :
244                         // Object literal
245                         new jQuery.Event( type, event ) :
246                         // Just the event type (string)
247                         new jQuery.Event( type );
249                 event.type = type;
250                 event.isTrigger = true;
251                 event.exclusive = exclusive;
252                 event.namespace = namespaces.join( "." );
253                 event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
254                 ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
256                 // Handle a global trigger
257                 if ( !elem ) {
259                         // TODO: Stop taunting the data cache; remove global events and always attach to document
260                         cache = jQuery.cache;
261                         for ( i in cache ) {
262                                 if ( cache[ i ].events && cache[ i ].events[ type ] ) {
263                                         jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
264                                 }
265                         }
266                         return;
267                 }
269                 // Clean up the event in case it is being reused
270                 event.result = undefined;
271                 if ( !event.target ) {
272                         event.target = elem;
273                 }
275                 // Clone any incoming data and prepend the event, creating the handler arg list
276                 data = data != null ? jQuery.makeArray( data ) : [];
277                 data.unshift( event );
279                 // Allow special events to draw outside the lines
280                 special = jQuery.event.special[ type ] || {};
281                 if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
282                         return;
283                 }
285                 // Determine event propagation path in advance, per W3C events spec (#9951)
286                 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
287                 eventPath = [[ elem, special.bindType || type ]];
288                 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
290                         bubbleType = special.delegateType || type;
291                         cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
292                         for ( old = elem; cur; cur = cur.parentNode ) {
293                                 eventPath.push([ cur, bubbleType ]);
294                                 old = cur;
295                         }
297                         // Only add window if we got to document (e.g., not plain obj or detached DOM)
298                         if ( old === (elem.ownerDocument || document) ) {
299                                 eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
300                         }
301                 }
303                 // Fire handlers on the event path
304                 for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
306                         cur = eventPath[i][0];
307                         event.type = eventPath[i][1];
309                         handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
310                         if ( handle ) {
311                                 handle.apply( cur, data );
312                         }
313                         // Note that this is a bare JS function and not a jQuery handler
314                         handle = ontype && cur[ ontype ];
315                         if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
316                                 event.preventDefault();
317                         }
318                 }
319                 event.type = type;
321                 // If nobody prevented the default action, do it now
322                 if ( !onlyHandlers && !event.isDefaultPrevented() ) {
324                         if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
325                                 !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
327                                 // Call a native DOM method on the target with the same name name as the event.
328                                 // Can't use an .isFunction() check here because IE6/7 fails that test.
329                                 // Don't do default actions on window, that's where global variables be (#6170)
330                                 if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
332                                         // Don't re-trigger an onFOO event when we call its FOO() method
333                                         old = elem[ ontype ];
335                                         if ( old ) {
336                                                 elem[ ontype ] = null;
337                                         }
339                                         // Prevent re-triggering of the same event, since we already bubbled it above
340                                         jQuery.event.triggered = type;
341                                         try {
342                                                 elem[ type ]();
343                                         } catch ( e ) {
344                                                 // IE<9 dies on focus/blur to hidden element (#1486,#12518)
345                                                 // only reproducible on winXP IE8 native, not IE9 in IE8 mode
346                                         }
347                                         jQuery.event.triggered = undefined;
349                                         if ( old ) {
350                                                 elem[ ontype ] = old;
351                                         }
352                                 }
353                         }
354                 }
356                 return event.result;
357         },
359         dispatch: function( event ) {
361                 // Make a writable jQuery.Event from the native event object
362                 event = jQuery.event.fix( event );
364                 var i, j, cur, ret, selMatch, matched, matches, handleObj, sel,
365                         handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
366                         delegateCount = handlers.delegateCount,
367                         args = core_slice.call( arguments ),
368                         run_all = !event.exclusive && !event.namespace,
369                         special = jQuery.event.special[ event.type ] || {},
370                         handlerQueue = [];
372                 // Use the fix-ed jQuery.Event rather than the (read-only) native event
373                 args[0] = event;
374                 event.delegateTarget = this;
376                 // Call the preDispatch hook for the mapped type, and let it bail if desired
377                 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
378                         return;
379                 }
381                 // Determine handlers that should run if there are delegated events
382                 // Avoid non-left-click bubbling in Firefox (#3861)
383                 if ( delegateCount && !(event.button && event.type === "click") ) {
385                         for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
387                                 // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
388                                 if ( cur.disabled !== true || event.type !== "click" ) {
389                                         selMatch = {};
390                                         matches = [];
391                                         for ( i = 0; i < delegateCount; i++ ) {
392                                                 handleObj = handlers[ i ];
393                                                 sel = handleObj.selector;
395                                                 if ( selMatch[ sel ] === undefined ) {
396                                                         selMatch[ sel ] = handleObj.needsContext ?
397                                                                 jQuery( sel, this ).index( cur ) >= 0 :
398                                                                 jQuery.find( sel, this, null, [ cur ] ).length;
399                                                 }
400                                                 if ( selMatch[ sel ] ) {
401                                                         matches.push( handleObj );
402                                                 }
403                                         }
404                                         if ( matches.length ) {
405                                                 handlerQueue.push({ elem: cur, matches: matches });
406                                         }
407                                 }
408                         }
409                 }
411                 // Add the remaining (directly-bound) handlers
412                 if ( handlers.length > delegateCount ) {
413                         handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
414                 }
416                 // Run delegates first; they may want to stop propagation beneath us
417                 for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
418                         matched = handlerQueue[ i ];
419                         event.currentTarget = matched.elem;
421                         for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
422                                 handleObj = matched.matches[ j ];
424                                 // Triggered event must either 1) be non-exclusive and have no namespace, or
425                                 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
426                                 if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
428                                         event.data = handleObj.data;
429                                         event.handleObj = handleObj;
431                                         ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
432                                                         .apply( matched.elem, args );
434                                         if ( ret !== undefined ) {
435                                                 event.result = ret;
436                                                 if ( ret === false ) {
437                                                         event.preventDefault();
438                                                         event.stopPropagation();
439                                                 }
440                                         }
441                                 }
442                         }
443                 }
445                 // Call the postDispatch hook for the mapped type
446                 if ( special.postDispatch ) {
447                         special.postDispatch.call( this, event );
448                 }
450                 return event.result;
451         },
453         // Includes some event props shared by KeyEvent and MouseEvent
454         // *** attrChange attrName relatedNode srcElement  are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
455         props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
457         fixHooks: {},
459         keyHooks: {
460                 props: "char charCode key keyCode".split(" "),
461                 filter: function( event, original ) {
463                         // Add which for key events
464                         if ( event.which == null ) {
465                                 event.which = original.charCode != null ? original.charCode : original.keyCode;
466                         }
468                         return event;
469                 }
470         },
472         mouseHooks: {
473                 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
474                 filter: function( event, original ) {
475                         var eventDoc, doc, body,
476                                 button = original.button,
477                                 fromElement = original.fromElement;
479                         // Calculate pageX/Y if missing and clientX/Y available
480                         if ( event.pageX == null && original.clientX != null ) {
481                                 eventDoc = event.target.ownerDocument || document;
482                                 doc = eventDoc.documentElement;
483                                 body = eventDoc.body;
485                                 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
486                                 event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
487                         }
489                         // Add relatedTarget, if necessary
490                         if ( !event.relatedTarget && fromElement ) {
491                                 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
492                         }
494                         // Add which for click: 1 === left; 2 === middle; 3 === right
495                         // Note: button is not normalized, so don't use it
496                         if ( !event.which && button !== undefined ) {
497                                 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
498                         }
500                         return event;
501                 }
502         },
504         fix: function( event ) {
505                 if ( event[ jQuery.expando ] ) {
506                         return event;
507                 }
509                 // Create a writable copy of the event object and normalize some properties
510                 var i, prop,
511                         originalEvent = event,
512                         fixHook = jQuery.event.fixHooks[ event.type ] || {},
513                         copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
515                 event = jQuery.Event( originalEvent );
517                 for ( i = copy.length; i; ) {
518                         prop = copy[ --i ];
519                         event[ prop ] = originalEvent[ prop ];
520                 }
522                 // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
523                 if ( !event.target ) {
524                         event.target = originalEvent.srcElement || document;
525                 }
527                 // Target should not be a text node (#504, Safari)
528                 if ( event.target.nodeType === 3 ) {
529                         event.target = event.target.parentNode;
530                 }
532                 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8)
533                 event.metaKey = !!event.metaKey;
535                 return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
536         },
538         special: {
539                 load: {
540                         // Prevent triggered image.load events from bubbling to window.load
541                         noBubble: true
542                 },
544                 focus: {
545                         delegateType: "focusin"
546                 },
547                 blur: {
548                         delegateType: "focusout"
549                 },
551                 beforeunload: {
552                         postDispatch: function( event ) {
554                                 // Even when returnValue equals to undefined Firefox will still show alert
555                                 if ( event.result !== undefined ) {
556                                         event.originalEvent.returnValue = event.result;
557                                 }
558                         }
559                 }
560         },
562         simulate: function( type, elem, event, bubble ) {
563                 // Piggyback on a donor event to simulate a different one.
564                 // Fake originalEvent to avoid donor's stopPropagation, but if the
565                 // simulated event prevents default then we do the same on the donor.
566                 var e = jQuery.extend(
567                         new jQuery.Event(),
568                         event,
569                         { type: type,
570                                 isSimulated: true,
571                                 originalEvent: {}
572                         }
573                 );
574                 if ( bubble ) {
575                         jQuery.event.trigger( e, null, elem );
576                 } else {
577                         jQuery.event.dispatch.call( elem, e );
578                 }
579                 if ( e.isDefaultPrevented() ) {
580                         event.preventDefault();
581                 }
582         }
585 // Some plugins are using, but it's undocumented/deprecated and will be removed.
586 // The 1.7 special event interface should provide all the hooks needed now.
587 jQuery.event.handle = jQuery.event.dispatch;
589 jQuery.removeEvent = document.removeEventListener ?
590         function( elem, type, handle ) {
591                 if ( elem.removeEventListener ) {
592                         elem.removeEventListener( type, handle, false );
593                 }
594         } :
595         function( elem, type, handle ) {
596                 var name = "on" + type;
598                 if ( elem.detachEvent ) {
600                         // #8545, #7054, preventing memory leaks for custom events in IE6-8
601                         // detachEvent needed property on element, by name of that event, to properly expose it to GC
602                         if ( typeof elem[ name ] === "undefined" ) {
603                                 elem[ name ] = null;
604                         }
606                         elem.detachEvent( name, handle );
607                 }
608         };
610 jQuery.Event = function( src, props ) {
611         // Allow instantiation without the 'new' keyword
612         if ( !(this instanceof jQuery.Event) ) {
613                 return new jQuery.Event( src, props );
614         }
616         // Event object
617         if ( src && src.type ) {
618                 this.originalEvent = src;
619                 this.type = src.type;
621                 // Events bubbling up the document may have been marked as prevented
622                 // by a handler lower down the tree; reflect the correct value.
623                 this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
624                         src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
626         // Event type
627         } else {
628                 this.type = src;
629         }
631         // Put explicitly provided properties onto the event object
632         if ( props ) {
633                 jQuery.extend( this, props );
634         }
636         // Create a timestamp if incoming event doesn't have one
637         this.timeStamp = src && src.timeStamp || jQuery.now();
639         // Mark it as fixed
640         this[ jQuery.expando ] = true;
643 function returnFalse() {
644         return false;
646 function returnTrue() {
647         return true;
650 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
651 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
652 jQuery.Event.prototype = {
653         preventDefault: function() {
654                 this.isDefaultPrevented = returnTrue;
656                 var e = this.originalEvent;
657                 if ( !e ) {
658                         return;
659                 }
661                 // if preventDefault exists run it on the original event
662                 if ( e.preventDefault ) {
663                         e.preventDefault();
665                 // otherwise set the returnValue property of the original event to false (IE)
666                 } else {
667                         e.returnValue = false;
668                 }
669         },
670         stopPropagation: function() {
671                 this.isPropagationStopped = returnTrue;
673                 var e = this.originalEvent;
674                 if ( !e ) {
675                         return;
676                 }
677                 // if stopPropagation exists run it on the original event
678                 if ( e.stopPropagation ) {
679                         e.stopPropagation();
680                 }
681                 // otherwise set the cancelBubble property of the original event to true (IE)
682                 e.cancelBubble = true;
683         },
684         stopImmediatePropagation: function() {
685                 this.isImmediatePropagationStopped = returnTrue;
686                 this.stopPropagation();
687         },
688         isDefaultPrevented: returnFalse,
689         isPropagationStopped: returnFalse,
690         isImmediatePropagationStopped: returnFalse
693 // Create mouseenter/leave events using mouseover/out and event-time checks
694 jQuery.each({
695         mouseenter: "mouseover",
696         mouseleave: "mouseout"
697 }, function( orig, fix ) {
698         jQuery.event.special[ orig ] = {
699                 delegateType: fix,
700                 bindType: fix,
702                 handle: function( event ) {
703                         var ret,
704                                 target = this,
705                                 related = event.relatedTarget,
706                                 handleObj = event.handleObj;
708                         // For mousenter/leave call the handler if related is outside the target.
709                         // NB: No relatedTarget if the mouse left/entered the browser window
710                         if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
711                                 event.type = handleObj.origType;
712                                 ret = handleObj.handler.apply( this, arguments );
713                                 event.type = fix;
714                         }
715                         return ret;
716                 }
717         };
720 // IE submit delegation
721 if ( !jQuery.support.submitBubbles ) {
723         jQuery.event.special.submit = {
724                 setup: function() {
725                         // Only need this for delegated form submit events
726                         if ( jQuery.nodeName( this, "form" ) ) {
727                                 return false;
728                         }
730                         // Lazy-add a submit handler when a descendant form may potentially be submitted
731                         jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
732                                 // Node name check avoids a VML-related crash in IE (#9807)
733                                 var elem = e.target,
734                                         form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
735                                 if ( form && !jQuery._data( form, "_submit_attached" ) ) {
736                                         jQuery.event.add( form, "submit._submit", function( event ) {
737                                                 event._submit_bubble = true;
738                                         });
739                                         jQuery._data( form, "_submit_attached", true );
740                                 }
741                         });
742                         // return undefined since we don't need an event listener
743                 },
745                 postDispatch: function( event ) {
746                         // If form was submitted by the user, bubble the event up the tree
747                         if ( event._submit_bubble ) {
748                                 delete event._submit_bubble;
749                                 if ( this.parentNode && !event.isTrigger ) {
750                                         jQuery.event.simulate( "submit", this.parentNode, event, true );
751                                 }
752                         }
753                 },
755                 teardown: function() {
756                         // Only need this for delegated form submit events
757                         if ( jQuery.nodeName( this, "form" ) ) {
758                                 return false;
759                         }
761                         // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
762                         jQuery.event.remove( this, "._submit" );
763                 }
764         };
767 // IE change delegation and checkbox/radio fix
768 if ( !jQuery.support.changeBubbles ) {
770         jQuery.event.special.change = {
772                 setup: function() {
774                         if ( rformElems.test( this.nodeName ) ) {
775                                 // IE doesn't fire change on a check/radio until blur; trigger it on click
776                                 // after a propertychange. Eat the blur-change in special.change.handle.
777                                 // This still fires onchange a second time for check/radio after blur.
778                                 if ( this.type === "checkbox" || this.type === "radio" ) {
779                                         jQuery.event.add( this, "propertychange._change", function( event ) {
780                                                 if ( event.originalEvent.propertyName === "checked" ) {
781                                                         this._just_changed = true;
782                                                 }
783                                         });
784                                         jQuery.event.add( this, "click._change", function( event ) {
785                                                 if ( this._just_changed && !event.isTrigger ) {
786                                                         this._just_changed = false;
787                                                 }
788                                                 // Allow triggered, simulated change events (#11500)
789                                                 jQuery.event.simulate( "change", this, event, true );
790                                         });
791                                 }
792                                 return false;
793                         }
794                         // Delegated event; lazy-add a change handler on descendant inputs
795                         jQuery.event.add( this, "beforeactivate._change", function( e ) {
796                                 var elem = e.target;
798                                 if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) {
799                                         jQuery.event.add( elem, "change._change", function( event ) {
800                                                 if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
801                                                         jQuery.event.simulate( "change", this.parentNode, event, true );
802                                                 }
803                                         });
804                                         jQuery._data( elem, "_change_attached", true );
805                                 }
806                         });
807                 },
809                 handle: function( event ) {
810                         var elem = event.target;
812                         // Swallow native change events from checkbox/radio, we already triggered them above
813                         if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
814                                 return event.handleObj.handler.apply( this, arguments );
815                         }
816                 },
818                 teardown: function() {
819                         jQuery.event.remove( this, "._change" );
821                         return !rformElems.test( this.nodeName );
822                 }
823         };
826 // Create "bubbling" focus and blur events
827 if ( !jQuery.support.focusinBubbles ) {
828         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
830                 // Attach a single capturing handler while someone wants focusin/focusout
831                 var attaches = 0,
832                         handler = function( event ) {
833                                 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
834                         };
836                 jQuery.event.special[ fix ] = {
837                         setup: function() {
838                                 if ( attaches++ === 0 ) {
839                                         document.addEventListener( orig, handler, true );
840                                 }
841                         },
842                         teardown: function() {
843                                 if ( --attaches === 0 ) {
844                                         document.removeEventListener( orig, handler, true );
845                                 }
846                         }
847                 };
848         });
851 jQuery.fn.extend({
853         on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
854                 var origFn, type;
856                 // Types can be a map of types/handlers
857                 if ( typeof types === "object" ) {
858                         // ( types-Object, selector, data )
859                         if ( typeof selector !== "string" ) { // && selector != null
860                                 // ( types-Object, data )
861                                 data = data || selector;
862                                 selector = undefined;
863                         }
864                         for ( type in types ) {
865                                 this.on( type, selector, data, types[ type ], one );
866                         }
867                         return this;
868                 }
870                 if ( data == null && fn == null ) {
871                         // ( types, fn )
872                         fn = selector;
873                         data = selector = undefined;
874                 } else if ( fn == null ) {
875                         if ( typeof selector === "string" ) {
876                                 // ( types, selector, fn )
877                                 fn = data;
878                                 data = undefined;
879                         } else {
880                                 // ( types, data, fn )
881                                 fn = data;
882                                 data = selector;
883                                 selector = undefined;
884                         }
885                 }
886                 if ( fn === false ) {
887                         fn = returnFalse;
888                 } else if ( !fn ) {
889                         return this;
890                 }
892                 if ( one === 1 ) {
893                         origFn = fn;
894                         fn = function( event ) {
895                                 // Can use an empty set, since event contains the info
896                                 jQuery().off( event );
897                                 return origFn.apply( this, arguments );
898                         };
899                         // Use same guid so caller can remove using origFn
900                         fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
901                 }
902                 return this.each( function() {
903                         jQuery.event.add( this, types, fn, data, selector );
904                 });
905         },
906         one: function( types, selector, data, fn ) {
907                 return this.on( types, selector, data, fn, 1 );
908         },
909         off: function( types, selector, fn ) {
910                 var handleObj, type;
911                 if ( types && types.preventDefault && types.handleObj ) {
912                         // ( event )  dispatched jQuery.Event
913                         handleObj = types.handleObj;
914                         jQuery( types.delegateTarget ).off(
915                                 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
916                                 handleObj.selector,
917                                 handleObj.handler
918                         );
919                         return this;
920                 }
921                 if ( typeof types === "object" ) {
922                         // ( types-object [, selector] )
923                         for ( type in types ) {
924                                 this.off( type, selector, types[ type ] );
925                         }
926                         return this;
927                 }
928                 if ( selector === false || typeof selector === "function" ) {
929                         // ( types [, fn] )
930                         fn = selector;
931                         selector = undefined;
932                 }
933                 if ( fn === false ) {
934                         fn = returnFalse;
935                 }
936                 return this.each(function() {
937                         jQuery.event.remove( this, types, fn, selector );
938                 });
939         },
941         bind: function( types, data, fn ) {
942                 return this.on( types, null, data, fn );
943         },
944         unbind: function( types, fn ) {
945                 return this.off( types, null, fn );
946         },
948         live: function( types, data, fn ) {
949                 jQuery( this.context ).on( types, this.selector, data, fn );
950                 return this;
951         },
952         die: function( types, fn ) {
953                 jQuery( this.context ).off( types, this.selector || "**", fn );
954                 return this;
955         },
957         delegate: function( selector, types, data, fn ) {
958                 return this.on( types, selector, data, fn );
959         },
960         undelegate: function( selector, types, fn ) {
961                 // ( namespace ) or ( selector, types [, fn] )
962                 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
963         },
965         trigger: function( type, data ) {
966                 return this.each(function() {
967                         jQuery.event.trigger( type, data, this );
968                 });
969         },
970         triggerHandler: function( type, data ) {
971                 if ( this[0] ) {
972                         return jQuery.event.trigger( type, data, this[0], true );
973                 }
974         },
976         hover: function( fnOver, fnOut ) {
977                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
978         }
981 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
982         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
983         "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
985         // Handle event binding
986         jQuery.fn[ name ] = function( data, fn ) {
987                 if ( fn == null ) {
988                         fn = data;
989                         data = null;
990                 }
992                 return arguments.length > 0 ?
993                         this.on( name, null, data, fn ) :
994                         this.trigger( name );
995         };
997         if ( rkeyEvent.test( name ) ) {
998                 jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
999         }
1001         if ( rmouseEvent.test( name ) ) {
1002                 jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
1003         }