11import jQuery from "./core.js" ;
2- import document from "./var/document.js" ;
32import documentElement from "./var/documentElement.js" ;
43import rnothtmlwhite from "./var/rnothtmlwhite.js" ;
54import rcheckableType from "./var/rcheckableType.js" ;
65import slice from "./var/slice.js" ;
6+ import isIE from "./var/isIE.js" ;
77import acceptData from "./data/var/acceptData.js" ;
88import dataPriv from "./data/var/dataPriv.js" ;
99import nodeName from "./core/nodeName.js" ;
@@ -21,16 +21,6 @@ function returnFalse() {
2121 return false ;
2222}
2323
24- // Support: IE <=9 - 11+
25- // focus() and blur() are asynchronous, except when they are no-op.
26- // So expect focus to be synchronous when the element is already active,
27- // and blur to be synchronous when the element is not already active.
28- // (focus and blur are always synchronous in other supported browsers,
29- // this just defines when we can count on it).
30- function expectSync ( elem , type ) {
31- return ( elem === document . activeElement ) === ( type === "focus" ) ;
32- }
33-
3424function on ( elem , types , selector , data , fn , one ) {
3525 var origFn , type ;
3626
@@ -459,7 +449,7 @@ jQuery.event = {
459449 el . click && nodeName ( el , "input" ) ) {
460450
461451 // dataPriv.set( el, "click", ... )
462- leverageNative ( el , "click" , returnTrue ) ;
452+ leverageNative ( el , "click" , true ) ;
463453 }
464454
465455 // Return false to allow normal processing in the caller
@@ -511,10 +501,10 @@ jQuery.event = {
511501// synthetic events by interrupting progress until reinvoked in response to
512502// *native* events that it fires directly, ensuring that state changes have
513503// already occurred before other listeners are invoked.
514- function leverageNative ( el , type , expectSync ) {
504+ function leverageNative ( el , type , isSetup ) {
515505
516- // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
517- if ( ! expectSync ) {
506+ // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add
507+ if ( ! isSetup ) {
518508 if ( dataPriv . get ( el , type ) === undefined ) {
519509 jQuery . event . add ( el , type , returnTrue ) ;
520510 }
@@ -526,15 +516,13 @@ function leverageNative( el, type, expectSync ) {
526516 jQuery . event . add ( el , type , {
527517 namespace : false ,
528518 handler : function ( event ) {
529- var notAsync , result ,
519+ var result ,
530520 saved = dataPriv . get ( this , type ) ;
531521
532522 if ( ( event . isTrigger & 1 ) && this [ type ] ) {
533523
534524 // Interrupt processing of the outer synthetic .trigger()ed event
535- // Saved data should be false in such cases, but might be a leftover capture object
536- // from an async native handler (gh-4350)
537- if ( ! saved . length ) {
525+ if ( ! saved ) {
538526
539527 // Store arguments for use when handling the inner native event
540528 // There will always be at least one argument (an event object), so this array
@@ -543,28 +531,17 @@ function leverageNative( el, type, expectSync ) {
543531 dataPriv . set ( this , type , saved ) ;
544532
545533 // Trigger the native event and capture its result
546- // Support: IE <=9 - 11+
547- // focus() and blur() are asynchronous
548- notAsync = expectSync ( this , type ) ;
549534 this [ type ] ( ) ;
550535 result = dataPriv . get ( this , type ) ;
551- if ( saved !== result || notAsync ) {
552- dataPriv . set ( this , type , false ) ;
553- } else {
554- result = { } ;
555- }
536+ dataPriv . set ( this , type , false ) ;
537+
556538 if ( saved !== result ) {
557539
558540 // Cancel the outer synthetic event
559541 event . stopImmediatePropagation ( ) ;
560542 event . preventDefault ( ) ;
561543
562- // Support: Chrome 86+
563- // In Chrome, if an element having a focusout handler is blurred by
564- // clicking outside of it, it invokes the handler synchronously. If
565- // that handler calls `.remove()` on the element, the data is cleared,
566- // leaving `result` undefined. We need to guard against this.
567- return result && result . value ;
544+ return result ;
568545 }
569546
570547 // If this is an inner synthetic event for an event with a bubbling surrogate
@@ -582,16 +559,11 @@ function leverageNative( el, type, expectSync ) {
582559 } else if ( saved . length ) {
583560
584561 // ...and capture the result
585- dataPriv . set ( this , type , {
586- value : jQuery . event . trigger (
587-
588- // Support: IE <=9 - 11+
589- // Extend with the prototype to reset the above stopImmediatePropagation()
590- jQuery . extend ( saved [ 0 ] , jQuery . Event . prototype ) ,
591- saved . slice ( 1 ) ,
592- this
593- )
594- } ) ;
562+ dataPriv . set ( this , type , jQuery . event . trigger (
563+ saved [ 0 ] ,
564+ saved . slice ( 1 ) ,
565+ this
566+ ) ) ;
595567
596568 // Abort handling of the native event
597569 event . stopImmediatePropagation ( ) ;
@@ -724,6 +696,29 @@ jQuery.each( {
724696} , jQuery . event . addProp ) ;
725697
726698jQuery . each ( { focus : "focusin" , blur : "focusout" } , function ( type , delegateType ) {
699+
700+ // Support: IE 11+
701+ // Attach a single focusin/focusout handler on the document while someone wants focus/blur.
702+ // This is because the former are synchronous in IE while the latter are async. In other
703+ // browsers, all those handlers are invoked synchronously.
704+ function focusMappedHandler ( nativeEvent ) {
705+
706+ // `eventHandle` would already wrap the event, but we need to change the `type` here.
707+ var event = jQuery . event . fix ( nativeEvent ) ;
708+ event . type = nativeEvent . type === "focusin" ? "focus" : "blur" ;
709+ event . isSimulated = true ;
710+
711+ // focus/blur don't bubble while focusin/focusout do; simulate the former by only
712+ // invoking the handler at the lower level.
713+ if ( event . target === event . currentTarget ) {
714+
715+ // The setup part calls `leverageNative`, which, in turn, calls
716+ // `jQuery.event.add`, so event handle will already have been set
717+ // by this point.
718+ dataPriv . get ( this , "handle" ) ( event ) ;
719+ }
720+ }
721+
727722 jQuery . event . special [ type ] = {
728723
729724 // Utilize native event if possible so blur/focus sequence is correct
@@ -732,10 +727,15 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
732727 // Claim the first handler
733728 // dataPriv.set( this, "focus", ... )
734729 // dataPriv.set( this, "blur", ... )
735- leverageNative ( this , type , expectSync ) ;
730+ leverageNative ( this , type , true ) ;
731+
732+ if ( isIE ) {
733+ this . addEventListener ( delegateType , focusMappedHandler ) ;
734+ } else {
736735
737- // Return false to allow normal processing in the caller
738- return false ;
736+ // Return false to allow normal processing in the caller
737+ return false ;
738+ }
739739 } ,
740740 trigger : function ( ) {
741741
@@ -746,6 +746,16 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
746746 return true ;
747747 } ,
748748
749+ teardown : function ( ) {
750+ if ( isIE ) {
751+ this . removeEventListener ( delegateType , focusMappedHandler ) ;
752+ } else {
753+
754+ // Return false to indicate standard teardown should be applied
755+ return false ;
756+ }
757+ } ,
758+
749759 // Suppress native focus or blur if we're currently inside
750760 // a leveraged native-event stack
751761 _default : function ( event ) {
0 commit comments