1 import jQuery from "./core.js";
2 import documentElement from "./var/documentElement.js";
3 import rnothtmlwhite from "./var/rnothtmlwhite.js";
4 import rcheckableType from "./var/rcheckableType.js";
5 import slice from "./var/slice.js";
6 import isIE from "./var/isIE.js";
7 import acceptData from "./data/var/acceptData.js";
8 import dataPriv from "./data/var/dataPriv.js";
9 import nodeName from "./core/nodeName.js";
11 import "./core/init.js";
12 import "./selector.js";
14 var rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
16 function returnTrue() {
20 function returnFalse() {
24 function on( elem, types, selector, data, fn, one ) {
27 // Types can be a map of types/handlers
28 if ( typeof types === "object" ) {
30 // ( types-Object, selector, data )
31 if ( typeof selector !== "string" ) {
33 // ( types-Object, data )
34 data = data || selector;
37 for ( type in types ) {
38 on( elem, type, selector, data, types[ type ], one );
43 if ( data == null && fn == null ) {
47 data = selector = undefined;
48 } else if ( fn == null ) {
49 if ( typeof selector === "string" ) {
51 // ( types, selector, fn )
56 // ( types, data, fn )
70 fn = function( event ) {
72 // Can use an empty set, since event contains the info
73 jQuery().off( event );
74 return origFn.apply( this, arguments );
77 // Use same guid so caller can remove using origFn
78 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
80 return elem.each( function() {
81 jQuery.event.add( this, types, fn, data, selector );
86 * Helper functions for managing events -- not part of the public interface.
87 * Props to Dean Edwards' addEvent library for many of the ideas.
91 add: function( elem, types, handler, data, selector ) {
93 var handleObjIn, eventHandle, tmp,
95 special, handlers, type, namespaces, origType,
96 elemData = dataPriv.get( elem );
98 // Only attach events to objects that accept data
99 if ( !acceptData( elem ) ) {
103 // Caller can pass in an object of custom data in lieu of the handler
104 if ( handler.handler ) {
105 handleObjIn = handler;
106 handler = handleObjIn.handler;
107 selector = handleObjIn.selector;
110 // Ensure that invalid selectors throw exceptions at attach time
111 // Evaluate against documentElement in case elem is a non-element node (e.g., document)
113 jQuery.find.matchesSelector( documentElement, selector );
116 // Make sure that the handler has a unique ID, used to find/remove it later
117 if ( !handler.guid ) {
118 handler.guid = jQuery.guid++;
121 // Init the element's event structure and main handler, if this is the first
122 if ( !( events = elemData.events ) ) {
123 events = elemData.events = Object.create( null );
125 if ( !( eventHandle = elemData.handle ) ) {
126 eventHandle = elemData.handle = function( e ) {
128 // Discard the second event of a jQuery.event.trigger() and
129 // when an event is called after a page has unloaded
130 return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
131 jQuery.event.dispatch.apply( elem, arguments ) : undefined;
135 // Handle multiple events separated by a space
136 types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
139 tmp = rtypenamespace.exec( types[ t ] ) || [];
140 type = origType = tmp[ 1 ];
141 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
143 // There *must* be a type, no attaching namespace-only handlers
148 // If event changes its type, use the special event handlers for the changed type
149 special = jQuery.event.special[ type ] || {};
151 // If selector defined, determine special event api type, otherwise given type
152 type = ( selector ? special.delegateType : special.bindType ) || type;
154 // Update special based on newly reset type
155 special = jQuery.event.special[ type ] || {};
157 // handleObj is passed to all event handlers
158 handleObj = jQuery.extend( {
165 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
166 namespace: namespaces.join( "." )
169 // Init the event handler queue if we're the first
170 if ( !( handlers = events[ type ] ) ) {
171 handlers = events[ type ] = [];
172 handlers.delegateCount = 0;
174 // Only use addEventListener if the special events handler returns false
175 if ( !special.setup ||
176 special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
178 if ( elem.addEventListener ) {
179 elem.addEventListener( type, eventHandle );
185 special.add.call( elem, handleObj );
187 if ( !handleObj.handler.guid ) {
188 handleObj.handler.guid = handler.guid;
192 // Add to the element's handler list, delegates in front
194 handlers.splice( handlers.delegateCount++, 0, handleObj );
196 handlers.push( handleObj );
202 // Detach an event or set of events from an element
203 remove: function( elem, types, handler, selector, mappedTypes ) {
205 var j, origCount, tmp,
206 events, t, handleObj,
207 special, handlers, type, namespaces, origType,
208 elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
210 if ( !elemData || !( events = elemData.events ) ) {
214 // Once for each type.namespace in types; type may be omitted
215 types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
218 tmp = rtypenamespace.exec( types[ t ] ) || [];
219 type = origType = tmp[ 1 ];
220 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
222 // Unbind all events (on this namespace, if provided) for the element
224 for ( type in events ) {
225 jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
230 special = jQuery.event.special[ type ] || {};
231 type = ( selector ? special.delegateType : special.bindType ) || type;
232 handlers = events[ type ] || [];
234 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
236 // Remove matching events
237 origCount = j = handlers.length;
239 handleObj = handlers[ j ];
241 if ( ( mappedTypes || origType === handleObj.origType ) &&
242 ( !handler || handler.guid === handleObj.guid ) &&
243 ( !tmp || tmp.test( handleObj.namespace ) ) &&
244 ( !selector || selector === handleObj.selector ||
245 selector === "**" && handleObj.selector ) ) {
246 handlers.splice( j, 1 );
248 if ( handleObj.selector ) {
249 handlers.delegateCount--;
251 if ( special.remove ) {
252 special.remove.call( elem, handleObj );
257 // Remove generic event handler if we removed something and no more handlers exist
258 // (avoids potential for endless recursion during removal of special event handlers)
259 if ( origCount && !handlers.length ) {
260 if ( !special.teardown ||
261 special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
263 jQuery.removeEvent( elem, type, elemData.handle );
266 delete events[ type ];
270 // Remove data and the expando if it's no longer used
271 if ( jQuery.isEmptyObject( events ) ) {
272 dataPriv.remove( elem, "handle events" );
276 dispatch: function( nativeEvent ) {
278 var i, j, ret, matched, handleObj, handlerQueue,
279 args = new Array( arguments.length ),
281 // Make a writable jQuery.Event from the native event object
282 event = jQuery.event.fix( nativeEvent ),
285 dataPriv.get( this, "events" ) || Object.create( null )
286 )[ event.type ] || [],
287 special = jQuery.event.special[ event.type ] || {};
289 // Use the fix-ed jQuery.Event rather than the (read-only) native event
292 for ( i = 1; i < arguments.length; i++ ) {
293 args[ i ] = arguments[ i ];
296 event.delegateTarget = this;
298 // Call the preDispatch hook for the mapped type, and let it bail if desired
299 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
303 // Determine handlers
304 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
306 // Run delegates first; they may want to stop propagation beneath us
308 while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
309 event.currentTarget = matched.elem;
312 while ( ( handleObj = matched.handlers[ j++ ] ) &&
313 !event.isImmediatePropagationStopped() ) {
315 // If the event is namespaced, then each handler is only invoked if it is
316 // specially universal or its namespaces are a superset of the event's.
317 if ( !event.rnamespace || handleObj.namespace === false ||
318 event.rnamespace.test( handleObj.namespace ) ) {
320 event.handleObj = handleObj;
321 event.data = handleObj.data;
323 ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
324 handleObj.handler ).apply( matched.elem, args );
326 if ( ret !== undefined ) {
327 if ( ( event.result = ret ) === false ) {
328 event.preventDefault();
329 event.stopPropagation();
336 // Call the postDispatch hook for the mapped type
337 if ( special.postDispatch ) {
338 special.postDispatch.call( this, event );
344 handlers: function( event, handlers ) {
345 var i, handleObj, sel, matchedHandlers, matchedSelectors,
347 delegateCount = handlers.delegateCount,
350 // Find delegate handlers
351 if ( delegateCount &&
353 // Support: Firefox <=42 - 66+
354 // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
355 // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
357 // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
358 !( event.type === "click" && event.button >= 1 ) ) {
360 for ( ; cur !== this; cur = cur.parentNode || this ) {
362 // Don't check non-elements (trac-13208)
363 // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764)
364 if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
365 matchedHandlers = [];
366 matchedSelectors = {};
367 for ( i = 0; i < delegateCount; i++ ) {
368 handleObj = handlers[ i ];
370 // Don't conflict with Object.prototype properties (trac-13203)
371 sel = handleObj.selector + " ";
373 if ( matchedSelectors[ sel ] === undefined ) {
374 matchedSelectors[ sel ] = handleObj.needsContext ?
375 jQuery( sel, this ).index( cur ) > -1 :
376 jQuery.find( sel, this, null, [ cur ] ).length;
378 if ( matchedSelectors[ sel ] ) {
379 matchedHandlers.push( handleObj );
382 if ( matchedHandlers.length ) {
383 handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
389 // Add the remaining (directly-bound) handlers
391 if ( delegateCount < handlers.length ) {
392 handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
398 addProp: function( name, hook ) {
399 Object.defineProperty( jQuery.Event.prototype, name, {
403 get: typeof hook === "function" ?
405 if ( this.originalEvent ) {
406 return hook( this.originalEvent );
410 if ( this.originalEvent ) {
411 return this.originalEvent[ name ];
415 set: function( value ) {
416 Object.defineProperty( this, name, {
426 fix: function( originalEvent ) {
427 return originalEvent[ jQuery.expando ] ?
429 new jQuery.Event( originalEvent );
432 special: jQuery.extend( Object.create( null ), {
435 // Prevent triggered image.load events from bubbling to window.load
440 // Utilize native event to ensure correct state for checkable inputs
441 setup: function( data ) {
443 // For mutual compressibility with _default, replace `this` access with a local var.
444 // `|| data` is dead code meant only to preserve the variable through minification.
445 var el = this || data;
447 // Claim the first handler
448 if ( rcheckableType.test( el.type ) &&
449 el.click && nodeName( el, "input" ) ) {
451 // dataPriv.set( el, "click", ... )
452 leverageNative( el, "click", true );
455 // Return false to allow normal processing in the caller
458 trigger: function( data ) {
460 // For mutual compressibility with _default, replace `this` access with a local var.
461 // `|| data` is dead code meant only to preserve the variable through minification.
462 var el = this || data;
464 // Force setup before triggering a click
465 if ( rcheckableType.test( el.type ) &&
466 el.click && nodeName( el, "input" ) ) {
468 leverageNative( el, "click" );
471 // Return non-false to allow normal event-path propagation
475 // For cross-browser consistency, suppress native .click() on links
476 // Also prevent it if we're currently inside a leveraged native-event stack
477 _default: function( event ) {
478 var target = event.target;
479 return rcheckableType.test( target.type ) &&
480 target.click && nodeName( target, "input" ) &&
481 dataPriv.get( target, "click" ) ||
482 nodeName( target, "a" );
487 postDispatch: function( event ) {
489 // Support: Chrome <=73+
490 // Chrome doesn't alert on `event.preventDefault()`
491 // as the standard mandates.
492 if ( event.result !== undefined && event.originalEvent ) {
493 event.originalEvent.returnValue = event.result;
500 // Ensure the presence of an event listener that handles manually-triggered
501 // synthetic events by interrupting progress until reinvoked in response to
502 // *native* events that it fires directly, ensuring that state changes have
503 // already occurred before other listeners are invoked.
504 function leverageNative( el, type, isSetup ) {
506 // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add
508 if ( dataPriv.get( el, type ) === undefined ) {
509 jQuery.event.add( el, type, returnTrue );
514 // Register the controller as a special universal handler for all event namespaces
515 dataPriv.set( el, type, false );
516 jQuery.event.add( el, type, {
518 handler: function( event ) {
520 saved = dataPriv.get( this, type );
522 if ( ( event.isTrigger & 1 ) && this[ type ] ) {
524 // Interrupt processing of the outer synthetic .trigger()ed event
527 // Store arguments for use when handling the inner native event
528 // There will always be at least one argument (an event object), so this array
529 // will not be confused with a leftover capture object.
530 saved = slice.call( arguments );
531 dataPriv.set( this, type, saved );
533 // Trigger the native event and capture its result
535 result = dataPriv.get( this, type );
536 dataPriv.set( this, type, false );
538 if ( saved !== result ) {
540 // Cancel the outer synthetic event
541 event.stopImmediatePropagation();
542 event.preventDefault();
547 // If this is an inner synthetic event for an event with a bubbling surrogate
548 // (focus or blur), assume that the surrogate already propagated from triggering
549 // the native event and prevent that from happening again here.
550 // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
551 // bubbling surrogate propagates *after* the non-bubbling base), but that seems
552 // less bad than duplication.
553 } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
554 event.stopPropagation();
557 // If this is a native event triggered above, everything is now in order
558 // Fire an inner synthetic event with the original arguments
559 } else if ( saved ) {
561 // ...and capture the result
562 dataPriv.set( this, type, jQuery.event.trigger(
568 // Abort handling of the native event by all jQuery handlers while allowing
569 // native handlers on the same element to run. On target, this is achieved
570 // by stopping immediate propagation just on the jQuery event. However,
571 // the native event is re-wrapped by a jQuery one on each level of the
572 // propagation so the only way to stop it for jQuery is to stop it for
573 // everyone via native `stopPropagation()`. This is not a problem for
574 // focus/blur which don't bubble, but it does also stop click on checkboxes
575 // and radios. We accept this limitation.
576 event.stopPropagation();
577 event.isImmediatePropagationStopped = returnTrue;
583 jQuery.removeEvent = function( elem, type, handle ) {
585 // This "if" is needed for plain objects
586 if ( elem.removeEventListener ) {
587 elem.removeEventListener( type, handle );
591 jQuery.Event = function( src, props ) {
593 // Allow instantiation without the 'new' keyword
594 if ( !( this instanceof jQuery.Event ) ) {
595 return new jQuery.Event( src, props );
599 if ( src && src.type ) {
600 this.originalEvent = src;
601 this.type = src.type;
603 // Events bubbling up the document may have been marked as prevented
604 // by a handler lower down the tree; reflect the correct value.
605 this.isDefaultPrevented = src.defaultPrevented ?
609 // Create target properties
610 this.target = src.target;
611 this.currentTarget = src.currentTarget;
612 this.relatedTarget = src.relatedTarget;
619 // Put explicitly provided properties onto the event object
621 jQuery.extend( this, props );
624 // Create a timestamp if incoming event doesn't have one
625 this.timeStamp = src && src.timeStamp || Date.now();
628 this[ jQuery.expando ] = true;
631 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
632 // https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
633 jQuery.Event.prototype = {
634 constructor: jQuery.Event,
635 isDefaultPrevented: returnFalse,
636 isPropagationStopped: returnFalse,
637 isImmediatePropagationStopped: returnFalse,
640 preventDefault: function() {
641 var e = this.originalEvent;
643 this.isDefaultPrevented = returnTrue;
645 if ( e && !this.isSimulated ) {
649 stopPropagation: function() {
650 var e = this.originalEvent;
652 this.isPropagationStopped = returnTrue;
654 if ( e && !this.isSimulated ) {
658 stopImmediatePropagation: function() {
659 var e = this.originalEvent;
661 this.isImmediatePropagationStopped = returnTrue;
663 if ( e && !this.isSimulated ) {
664 e.stopImmediatePropagation();
667 this.stopPropagation();
671 // Includes all common event props including KeyEvent and MouseEvent specific props
676 changedTouches: true,
704 }, jQuery.event.addProp );
706 jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
709 // Attach a single focusin/focusout handler on the document while someone wants focus/blur.
710 // This is because the former are synchronous in IE while the latter are async. In other
711 // browsers, all those handlers are invoked synchronously.
712 function focusMappedHandler( nativeEvent ) {
714 // `eventHandle` would already wrap the event, but we need to change the `type` here.
715 var event = jQuery.event.fix( nativeEvent );
716 event.type = nativeEvent.type === "focusin" ? "focus" : "blur";
717 event.isSimulated = true;
719 // focus/blur don't bubble while focusin/focusout do; simulate the former by only
720 // invoking the handler at the lower level.
721 if ( event.target === event.currentTarget ) {
723 // The setup part calls `leverageNative`, which, in turn, calls
724 // `jQuery.event.add`, so event handle will already have been set
726 dataPriv.get( this, "handle" )( event );
730 jQuery.event.special[ type ] = {
732 // Utilize native event if possible so blur/focus sequence is correct
735 // Claim the first handler
736 // dataPriv.set( this, "focus", ... )
737 // dataPriv.set( this, "blur", ... )
738 leverageNative( this, type, true );
741 this.addEventListener( delegateType, focusMappedHandler );
744 // Return false to allow normal processing in the caller
748 trigger: function() {
750 // Force setup before trigger
751 leverageNative( this, type );
753 // Return non-false to allow normal event-path propagation
757 teardown: function() {
759 this.removeEventListener( delegateType, focusMappedHandler );
762 // Return false to indicate standard teardown should be applied
767 // Suppress native focus or blur if we're currently inside
768 // a leveraged native-event stack
769 _default: function( event ) {
770 return dataPriv.get( event.target, type );
773 delegateType: delegateType
777 // Create mouseenter/leave events using mouseover/out and event-time checks
778 // so that event delegation works in jQuery.
779 // Do the same for pointerenter/pointerleave and pointerover/pointerout
781 mouseenter: "mouseover",
782 mouseleave: "mouseout",
783 pointerenter: "pointerover",
784 pointerleave: "pointerout"
785 }, function( orig, fix ) {
786 jQuery.event.special[ orig ] = {
790 handle: function( event ) {
793 related = event.relatedTarget,
794 handleObj = event.handleObj;
796 // For mouseenter/leave call the handler if related is outside the target.
797 // NB: No relatedTarget if the mouse left/entered the browser window
798 if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
799 event.type = handleObj.origType;
800 ret = handleObj.handler.apply( this, arguments );
810 on: function( types, selector, data, fn ) {
811 return on( this, types, selector, data, fn );
813 one: function( types, selector, data, fn ) {
814 return on( this, types, selector, data, fn, 1 );
816 off: function( types, selector, fn ) {
818 if ( types && types.preventDefault && types.handleObj ) {
820 // ( event ) dispatched jQuery.Event
821 handleObj = types.handleObj;
822 jQuery( types.delegateTarget ).off(
823 handleObj.namespace ?
824 handleObj.origType + "." + handleObj.namespace :
831 if ( typeof types === "object" ) {
833 // ( types-object [, selector] )
834 for ( type in types ) {
835 this.off( type, selector, types[ type ] );
839 if ( selector === false || typeof selector === "function" ) {
843 selector = undefined;
845 if ( fn === false ) {
848 return this.each( function() {
849 jQuery.event.remove( this, types, fn, selector );
854 export default jQuery;