Build: update node dependencies barring jscs
[jquery.git] / src / event.js
blob16ca030bdb3549843a16295d91efe5e534c94a33
1 define([
2         "./core",
3         "./var/strundefined",
4         "./var/rnotwhite",
5         "./var/hasOwn",
6         "./var/slice",
7         "./event/support",
9         "./core/init",
10         "./data/accepts",
11         "./selector"
12 ], function( jQuery, strundefined, rnotwhite, hasOwn, slice, support ) {
14 var rformElems = /^(?:input|select|textarea)$/i,
15         rkeyEvent = /^key/,
16         rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
17         rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
18         rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
20 function returnTrue() {
21         return true;
24 function returnFalse() {
25         return false;
28 function safeActiveElement() {
29         try {
30                 return document.activeElement;
31         } catch ( err ) { }
35  * Helper functions for managing events -- not part of the public interface.
36  * Props to Dean Edwards' addEvent library for many of the ideas.
37  */
38 jQuery.event = {
40         global: {},
42         add: function( elem, types, handler, data, selector ) {
43                 var tmp, events, t, handleObjIn,
44                         special, eventHandle, handleObj,
45                         handlers, type, namespaces, origType,
46                         elemData = jQuery._data( elem );
48                 // Don't attach events to noData or text/comment nodes (but allow plain objects)
49                 if ( !elemData ) {
50                         return;
51                 }
53                 // Caller can pass in an object of custom data in lieu of the handler
54                 if ( handler.handler ) {
55                         handleObjIn = handler;
56                         handler = handleObjIn.handler;
57                         selector = handleObjIn.selector;
58                 }
60                 // Make sure that the handler has a unique ID, used to find/remove it later
61                 if ( !handler.guid ) {
62                         handler.guid = jQuery.guid++;
63                 }
65                 // Init the element's event structure and main handler, if this is the first
66                 if ( !(events = elemData.events) ) {
67                         events = elemData.events = {};
68                 }
69                 if ( !(eventHandle = elemData.handle) ) {
70                         eventHandle = elemData.handle = function( e ) {
71                                 // Discard the second event of a jQuery.event.trigger() and
72                                 // when an event is called after a page has unloaded
73                                 return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
74                                         jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
75                                         undefined;
76                         };
77                         // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
78                         eventHandle.elem = elem;
79                 }
81                 // Handle multiple events separated by a space
82                 types = ( types || "" ).match( rnotwhite ) || [ "" ];
83                 t = types.length;
84                 while ( t-- ) {
85                         tmp = rtypenamespace.exec( types[t] ) || [];
86                         type = origType = tmp[1];
87                         namespaces = ( tmp[2] || "" ).split( "." ).sort();
89                         // There *must* be a type, no attaching namespace-only handlers
90                         if ( !type ) {
91                                 continue;
92                         }
94                         // If event changes its type, use the special event handlers for the changed type
95                         special = jQuery.event.special[ type ] || {};
97                         // If selector defined, determine special event api type, otherwise given type
98                         type = ( selector ? special.delegateType : special.bindType ) || type;
100                         // Update special based on newly reset type
101                         special = jQuery.event.special[ type ] || {};
103                         // handleObj is passed to all event handlers
104                         handleObj = jQuery.extend({
105                                 type: type,
106                                 origType: origType,
107                                 data: data,
108                                 handler: handler,
109                                 guid: handler.guid,
110                                 selector: selector,
111                                 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
112                                 namespace: namespaces.join(".")
113                         }, handleObjIn );
115                         // Init the event handler queue if we're the first
116                         if ( !(handlers = events[ type ]) ) {
117                                 handlers = events[ type ] = [];
118                                 handlers.delegateCount = 0;
120                                 // Only use addEventListener/attachEvent if the special events handler returns false
121                                 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
122                                         // Bind the global event handler to the element
123                                         if ( elem.addEventListener ) {
124                                                 elem.addEventListener( type, eventHandle, false );
126                                         } else if ( elem.attachEvent ) {
127                                                 elem.attachEvent( "on" + type, eventHandle );
128                                         }
129                                 }
130                         }
132                         if ( special.add ) {
133                                 special.add.call( elem, handleObj );
135                                 if ( !handleObj.handler.guid ) {
136                                         handleObj.handler.guid = handler.guid;
137                                 }
138                         }
140                         // Add to the element's handler list, delegates in front
141                         if ( selector ) {
142                                 handlers.splice( handlers.delegateCount++, 0, handleObj );
143                         } else {
144                                 handlers.push( handleObj );
145                         }
147                         // Keep track of which events have ever been used, for event optimization
148                         jQuery.event.global[ type ] = true;
149                 }
151                 // Nullify elem to prevent memory leaks in IE
152                 elem = null;
153         },
155         // Detach an event or set of events from an element
156         remove: function( elem, types, handler, selector, mappedTypes ) {
157                 var j, handleObj, tmp,
158                         origCount, t, events,
159                         special, handlers, type,
160                         namespaces, origType,
161                         elemData = jQuery.hasData( elem ) && jQuery._data( elem );
163                 if ( !elemData || !(events = elemData.events) ) {
164                         return;
165                 }
167                 // Once for each type.namespace in types; type may be omitted
168                 types = ( types || "" ).match( rnotwhite ) || [ "" ];
169                 t = types.length;
170                 while ( t-- ) {
171                         tmp = rtypenamespace.exec( types[t] ) || [];
172                         type = origType = tmp[1];
173                         namespaces = ( tmp[2] || "" ).split( "." ).sort();
175                         // Unbind all events (on this namespace, if provided) for the element
176                         if ( !type ) {
177                                 for ( type in events ) {
178                                         jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
179                                 }
180                                 continue;
181                         }
183                         special = jQuery.event.special[ type ] || {};
184                         type = ( selector ? special.delegateType : special.bindType ) || type;
185                         handlers = events[ type ] || [];
186                         tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
188                         // Remove matching events
189                         origCount = j = handlers.length;
190                         while ( j-- ) {
191                                 handleObj = handlers[ j ];
193                                 if ( ( mappedTypes || origType === handleObj.origType ) &&
194                                         ( !handler || handler.guid === handleObj.guid ) &&
195                                         ( !tmp || tmp.test( handleObj.namespace ) ) &&
196                                         ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
197                                         handlers.splice( j, 1 );
199                                         if ( handleObj.selector ) {
200                                                 handlers.delegateCount--;
201                                         }
202                                         if ( special.remove ) {
203                                                 special.remove.call( elem, handleObj );
204                                         }
205                                 }
206                         }
208                         // Remove generic event handler if we removed something and no more handlers exist
209                         // (avoids potential for endless recursion during removal of special event handlers)
210                         if ( origCount && !handlers.length ) {
211                                 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
212                                         jQuery.removeEvent( elem, type, elemData.handle );
213                                 }
215                                 delete events[ type ];
216                         }
217                 }
219                 // Remove the expando if it's no longer used
220                 if ( jQuery.isEmptyObject( events ) ) {
221                         delete elemData.handle;
223                         // removeData also checks for emptiness and clears the expando if empty
224                         // so use it instead of delete
225                         jQuery._removeData( elem, "events" );
226                 }
227         },
229         trigger: function( event, data, elem, onlyHandlers ) {
230                 var handle, ontype, cur,
231                         bubbleType, special, tmp, i,
232                         eventPath = [ elem || document ],
233                         type = hasOwn.call( event, "type" ) ? event.type : event,
234                         namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
236                 cur = tmp = elem = elem || document;
238                 // Don't do events on text and comment nodes
239                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
240                         return;
241                 }
243                 // focus/blur morphs to focusin/out; ensure we're not firing them right now
244                 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
245                         return;
246                 }
248                 if ( type.indexOf(".") >= 0 ) {
249                         // Namespaced trigger; create a regexp to match event type in handle()
250                         namespaces = type.split(".");
251                         type = namespaces.shift();
252                         namespaces.sort();
253                 }
254                 ontype = type.indexOf(":") < 0 && "on" + type;
256                 // Caller can pass in a jQuery.Event object, Object, or just an event type string
257                 event = event[ jQuery.expando ] ?
258                         event :
259                         new jQuery.Event( type, typeof event === "object" && event );
261                 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
262                 event.isTrigger = onlyHandlers ? 2 : 3;
263                 event.namespace = namespaces.join(".");
264                 event.namespace_re = event.namespace ?
265                         new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
266                         null;
268                 // Clean up the event in case it is being reused
269                 event.result = undefined;
270                 if ( !event.target ) {
271                         event.target = elem;
272                 }
274                 // Clone any incoming data and prepend the event, creating the handler arg list
275                 data = data == null ?
276                         [ event ] :
277                         jQuery.makeArray( data, [ event ] );
279                 // Allow special events to draw outside the lines
280                 special = jQuery.event.special[ type ] || {};
281                 if ( !onlyHandlers && 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                 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
289                         bubbleType = special.delegateType || type;
290                         if ( !rfocusMorph.test( bubbleType + type ) ) {
291                                 cur = cur.parentNode;
292                         }
293                         for ( ; cur; cur = cur.parentNode ) {
294                                 eventPath.push( cur );
295                                 tmp = cur;
296                         }
298                         // Only add window if we got to document (e.g., not plain obj or detached DOM)
299                         if ( tmp === (elem.ownerDocument || document) ) {
300                                 eventPath.push( tmp.defaultView || tmp.parentWindow || window );
301                         }
302                 }
304                 // Fire handlers on the event path
305                 i = 0;
306                 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
308                         event.type = i > 1 ?
309                                 bubbleType :
310                                 special.bindType || type;
312                         // jQuery handler
313                         handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
314                         if ( handle ) {
315                                 handle.apply( cur, data );
316                         }
318                         // Native handler
319                         handle = ontype && cur[ ontype ];
320                         if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
321                                 event.result = handle.apply( cur, data );
322                                 if ( event.result === false ) {
323                                         event.preventDefault();
324                                 }
325                         }
326                 }
327                 event.type = type;
329                 // If nobody prevented the default action, do it now
330                 if ( !onlyHandlers && !event.isDefaultPrevented() ) {
332                         if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
333                                 jQuery.acceptData( elem ) ) {
335                                 // Call a native DOM method on the target with the same name name as the event.
336                                 // Can't use an .isFunction() check here because IE6/7 fails that test.
337                                 // Don't do default actions on window, that's where global variables be (#6170)
338                                 if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
340                                         // Don't re-trigger an onFOO event when we call its FOO() method
341                                         tmp = elem[ ontype ];
343                                         if ( tmp ) {
344                                                 elem[ ontype ] = null;
345                                         }
347                                         // Prevent re-triggering of the same event, since we already bubbled it above
348                                         jQuery.event.triggered = type;
349                                         try {
350                                                 elem[ type ]();
351                                         } catch ( e ) {
352                                                 // IE<9 dies on focus/blur to hidden element (#1486,#12518)
353                                                 // only reproducible on winXP IE8 native, not IE9 in IE8 mode
354                                         }
355                                         jQuery.event.triggered = undefined;
357                                         if ( tmp ) {
358                                                 elem[ ontype ] = tmp;
359                                         }
360                                 }
361                         }
362                 }
364                 return event.result;
365         },
367         dispatch: function( event ) {
369                 // Make a writable jQuery.Event from the native event object
370                 event = jQuery.event.fix( event );
372                 var i, ret, handleObj, matched, j,
373                         handlerQueue = [],
374                         args = slice.call( arguments ),
375                         handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
376                         special = jQuery.event.special[ event.type ] || {};
378                 // Use the fix-ed jQuery.Event rather than the (read-only) native event
379                 args[0] = event;
380                 event.delegateTarget = this;
382                 // Call the preDispatch hook for the mapped type, and let it bail if desired
383                 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
384                         return;
385                 }
387                 // Determine handlers
388                 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
390                 // Run delegates first; they may want to stop propagation beneath us
391                 i = 0;
392                 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
393                         event.currentTarget = matched.elem;
395                         j = 0;
396                         while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
398                                 // Triggered event must either 1) have no namespace, or
399                                 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
400                                 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
402                                         event.handleObj = handleObj;
403                                         event.data = handleObj.data;
405                                         ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
406                                                         .apply( matched.elem, args );
408                                         if ( ret !== undefined ) {
409                                                 if ( (event.result = ret) === false ) {
410                                                         event.preventDefault();
411                                                         event.stopPropagation();
412                                                 }
413                                         }
414                                 }
415                         }
416                 }
418                 // Call the postDispatch hook for the mapped type
419                 if ( special.postDispatch ) {
420                         special.postDispatch.call( this, event );
421                 }
423                 return event.result;
424         },
426         handlers: function( event, handlers ) {
427                 var sel, handleObj, matches, i,
428                         handlerQueue = [],
429                         delegateCount = handlers.delegateCount,
430                         cur = event.target;
432                 // Find delegate handlers
433                 // Black-hole SVG <use> instance trees (#13180)
434                 // Avoid non-left-click bubbling in Firefox (#3861)
435                 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
437                         /* jshint eqeqeq: false */
438                         for ( ; cur != this; cur = cur.parentNode || this ) {
439                                 /* jshint eqeqeq: true */
441                                 // Don't check non-elements (#13208)
442                                 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
443                                 if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
444                                         matches = [];
445                                         for ( i = 0; i < delegateCount; i++ ) {
446                                                 handleObj = handlers[ i ];
448                                                 // Don't conflict with Object.prototype properties (#13203)
449                                                 sel = handleObj.selector + " ";
451                                                 if ( matches[ sel ] === undefined ) {
452                                                         matches[ sel ] = handleObj.needsContext ?
453                                                                 jQuery( sel, this ).index( cur ) >= 0 :
454                                                                 jQuery.find( sel, this, null, [ cur ] ).length;
455                                                 }
456                                                 if ( matches[ sel ] ) {
457                                                         matches.push( handleObj );
458                                                 }
459                                         }
460                                         if ( matches.length ) {
461                                                 handlerQueue.push({ elem: cur, handlers: matches });
462                                         }
463                                 }
464                         }
465                 }
467                 // Add the remaining (directly-bound) handlers
468                 if ( delegateCount < handlers.length ) {
469                         handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
470                 }
472                 return handlerQueue;
473         },
475         fix: function( event ) {
476                 if ( event[ jQuery.expando ] ) {
477                         return event;
478                 }
480                 // Create a writable copy of the event object and normalize some properties
481                 var i, prop, copy,
482                         type = event.type,
483                         originalEvent = event,
484                         fixHook = this.fixHooks[ type ];
486                 if ( !fixHook ) {
487                         this.fixHooks[ type ] = fixHook =
488                                 rmouseEvent.test( type ) ? this.mouseHooks :
489                                 rkeyEvent.test( type ) ? this.keyHooks :
490                                 {};
491                 }
492                 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
494                 event = new jQuery.Event( originalEvent );
496                 i = copy.length;
497                 while ( i-- ) {
498                         prop = copy[ i ];
499                         event[ prop ] = originalEvent[ prop ];
500                 }
502                 // Support: IE<9
503                 // Fix target property (#1925)
504                 if ( !event.target ) {
505                         event.target = originalEvent.srcElement || document;
506                 }
508                 // Support: Chrome 23+, Safari?
509                 // Target should not be a text node (#504, #13143)
510                 if ( event.target.nodeType === 3 ) {
511                         event.target = event.target.parentNode;
512                 }
514                 // Support: IE<9
515                 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
516                 event.metaKey = !!event.metaKey;
518                 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
519         },
521         // Includes some event props shared by KeyEvent and MouseEvent
522         props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
524         fixHooks: {},
526         keyHooks: {
527                 props: "char charCode key keyCode".split(" "),
528                 filter: function( event, original ) {
530                         // Add which for key events
531                         if ( event.which == null ) {
532                                 event.which = original.charCode != null ? original.charCode : original.keyCode;
533                         }
535                         return event;
536                 }
537         },
539         mouseHooks: {
540                 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
541                 filter: function( event, original ) {
542                         var body, eventDoc, doc,
543                                 button = original.button,
544                                 fromElement = original.fromElement;
546                         // Calculate pageX/Y if missing and clientX/Y available
547                         if ( event.pageX == null && original.clientX != null ) {
548                                 eventDoc = event.target.ownerDocument || document;
549                                 doc = eventDoc.documentElement;
550                                 body = eventDoc.body;
552                                 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
553                                 event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
554                         }
556                         // Add relatedTarget, if necessary
557                         if ( !event.relatedTarget && fromElement ) {
558                                 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
559                         }
561                         // Add which for click: 1 === left; 2 === middle; 3 === right
562                         // Note: button is not normalized, so don't use it
563                         if ( !event.which && button !== undefined ) {
564                                 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
565                         }
567                         return event;
568                 }
569         },
571         special: {
572                 load: {
573                         // Prevent triggered image.load events from bubbling to window.load
574                         noBubble: true
575                 },
576                 focus: {
577                         // Fire native event if possible so blur/focus sequence is correct
578                         trigger: function() {
579                                 if ( this !== safeActiveElement() && this.focus ) {
580                                         try {
581                                                 this.focus();
582                                                 return false;
583                                         } catch ( e ) {
584                                                 // Support: IE<9
585                                                 // If we error on focus to hidden element (#1486, #12518),
586                                                 // let .trigger() run the handlers
587                                         }
588                                 }
589                         },
590                         delegateType: "focusin"
591                 },
592                 blur: {
593                         trigger: function() {
594                                 if ( this === safeActiveElement() && this.blur ) {
595                                         this.blur();
596                                         return false;
597                                 }
598                         },
599                         delegateType: "focusout"
600                 },
601                 click: {
602                         // For checkbox, fire native event so checked state will be right
603                         trigger: function() {
604                                 if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
605                                         this.click();
606                                         return false;
607                                 }
608                         },
610                         // For cross-browser consistency, don't fire native .click() on links
611                         _default: function( event ) {
612                                 return jQuery.nodeName( event.target, "a" );
613                         }
614                 },
616                 beforeunload: {
617                         postDispatch: function( event ) {
619                                 // Support: Firefox 20+
620                                 // Firefox doesn't alert if the returnValue field is not set.
621                                 if ( event.result !== undefined && event.originalEvent ) {
622                                         event.originalEvent.returnValue = event.result;
623                                 }
624                         }
625                 }
626         },
628         simulate: function( type, elem, event, bubble ) {
629                 // Piggyback on a donor event to simulate a different one.
630                 // Fake originalEvent to avoid donor's stopPropagation, but if the
631                 // simulated event prevents default then we do the same on the donor.
632                 var e = jQuery.extend(
633                         new jQuery.Event(),
634                         event,
635                         {
636                                 type: type,
637                                 isSimulated: true,
638                                 originalEvent: {}
639                         }
640                 );
641                 if ( bubble ) {
642                         jQuery.event.trigger( e, null, elem );
643                 } else {
644                         jQuery.event.dispatch.call( elem, e );
645                 }
646                 if ( e.isDefaultPrevented() ) {
647                         event.preventDefault();
648                 }
649         }
652 jQuery.removeEvent = document.removeEventListener ?
653         function( elem, type, handle ) {
654                 if ( elem.removeEventListener ) {
655                         elem.removeEventListener( type, handle, false );
656                 }
657         } :
658         function( elem, type, handle ) {
659                 var name = "on" + type;
661                 if ( elem.detachEvent ) {
663                         // #8545, #7054, preventing memory leaks for custom events in IE6-8
664                         // detachEvent needed property on element, by name of that event, to properly expose it to GC
665                         if ( typeof elem[ name ] === strundefined ) {
666                                 elem[ name ] = null;
667                         }
669                         elem.detachEvent( name, handle );
670                 }
671         };
673 jQuery.Event = function( src, props ) {
674         // Allow instantiation without the 'new' keyword
675         if ( !(this instanceof jQuery.Event) ) {
676                 return new jQuery.Event( src, props );
677         }
679         // Event object
680         if ( src && src.type ) {
681                 this.originalEvent = src;
682                 this.type = src.type;
684                 // Events bubbling up the document may have been marked as prevented
685                 // by a handler lower down the tree; reflect the correct value.
686                 this.isDefaultPrevented = src.defaultPrevented ||
687                                 src.defaultPrevented === undefined &&
688                                 // Support: IE < 9, Android < 4.0
689                                 src.returnValue === false ?
690                         returnTrue :
691                         returnFalse;
693         // Event type
694         } else {
695                 this.type = src;
696         }
698         // Put explicitly provided properties onto the event object
699         if ( props ) {
700                 jQuery.extend( this, props );
701         }
703         // Create a timestamp if incoming event doesn't have one
704         this.timeStamp = src && src.timeStamp || jQuery.now();
706         // Mark it as fixed
707         this[ jQuery.expando ] = true;
710 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
711 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
712 jQuery.Event.prototype = {
713         isDefaultPrevented: returnFalse,
714         isPropagationStopped: returnFalse,
715         isImmediatePropagationStopped: returnFalse,
717         preventDefault: function() {
718                 var e = this.originalEvent;
720                 this.isDefaultPrevented = returnTrue;
721                 if ( !e ) {
722                         return;
723                 }
725                 // If preventDefault exists, run it on the original event
726                 if ( e.preventDefault ) {
727                         e.preventDefault();
729                 // Support: IE
730                 // Otherwise set the returnValue property of the original event to false
731                 } else {
732                         e.returnValue = false;
733                 }
734         },
735         stopPropagation: function() {
736                 var e = this.originalEvent;
738                 this.isPropagationStopped = returnTrue;
739                 if ( !e ) {
740                         return;
741                 }
742                 // If stopPropagation exists, run it on the original event
743                 if ( e.stopPropagation ) {
744                         e.stopPropagation();
745                 }
747                 // Support: IE
748                 // Set the cancelBubble property of the original event to true
749                 e.cancelBubble = true;
750         },
751         stopImmediatePropagation: function() {
752                 var e = this.originalEvent;
754                 this.isImmediatePropagationStopped = returnTrue;
756                 if ( e && e.stopImmediatePropagation ) {
757                         e.stopImmediatePropagation();
758                 }
760                 this.stopPropagation();
761         }
764 // Create mouseenter/leave events using mouseover/out and event-time checks
765 jQuery.each({
766         mouseenter: "mouseover",
767         mouseleave: "mouseout",
768         pointerenter: "pointerover",
769         pointerleave: "pointerout"
770 }, function( orig, fix ) {
771         jQuery.event.special[ orig ] = {
772                 delegateType: fix,
773                 bindType: fix,
775                 handle: function( event ) {
776                         var ret,
777                                 target = this,
778                                 related = event.relatedTarget,
779                                 handleObj = event.handleObj;
781                         // For mousenter/leave call the handler if related is outside the target.
782                         // NB: No relatedTarget if the mouse left/entered the browser window
783                         if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
784                                 event.type = handleObj.origType;
785                                 ret = handleObj.handler.apply( this, arguments );
786                                 event.type = fix;
787                         }
788                         return ret;
789                 }
790         };
793 // IE submit delegation
794 if ( !support.submitBubbles ) {
796         jQuery.event.special.submit = {
797                 setup: function() {
798                         // Only need this for delegated form submit events
799                         if ( jQuery.nodeName( this, "form" ) ) {
800                                 return false;
801                         }
803                         // Lazy-add a submit handler when a descendant form may potentially be submitted
804                         jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
805                                 // Node name check avoids a VML-related crash in IE (#9807)
806                                 var elem = e.target,
807                                         form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
808                                 if ( form && !jQuery._data( form, "submitBubbles" ) ) {
809                                         jQuery.event.add( form, "submit._submit", function( event ) {
810                                                 event._submit_bubble = true;
811                                         });
812                                         jQuery._data( form, "submitBubbles", true );
813                                 }
814                         });
815                         // return undefined since we don't need an event listener
816                 },
818                 postDispatch: function( event ) {
819                         // If form was submitted by the user, bubble the event up the tree
820                         if ( event._submit_bubble ) {
821                                 delete event._submit_bubble;
822                                 if ( this.parentNode && !event.isTrigger ) {
823                                         jQuery.event.simulate( "submit", this.parentNode, event, true );
824                                 }
825                         }
826                 },
828                 teardown: function() {
829                         // Only need this for delegated form submit events
830                         if ( jQuery.nodeName( this, "form" ) ) {
831                                 return false;
832                         }
834                         // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
835                         jQuery.event.remove( this, "._submit" );
836                 }
837         };
840 // IE change delegation and checkbox/radio fix
841 if ( !support.changeBubbles ) {
843         jQuery.event.special.change = {
845                 setup: function() {
847                         if ( rformElems.test( this.nodeName ) ) {
848                                 // IE doesn't fire change on a check/radio until blur; trigger it on click
849                                 // after a propertychange. Eat the blur-change in special.change.handle.
850                                 // This still fires onchange a second time for check/radio after blur.
851                                 if ( this.type === "checkbox" || this.type === "radio" ) {
852                                         jQuery.event.add( this, "propertychange._change", function( event ) {
853                                                 if ( event.originalEvent.propertyName === "checked" ) {
854                                                         this._just_changed = true;
855                                                 }
856                                         });
857                                         jQuery.event.add( this, "click._change", function( event ) {
858                                                 if ( this._just_changed && !event.isTrigger ) {
859                                                         this._just_changed = false;
860                                                 }
861                                                 // Allow triggered, simulated change events (#11500)
862                                                 jQuery.event.simulate( "change", this, event, true );
863                                         });
864                                 }
865                                 return false;
866                         }
867                         // Delegated event; lazy-add a change handler on descendant inputs
868                         jQuery.event.add( this, "beforeactivate._change", function( e ) {
869                                 var elem = e.target;
871                                 if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
872                                         jQuery.event.add( elem, "change._change", function( event ) {
873                                                 if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
874                                                         jQuery.event.simulate( "change", this.parentNode, event, true );
875                                                 }
876                                         });
877                                         jQuery._data( elem, "changeBubbles", true );
878                                 }
879                         });
880                 },
882                 handle: function( event ) {
883                         var elem = event.target;
885                         // Swallow native change events from checkbox/radio, we already triggered them above
886                         if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
887                                 return event.handleObj.handler.apply( this, arguments );
888                         }
889                 },
891                 teardown: function() {
892                         jQuery.event.remove( this, "._change" );
894                         return !rformElems.test( this.nodeName );
895                 }
896         };
899 // Create "bubbling" focus and blur events
900 if ( !support.focusinBubbles ) {
901         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
903                 // Attach a single capturing handler on the document while someone wants focusin/focusout
904                 var handler = function( event ) {
905                                 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
906                         };
908                 jQuery.event.special[ fix ] = {
909                         setup: function() {
910                                 var doc = this.ownerDocument || this,
911                                         attaches = jQuery._data( doc, fix );
913                                 if ( !attaches ) {
914                                         doc.addEventListener( orig, handler, true );
915                                 }
916                                 jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
917                         },
918                         teardown: function() {
919                                 var doc = this.ownerDocument || this,
920                                         attaches = jQuery._data( doc, fix ) - 1;
922                                 if ( !attaches ) {
923                                         doc.removeEventListener( orig, handler, true );
924                                         jQuery._removeData( doc, fix );
925                                 } else {
926                                         jQuery._data( doc, fix, attaches );
927                                 }
928                         }
929                 };
930         });
933 jQuery.fn.extend({
935         on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
936                 var type, origFn;
938                 // Types can be a map of types/handlers
939                 if ( typeof types === "object" ) {
940                         // ( types-Object, selector, data )
941                         if ( typeof selector !== "string" ) {
942                                 // ( types-Object, data )
943                                 data = data || selector;
944                                 selector = undefined;
945                         }
946                         for ( type in types ) {
947                                 this.on( type, selector, data, types[ type ], one );
948                         }
949                         return this;
950                 }
952                 if ( data == null && fn == null ) {
953                         // ( types, fn )
954                         fn = selector;
955                         data = selector = undefined;
956                 } else if ( fn == null ) {
957                         if ( typeof selector === "string" ) {
958                                 // ( types, selector, fn )
959                                 fn = data;
960                                 data = undefined;
961                         } else {
962                                 // ( types, data, fn )
963                                 fn = data;
964                                 data = selector;
965                                 selector = undefined;
966                         }
967                 }
968                 if ( fn === false ) {
969                         fn = returnFalse;
970                 } else if ( !fn ) {
971                         return this;
972                 }
974                 if ( one === 1 ) {
975                         origFn = fn;
976                         fn = function( event ) {
977                                 // Can use an empty set, since event contains the info
978                                 jQuery().off( event );
979                                 return origFn.apply( this, arguments );
980                         };
981                         // Use same guid so caller can remove using origFn
982                         fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
983                 }
984                 return this.each( function() {
985                         jQuery.event.add( this, types, fn, data, selector );
986                 });
987         },
988         one: function( types, selector, data, fn ) {
989                 return this.on( types, selector, data, fn, 1 );
990         },
991         off: function( types, selector, fn ) {
992                 var handleObj, type;
993                 if ( types && types.preventDefault && types.handleObj ) {
994                         // ( event )  dispatched jQuery.Event
995                         handleObj = types.handleObj;
996                         jQuery( types.delegateTarget ).off(
997                                 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
998                                 handleObj.selector,
999                                 handleObj.handler
1000                         );
1001                         return this;
1002                 }
1003                 if ( typeof types === "object" ) {
1004                         // ( types-object [, selector] )
1005                         for ( type in types ) {
1006                                 this.off( type, selector, types[ type ] );
1007                         }
1008                         return this;
1009                 }
1010                 if ( selector === false || typeof selector === "function" ) {
1011                         // ( types [, fn] )
1012                         fn = selector;
1013                         selector = undefined;
1014                 }
1015                 if ( fn === false ) {
1016                         fn = returnFalse;
1017                 }
1018                 return this.each(function() {
1019                         jQuery.event.remove( this, types, fn, selector );
1020                 });
1021         },
1023         trigger: function( type, data ) {
1024                 return this.each(function() {
1025                         jQuery.event.trigger( type, data, this );
1026                 });
1027         },
1028         triggerHandler: function( type, data ) {
1029                 var elem = this[0];
1030                 if ( elem ) {
1031                         return jQuery.event.trigger( type, data, elem, true );
1032                 }
1033         }
1036 return jQuery;