@@ -4,14 +4,15 @@ define( [
44 "./var/documentElement" ,
55 "./var/isFunction" ,
66 "./var/rnothtmlwhite" ,
7+ "./var/rcheckableType" ,
78 "./var/slice" ,
89 "./data/var/dataPriv" ,
910 "./core/nodeName" ,
1011
1112 "./core/init" ,
1213 "./selector"
1314] , function ( jQuery , document , documentElement , isFunction , rnothtmlwhite ,
14- slice , dataPriv , nodeName ) {
15+ rcheckableType , slice , dataPriv , nodeName ) {
1516
1617"use strict" ;
1718
@@ -329,9 +330,10 @@ jQuery.event = {
329330 while ( ( handleObj = matched . handlers [ j ++ ] ) &&
330331 ! event . isImmediatePropagationStopped ( ) ) {
331332
332- // Triggered event must either 1) have no namespace, or 2) have namespace(s)
333- // a subset or equal to those in the bound event (both can have no namespace).
334- if ( ! event . rnamespace || event . rnamespace . test ( handleObj . namespace ) ) {
333+ // If the event is namespaced, then each handler is only invoked if it is
334+ // specially universal or its namespaces are a superset of the event's.
335+ if ( ! event . rnamespace || handleObj . namespace === false ||
336+ event . rnamespace . test ( handleObj . namespace ) ) {
335337
336338 event . handleObj = handleObj ;
337339 event . data = handleObj . data ;
@@ -457,37 +459,101 @@ jQuery.event = {
457459 } ,
458460 focus : {
459461
460- // Fire native event if possible so blur/focus sequence is correct
462+ // Utilize native event if possible so blur/focus sequence is correct
463+ setup : function ( ) {
464+
465+ // Claim the first handler
466+ // dataPriv.set( this, "focus", ... )
467+ leverageNative ( this , "focus" , false , function ( el ) {
468+ return el !== safeActiveElement ( ) ;
469+ } ) ;
470+
471+ // Return false to allow normal processing in the caller
472+ return false ;
473+ } ,
461474 trigger : function ( ) {
462- if ( this !== safeActiveElement ( ) && this . focus ) {
463- this . focus ( ) ;
464- return false ;
465- }
475+
476+ // Force setup before trigger
477+ leverageNative ( this , "focus" , returnTrue ) ;
478+
479+ // Return non-false to allow normal event-path propagation
480+ return true ;
466481 } ,
482+
467483 delegateType : "focusin"
468484 } ,
469485 blur : {
486+
487+ // Utilize native event if possible so blur/focus sequence is correct
488+ setup : function ( ) {
489+
490+ // Claim the first handler
491+ // dataPriv.set( this, "blur", ... )
492+ leverageNative ( this , "blur" , false , function ( el ) {
493+ return el === safeActiveElement ( ) ;
494+ } ) ;
495+
496+ // Return false to allow normal processing in the caller
497+ return false ;
498+ } ,
470499 trigger : function ( ) {
471- if ( this === safeActiveElement ( ) && this . blur ) {
472- this . blur ( ) ;
473- return false ;
474- }
500+
501+ // Force setup before trigger
502+ leverageNative ( this , "blur" , returnTrue ) ;
503+
504+ // Return non-false to allow normal event-path propagation
505+ return true ;
475506 } ,
507+
476508 delegateType : "focusout"
477509 } ,
478510 click : {
479511
480- // For checkbox, fire native event so checked state will be right
481- trigger : function ( ) {
482- if ( this . type === "checkbox" && this . click && nodeName ( this , "input" ) ) {
483- this . click ( ) ;
484- return false ;
512+ // Utilize native event to ensure correct state for checkable inputs
513+ setup : function ( data ) {
514+
515+ // For mutual compressibility with _default, replace `this` access with a local var.
516+ // `|| data` is dead code meant only to preserve the variable through minification.
517+ var el = this || data ;
518+
519+ // Claim the first handler
520+ if ( rcheckableType . test ( el . type ) &&
521+ el . click && nodeName ( el , "input" ) &&
522+ dataPriv . get ( el , "click" ) === undefined ) {
523+
524+ // dataPriv.set( el, "click", ... )
525+ leverageNative ( el , "click" , false , returnFalse ) ;
485526 }
527+
528+ // Return false to allow normal processing in the caller
529+ return false ;
530+ } ,
531+ trigger : function ( data ) {
532+
533+ // For mutual compressibility with _default, replace `this` access with a local var.
534+ // `|| data` is dead code meant only to preserve the variable through minification.
535+ var el = this || data ;
536+
537+ // Force setup before triggering a click
538+ if ( rcheckableType . test ( el . type ) &&
539+ el . click && nodeName ( el , "input" ) &&
540+ dataPriv . get ( el , "click" ) === undefined ) {
541+
542+ leverageNative ( el , "click" , returnTrue ) ;
543+ }
544+
545+ // Return non-false to allow normal event-path propagation
546+ return true ;
486547 } ,
487548
488- // For cross-browser consistency, don't fire native .click() on links
549+ // For cross-browser consistency, suppress native .click() on links
550+ // Also prevent it if we're currently inside a leveraged native-event stack
489551 _default : function ( event ) {
490- return nodeName ( event . target , "a" ) ;
552+ var target = event . target ;
553+ return rcheckableType . test ( target . type ) &&
554+ target . click && nodeName ( target , "input" ) &&
555+ dataPriv . get ( target , "click" ) ||
556+ nodeName ( target , "a" ) ;
491557 }
492558 } ,
493559
@@ -504,6 +570,77 @@ jQuery.event = {
504570 }
505571} ;
506572
573+ // Ensure the presence of an event listener that handles manually-triggered
574+ // synthetic events by interrupting progress until reinvoked in response to
575+ // *native* events that it fires directly, ensuring that state changes have
576+ // already occurred before other listeners are invoked.
577+ function leverageNative ( el , type , forceAdd , allowAsync ) {
578+
579+ // Setup must go through jQuery.event.add
580+ if ( forceAdd ) {
581+ jQuery . event . add ( el , type , forceAdd ) ;
582+ return ;
583+ }
584+
585+ // Register the controller as a special universal handler for all event namespaces
586+ dataPriv . set ( el , type , forceAdd ) ;
587+ jQuery . event . add ( el , type , {
588+ namespace : false ,
589+ handler : function ( event ) {
590+ var maybeAsync , result ,
591+ saved = dataPriv . get ( this , type ) ;
592+
593+ // Interrupt processing of the outer synthetic .trigger()ed event
594+ if ( ( event . isTrigger & 1 ) && this [ type ] && ! saved ) {
595+
596+ // Store arguments for use when handling the inner native event
597+ saved = slice . call ( arguments ) ;
598+ dataPriv . set ( this , type , saved ) ;
599+
600+ // Trigger the native event and capture its result
601+ // Support: IE <=9 - 11+
602+ // focus() and blur() are asynchronous
603+ maybeAsync = allowAsync ( this , type ) ;
604+ this [ type ] ( ) ;
605+ result = dataPriv . get ( this , type ) ;
606+ if ( result !== saved ) {
607+ dataPriv . set ( this , type , false ) ;
608+
609+ // Cancel the outer synthetic event
610+ event . stopImmediatePropagation ( ) ;
611+ event . preventDefault ( ) ;
612+ return result ;
613+ } else if ( maybeAsync ) {
614+
615+ // Cancel the outer synthetic event in expectation of a followup
616+ event . stopImmediatePropagation ( ) ;
617+ event . preventDefault ( ) ;
618+ return ;
619+ } else {
620+ dataPriv . set ( this , type , false ) ;
621+ }
622+
623+ // If this is a native event triggered above, everything is now in order
624+ // Fire an inner synthetic event with the original arguments
625+ } else if ( ! event . isTrigger && saved ) {
626+
627+ // ...and capture the result
628+ dataPriv . set ( this , type , jQuery . event . trigger (
629+
630+ // Support: IE <=9 - 11+
631+ // Extend with the prototype to reset the above stopImmediatePropagation()
632+ jQuery . extend ( saved . shift ( ) , jQuery . Event . prototype ) ,
633+ saved ,
634+ this
635+ ) ) ;
636+
637+ // Abort handling of the native event
638+ event . stopImmediatePropagation ( ) ;
639+ }
640+ }
641+ } ) ;
642+ }
643+
507644jQuery . removeEvent = function ( elem , type , handle ) {
508645
509646 // This "if" is needed for plain objects
0 commit comments