blob: 3ff11ad0be76da90c9c9c90351e02706aa6d454a [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001define( [
2 "./core",
3 "./var/document",
4 "./var/documentElement",
5 "./var/isFunction",
6 "./var/rnothtmlwhite",
7 "./var/rcheckableType",
8 "./var/slice",
9 "./data/var/dataPriv",
10 "./core/nodeName",
11
12 "./core/init",
13 "./selector"
14], function( jQuery, document, documentElement, isFunction, rnothtmlwhite,
15 rcheckableType, slice, dataPriv, nodeName ) {
16
17"use strict";
18
19var
20 rkeyEvent = /^key/,
21 rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
22 rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
23
24function returnTrue() {
25 return true;
26}
27
28function returnFalse() {
29 return false;
30}
31
32// Support: IE <=9 - 11+
33// focus() and blur() are asynchronous, except when they are no-op.
34// So expect focus to be synchronous when the element is already active,
35// and blur to be synchronous when the element is not already active.
36// (focus and blur are always synchronous in other supported browsers,
37// this just defines when we can count on it).
38function expectSync( elem, type ) {
39 return ( elem === safeActiveElement() ) === ( type === "focus" );
40}
41
42// Support: IE <=9 only
43// Accessing document.activeElement can throw unexpectedly
44// https://bugs.jquery.com/ticket/13393
45function safeActiveElement() {
46 try {
47 return document.activeElement;
48 } catch ( err ) { }
49}
50
51function on( elem, types, selector, data, fn, one ) {
52 var origFn, type;
53
54 // Types can be a map of types/handlers
55 if ( typeof types === "object" ) {
56
57 // ( types-Object, selector, data )
58 if ( typeof selector !== "string" ) {
59
60 // ( types-Object, data )
61 data = data || selector;
62 selector = undefined;
63 }
64 for ( type in types ) {
65 on( elem, type, selector, data, types[ type ], one );
66 }
67 return elem;
68 }
69
70 if ( data == null && fn == null ) {
71
72 // ( types, fn )
73 fn = selector;
74 data = selector = undefined;
75 } else if ( fn == null ) {
76 if ( typeof selector === "string" ) {
77
78 // ( types, selector, fn )
79 fn = data;
80 data = undefined;
81 } else {
82
83 // ( types, data, fn )
84 fn = data;
85 data = selector;
86 selector = undefined;
87 }
88 }
89 if ( fn === false ) {
90 fn = returnFalse;
91 } else if ( !fn ) {
92 return elem;
93 }
94
95 if ( one === 1 ) {
96 origFn = fn;
97 fn = function( event ) {
98
99 // Can use an empty set, since event contains the info
100 jQuery().off( event );
101 return origFn.apply( this, arguments );
102 };
103
104 // Use same guid so caller can remove using origFn
105 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
106 }
107 return elem.each( function() {
108 jQuery.event.add( this, types, fn, data, selector );
109 } );
110}
111
112/*
113 * Helper functions for managing events -- not part of the public interface.
114 * Props to Dean Edwards' addEvent library for many of the ideas.
115 */
116jQuery.event = {
117
118 global: {},
119
120 add: function( elem, types, handler, data, selector ) {
121
122 var handleObjIn, eventHandle, tmp,
123 events, t, handleObj,
124 special, handlers, type, namespaces, origType,
125 elemData = dataPriv.get( elem );
126
127 // Don't attach events to noData or text/comment nodes (but allow plain objects)
128 if ( !elemData ) {
129 return;
130 }
131
132 // Caller can pass in an object of custom data in lieu of the handler
133 if ( handler.handler ) {
134 handleObjIn = handler;
135 handler = handleObjIn.handler;
136 selector = handleObjIn.selector;
137 }
138
139 // Ensure that invalid selectors throw exceptions at attach time
140 // Evaluate against documentElement in case elem is a non-element node (e.g., document)
141 if ( selector ) {
142 jQuery.find.matchesSelector( documentElement, selector );
143 }
144
145 // Make sure that the handler has a unique ID, used to find/remove it later
146 if ( !handler.guid ) {
147 handler.guid = jQuery.guid++;
148 }
149
150 // Init the element's event structure and main handler, if this is the first
151 if ( !( events = elemData.events ) ) {
152 events = elemData.events = {};
153 }
154 if ( !( eventHandle = elemData.handle ) ) {
155 eventHandle = elemData.handle = function( e ) {
156
157 // Discard the second event of a jQuery.event.trigger() and
158 // when an event is called after a page has unloaded
159 return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
160 jQuery.event.dispatch.apply( elem, arguments ) : undefined;
161 };
162 }
163
164 // Handle multiple events separated by a space
165 types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
166 t = types.length;
167 while ( t-- ) {
168 tmp = rtypenamespace.exec( types[ t ] ) || [];
169 type = origType = tmp[ 1 ];
170 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
171
172 // There *must* be a type, no attaching namespace-only handlers
173 if ( !type ) {
174 continue;
175 }
176
177 // If event changes its type, use the special event handlers for the changed type
178 special = jQuery.event.special[ type ] || {};
179
180 // If selector defined, determine special event api type, otherwise given type
181 type = ( selector ? special.delegateType : special.bindType ) || type;
182
183 // Update special based on newly reset type
184 special = jQuery.event.special[ type ] || {};
185
186 // handleObj is passed to all event handlers
187 handleObj = jQuery.extend( {
188 type: type,
189 origType: origType,
190 data: data,
191 handler: handler,
192 guid: handler.guid,
193 selector: selector,
194 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
195 namespace: namespaces.join( "." )
196 }, handleObjIn );
197
198 // Init the event handler queue if we're the first
199 if ( !( handlers = events[ type ] ) ) {
200 handlers = events[ type ] = [];
201 handlers.delegateCount = 0;
202
203 // Only use addEventListener if the special events handler returns false
204 if ( !special.setup ||
205 special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
206
207 if ( elem.addEventListener ) {
208 elem.addEventListener( type, eventHandle );
209 }
210 }
211 }
212
213 if ( special.add ) {
214 special.add.call( elem, handleObj );
215
216 if ( !handleObj.handler.guid ) {
217 handleObj.handler.guid = handler.guid;
218 }
219 }
220
221 // Add to the element's handler list, delegates in front
222 if ( selector ) {
223 handlers.splice( handlers.delegateCount++, 0, handleObj );
224 } else {
225 handlers.push( handleObj );
226 }
227
228 // Keep track of which events have ever been used, for event optimization
229 jQuery.event.global[ type ] = true;
230 }
231
232 },
233
234 // Detach an event or set of events from an element
235 remove: function( elem, types, handler, selector, mappedTypes ) {
236
237 var j, origCount, tmp,
238 events, t, handleObj,
239 special, handlers, type, namespaces, origType,
240 elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
241
242 if ( !elemData || !( events = elemData.events ) ) {
243 return;
244 }
245
246 // Once for each type.namespace in types; type may be omitted
247 types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
248 t = types.length;
249 while ( t-- ) {
250 tmp = rtypenamespace.exec( types[ t ] ) || [];
251 type = origType = tmp[ 1 ];
252 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
253
254 // Unbind all events (on this namespace, if provided) for the element
255 if ( !type ) {
256 for ( type in events ) {
257 jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
258 }
259 continue;
260 }
261
262 special = jQuery.event.special[ type ] || {};
263 type = ( selector ? special.delegateType : special.bindType ) || type;
264 handlers = events[ type ] || [];
265 tmp = tmp[ 2 ] &&
266 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
267
268 // Remove matching events
269 origCount = j = handlers.length;
270 while ( j-- ) {
271 handleObj = handlers[ j ];
272
273 if ( ( mappedTypes || origType === handleObj.origType ) &&
274 ( !handler || handler.guid === handleObj.guid ) &&
275 ( !tmp || tmp.test( handleObj.namespace ) ) &&
276 ( !selector || selector === handleObj.selector ||
277 selector === "**" && handleObj.selector ) ) {
278 handlers.splice( j, 1 );
279
280 if ( handleObj.selector ) {
281 handlers.delegateCount--;
282 }
283 if ( special.remove ) {
284 special.remove.call( elem, handleObj );
285 }
286 }
287 }
288
289 // Remove generic event handler if we removed something and no more handlers exist
290 // (avoids potential for endless recursion during removal of special event handlers)
291 if ( origCount && !handlers.length ) {
292 if ( !special.teardown ||
293 special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
294
295 jQuery.removeEvent( elem, type, elemData.handle );
296 }
297
298 delete events[ type ];
299 }
300 }
301
302 // Remove data and the expando if it's no longer used
303 if ( jQuery.isEmptyObject( events ) ) {
304 dataPriv.remove( elem, "handle events" );
305 }
306 },
307
308 dispatch: function( nativeEvent ) {
309
310 // Make a writable jQuery.Event from the native event object
311 var event = jQuery.event.fix( nativeEvent );
312
313 var i, j, ret, matched, handleObj, handlerQueue,
314 args = new Array( arguments.length ),
315 handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
316 special = jQuery.event.special[ event.type ] || {};
317
318 // Use the fix-ed jQuery.Event rather than the (read-only) native event
319 args[ 0 ] = event;
320
321 for ( i = 1; i < arguments.length; i++ ) {
322 args[ i ] = arguments[ i ];
323 }
324
325 event.delegateTarget = this;
326
327 // Call the preDispatch hook for the mapped type, and let it bail if desired
328 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
329 return;
330 }
331
332 // Determine handlers
333 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
334
335 // Run delegates first; they may want to stop propagation beneath us
336 i = 0;
337 while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
338 event.currentTarget = matched.elem;
339
340 j = 0;
341 while ( ( handleObj = matched.handlers[ j++ ] ) &&
342 !event.isImmediatePropagationStopped() ) {
343
344 // If the event is namespaced, then each handler is only invoked if it is
345 // specially universal or its namespaces are a superset of the event's.
346 if ( !event.rnamespace || handleObj.namespace === false ||
347 event.rnamespace.test( handleObj.namespace ) ) {
348
349 event.handleObj = handleObj;
350 event.data = handleObj.data;
351
352 ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
353 handleObj.handler ).apply( matched.elem, args );
354
355 if ( ret !== undefined ) {
356 if ( ( event.result = ret ) === false ) {
357 event.preventDefault();
358 event.stopPropagation();
359 }
360 }
361 }
362 }
363 }
364
365 // Call the postDispatch hook for the mapped type
366 if ( special.postDispatch ) {
367 special.postDispatch.call( this, event );
368 }
369
370 return event.result;
371 },
372
373 handlers: function( event, handlers ) {
374 var i, handleObj, sel, matchedHandlers, matchedSelectors,
375 handlerQueue = [],
376 delegateCount = handlers.delegateCount,
377 cur = event.target;
378
379 // Find delegate handlers
380 if ( delegateCount &&
381
382 // Support: IE <=9
383 // Black-hole SVG <use> instance trees (trac-13180)
384 cur.nodeType &&
385
386 // Support: Firefox <=42
387 // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
388 // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
389 // Support: IE 11 only
390 // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
391 !( event.type === "click" && event.button >= 1 ) ) {
392
393 for ( ; cur !== this; cur = cur.parentNode || this ) {
394
395 // Don't check non-elements (#13208)
396 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
397 if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
398 matchedHandlers = [];
399 matchedSelectors = {};
400 for ( i = 0; i < delegateCount; i++ ) {
401 handleObj = handlers[ i ];
402
403 // Don't conflict with Object.prototype properties (#13203)
404 sel = handleObj.selector + " ";
405
406 if ( matchedSelectors[ sel ] === undefined ) {
407 matchedSelectors[ sel ] = handleObj.needsContext ?
408 jQuery( sel, this ).index( cur ) > -1 :
409 jQuery.find( sel, this, null, [ cur ] ).length;
410 }
411 if ( matchedSelectors[ sel ] ) {
412 matchedHandlers.push( handleObj );
413 }
414 }
415 if ( matchedHandlers.length ) {
416 handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
417 }
418 }
419 }
420 }
421
422 // Add the remaining (directly-bound) handlers
423 cur = this;
424 if ( delegateCount < handlers.length ) {
425 handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
426 }
427
428 return handlerQueue;
429 },
430
431 addProp: function( name, hook ) {
432 Object.defineProperty( jQuery.Event.prototype, name, {
433 enumerable: true,
434 configurable: true,
435
436 get: isFunction( hook ) ?
437 function() {
438 if ( this.originalEvent ) {
439 return hook( this.originalEvent );
440 }
441 } :
442 function() {
443 if ( this.originalEvent ) {
444 return this.originalEvent[ name ];
445 }
446 },
447
448 set: function( value ) {
449 Object.defineProperty( this, name, {
450 enumerable: true,
451 configurable: true,
452 writable: true,
453 value: value
454 } );
455 }
456 } );
457 },
458
459 fix: function( originalEvent ) {
460 return originalEvent[ jQuery.expando ] ?
461 originalEvent :
462 new jQuery.Event( originalEvent );
463 },
464
465 special: {
466 load: {
467
468 // Prevent triggered image.load events from bubbling to window.load
469 noBubble: true
470 },
471 click: {
472
473 // Utilize native event to ensure correct state for checkable inputs
474 setup: function( data ) {
475
476 // For mutual compressibility with _default, replace `this` access with a local var.
477 // `|| data` is dead code meant only to preserve the variable through minification.
478 var el = this || data;
479
480 // Claim the first handler
481 if ( rcheckableType.test( el.type ) &&
482 el.click && nodeName( el, "input" ) ) {
483
484 // dataPriv.set( el, "click", ... )
485 leverageNative( el, "click", returnTrue );
486 }
487
488 // Return false to allow normal processing in the caller
489 return false;
490 },
491 trigger: function( data ) {
492
493 // For mutual compressibility with _default, replace `this` access with a local var.
494 // `|| data` is dead code meant only to preserve the variable through minification.
495 var el = this || data;
496
497 // Force setup before triggering a click
498 if ( rcheckableType.test( el.type ) &&
499 el.click && nodeName( el, "input" ) ) {
500
501 leverageNative( el, "click" );
502 }
503
504 // Return non-false to allow normal event-path propagation
505 return true;
506 },
507
508 // For cross-browser consistency, suppress native .click() on links
509 // Also prevent it if we're currently inside a leveraged native-event stack
510 _default: function( event ) {
511 var target = event.target;
512 return rcheckableType.test( target.type ) &&
513 target.click && nodeName( target, "input" ) &&
514 dataPriv.get( target, "click" ) ||
515 nodeName( target, "a" );
516 }
517 },
518
519 beforeunload: {
520 postDispatch: function( event ) {
521
522 // Support: Firefox 20+
523 // Firefox doesn't alert if the returnValue field is not set.
524 if ( event.result !== undefined && event.originalEvent ) {
525 event.originalEvent.returnValue = event.result;
526 }
527 }
528 }
529 }
530};
531
532// Ensure the presence of an event listener that handles manually-triggered
533// synthetic events by interrupting progress until reinvoked in response to
534// *native* events that it fires directly, ensuring that state changes have
535// already occurred before other listeners are invoked.
536function leverageNative( el, type, expectSync ) {
537
538 // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
539 if ( !expectSync ) {
540 if ( dataPriv.get( el, type ) === undefined ) {
541 jQuery.event.add( el, type, returnTrue );
542 }
543 return;
544 }
545
546 // Register the controller as a special universal handler for all event namespaces
547 dataPriv.set( el, type, false );
548 jQuery.event.add( el, type, {
549 namespace: false,
550 handler: function( event ) {
551 var notAsync, result,
552 saved = dataPriv.get( this, type );
553
554 if ( ( event.isTrigger & 1 ) && this[ type ] ) {
555
556 // Interrupt processing of the outer synthetic .trigger()ed event
557 // Saved data should be false in such cases, but might be a leftover capture object
558 // from an async native handler (gh-4350)
559 if ( !saved.length ) {
560
561 // Store arguments for use when handling the inner native event
562 // There will always be at least one argument (an event object), so this array
563 // will not be confused with a leftover capture object.
564 saved = slice.call( arguments );
565 dataPriv.set( this, type, saved );
566
567 // Trigger the native event and capture its result
568 // Support: IE <=9 - 11+
569 // focus() and blur() are asynchronous
570 notAsync = expectSync( this, type );
571 this[ type ]();
572 result = dataPriv.get( this, type );
573 if ( saved !== result || notAsync ) {
574 dataPriv.set( this, type, false );
575 } else {
576 result = {};
577 }
578 if ( saved !== result ) {
579
580 // Cancel the outer synthetic event
581 event.stopImmediatePropagation();
582 event.preventDefault();
583 return result.value;
584 }
585
586 // If this is an inner synthetic event for an event with a bubbling surrogate
587 // (focus or blur), assume that the surrogate already propagated from triggering the
588 // native event and prevent that from happening again here.
589 // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
590 // bubbling surrogate propagates *after* the non-bubbling base), but that seems
591 // less bad than duplication.
592 } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
593 event.stopPropagation();
594 }
595
596 // If this is a native event triggered above, everything is now in order
597 // Fire an inner synthetic event with the original arguments
598 } else if ( saved.length ) {
599
600 // ...and capture the result
601 dataPriv.set( this, type, {
602 value: jQuery.event.trigger(
603
604 // Support: IE <=9 - 11+
605 // Extend with the prototype to reset the above stopImmediatePropagation()
606 jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
607 saved.slice( 1 ),
608 this
609 )
610 } );
611
612 // Abort handling of the native event
613 event.stopImmediatePropagation();
614 }
615 }
616 } );
617}
618
619jQuery.removeEvent = function( elem, type, handle ) {
620
621 // This "if" is needed for plain objects
622 if ( elem.removeEventListener ) {
623 elem.removeEventListener( type, handle );
624 }
625};
626
627jQuery.Event = function( src, props ) {
628
629 // Allow instantiation without the 'new' keyword
630 if ( !( this instanceof jQuery.Event ) ) {
631 return new jQuery.Event( src, props );
632 }
633
634 // Event object
635 if ( src && src.type ) {
636 this.originalEvent = src;
637 this.type = src.type;
638
639 // Events bubbling up the document may have been marked as prevented
640 // by a handler lower down the tree; reflect the correct value.
641 this.isDefaultPrevented = src.defaultPrevented ||
642 src.defaultPrevented === undefined &&
643
644 // Support: Android <=2.3 only
645 src.returnValue === false ?
646 returnTrue :
647 returnFalse;
648
649 // Create target properties
650 // Support: Safari <=6 - 7 only
651 // Target should not be a text node (#504, #13143)
652 this.target = ( src.target && src.target.nodeType === 3 ) ?
653 src.target.parentNode :
654 src.target;
655
656 this.currentTarget = src.currentTarget;
657 this.relatedTarget = src.relatedTarget;
658
659 // Event type
660 } else {
661 this.type = src;
662 }
663
664 // Put explicitly provided properties onto the event object
665 if ( props ) {
666 jQuery.extend( this, props );
667 }
668
669 // Create a timestamp if incoming event doesn't have one
670 this.timeStamp = src && src.timeStamp || Date.now();
671
672 // Mark it as fixed
673 this[ jQuery.expando ] = true;
674};
675
676// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
677// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
678jQuery.Event.prototype = {
679 constructor: jQuery.Event,
680 isDefaultPrevented: returnFalse,
681 isPropagationStopped: returnFalse,
682 isImmediatePropagationStopped: returnFalse,
683 isSimulated: false,
684
685 preventDefault: function() {
686 var e = this.originalEvent;
687
688 this.isDefaultPrevented = returnTrue;
689
690 if ( e && !this.isSimulated ) {
691 e.preventDefault();
692 }
693 },
694 stopPropagation: function() {
695 var e = this.originalEvent;
696
697 this.isPropagationStopped = returnTrue;
698
699 if ( e && !this.isSimulated ) {
700 e.stopPropagation();
701 }
702 },
703 stopImmediatePropagation: function() {
704 var e = this.originalEvent;
705
706 this.isImmediatePropagationStopped = returnTrue;
707
708 if ( e && !this.isSimulated ) {
709 e.stopImmediatePropagation();
710 }
711
712 this.stopPropagation();
713 }
714};
715
716// Includes all common event props including KeyEvent and MouseEvent specific props
717jQuery.each( {
718 altKey: true,
719 bubbles: true,
720 cancelable: true,
721 changedTouches: true,
722 ctrlKey: true,
723 detail: true,
724 eventPhase: true,
725 metaKey: true,
726 pageX: true,
727 pageY: true,
728 shiftKey: true,
729 view: true,
730 "char": true,
731 code: true,
732 charCode: true,
733 key: true,
734 keyCode: true,
735 button: true,
736 buttons: true,
737 clientX: true,
738 clientY: true,
739 offsetX: true,
740 offsetY: true,
741 pointerId: true,
742 pointerType: true,
743 screenX: true,
744 screenY: true,
745 targetTouches: true,
746 toElement: true,
747 touches: true,
748
749 which: function( event ) {
750 var button = event.button;
751
752 // Add which for key events
753 if ( event.which == null && rkeyEvent.test( event.type ) ) {
754 return event.charCode != null ? event.charCode : event.keyCode;
755 }
756
757 // Add which for click: 1 === left; 2 === middle; 3 === right
758 if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
759 if ( button & 1 ) {
760 return 1;
761 }
762
763 if ( button & 2 ) {
764 return 3;
765 }
766
767 if ( button & 4 ) {
768 return 2;
769 }
770
771 return 0;
772 }
773
774 return event.which;
775 }
776}, jQuery.event.addProp );
777
778jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
779 jQuery.event.special[ type ] = {
780
781 // Utilize native event if possible so blur/focus sequence is correct
782 setup: function() {
783
784 // Claim the first handler
785 // dataPriv.set( this, "focus", ... )
786 // dataPriv.set( this, "blur", ... )
787 leverageNative( this, type, expectSync );
788
789 // Return false to allow normal processing in the caller
790 return false;
791 },
792 trigger: function() {
793
794 // Force setup before trigger
795 leverageNative( this, type );
796
797 // Return non-false to allow normal event-path propagation
798 return true;
799 },
800
801 delegateType: delegateType
802 };
803} );
804
805// Create mouseenter/leave events using mouseover/out and event-time checks
806// so that event delegation works in jQuery.
807// Do the same for pointerenter/pointerleave and pointerover/pointerout
808//
809// Support: Safari 7 only
810// Safari sends mouseenter too often; see:
811// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
812// for the description of the bug (it existed in older Chrome versions as well).
813jQuery.each( {
814 mouseenter: "mouseover",
815 mouseleave: "mouseout",
816 pointerenter: "pointerover",
817 pointerleave: "pointerout"
818}, function( orig, fix ) {
819 jQuery.event.special[ orig ] = {
820 delegateType: fix,
821 bindType: fix,
822
823 handle: function( event ) {
824 var ret,
825 target = this,
826 related = event.relatedTarget,
827 handleObj = event.handleObj;
828
829 // For mouseenter/leave call the handler if related is outside the target.
830 // NB: No relatedTarget if the mouse left/entered the browser window
831 if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
832 event.type = handleObj.origType;
833 ret = handleObj.handler.apply( this, arguments );
834 event.type = fix;
835 }
836 return ret;
837 }
838 };
839} );
840
841jQuery.fn.extend( {
842
843 on: function( types, selector, data, fn ) {
844 return on( this, types, selector, data, fn );
845 },
846 one: function( types, selector, data, fn ) {
847 return on( this, types, selector, data, fn, 1 );
848 },
849 off: function( types, selector, fn ) {
850 var handleObj, type;
851 if ( types && types.preventDefault && types.handleObj ) {
852
853 // ( event ) dispatched jQuery.Event
854 handleObj = types.handleObj;
855 jQuery( types.delegateTarget ).off(
856 handleObj.namespace ?
857 handleObj.origType + "." + handleObj.namespace :
858 handleObj.origType,
859 handleObj.selector,
860 handleObj.handler
861 );
862 return this;
863 }
864 if ( typeof types === "object" ) {
865
866 // ( types-object [, selector] )
867 for ( type in types ) {
868 this.off( type, selector, types[ type ] );
869 }
870 return this;
871 }
872 if ( selector === false || typeof selector === "function" ) {
873
874 // ( types [, fn] )
875 fn = selector;
876 selector = undefined;
877 }
878 if ( fn === false ) {
879 fn = returnFalse;
880 }
881 return this.each( function() {
882 jQuery.event.remove( this, types, fn, selector );
883 } );
884 }
885} );
886
887return jQuery;
888} );