]> source.dussan.org Git - jquery.git/commitdiff
Event: Fix handling of multiple async focus events
authorRichard Gibson <richard.gibson@gmail.com>
Mon, 29 Apr 2019 17:18:08 +0000 (13:18 -0400)
committerMichał Gołębiowski-Owczarek <m.goleb@gmail.com>
Mon, 29 Apr 2019 18:49:30 +0000 (20:49 +0200)
(cherry-picked from 24d71ac70406f522fc1b09bf7c4025251ec3aee6)

Fixes gh-4350
Closes gh-4354

src/event.js
test/unit/event.js

index b63b93b96ca12b0f479ee02b5ac41934e81aea95..48d9095c9f8653a488d8721c79b8b8a16c8a2cbe 100644 (file)
@@ -554,9 +554,13 @@ function leverageNative( el, type, expectSync ) {
                        if ( ( event.isTrigger & 1 ) && this[ type ] ) {
 
                                // Interrupt processing of the outer synthetic .trigger()ed event
-                               if ( !saved ) {
+                               // Saved data should be false in such cases, but might be a leftover capture object
+                               // from an async native handler (gh-4350)
+                               if ( !saved.length ) {
 
                                        // Store arguments for use when handling the inner native event
+                                       // There will always be at least one argument (an event object), so this array
+                                       // will not be confused with a leftover capture object.
                                        saved = slice.call( arguments );
                                        dataPriv.set( this, type, saved );
 
@@ -569,14 +573,14 @@ function leverageNative( el, type, expectSync ) {
                                        if ( saved !== result || notAsync ) {
                                                dataPriv.set( this, type, false );
                                        } else {
-                                               result = undefined;
+                                               result = {};
                                        }
                                        if ( saved !== result ) {
 
                                                // Cancel the outer synthetic event
                                                event.stopImmediatePropagation();
                                                event.preventDefault();
-                                               return result;
+                                               return result.value;
                                        }
 
                                // If this is an inner synthetic event for an event with a bubbling surrogate
@@ -591,17 +595,19 @@ function leverageNative( el, type, expectSync ) {
 
                        // If this is a native event triggered above, everything is now in order
                        // Fire an inner synthetic event with the original arguments
-                       } else if ( saved ) {
+                       } else if ( saved.length ) {
 
                                // ...and capture the result
-                               dataPriv.set( this, type, jQuery.event.trigger(
-
-                                       // Support: IE <=9 - 11+
-                                       // Extend with the prototype to reset the above stopImmediatePropagation()
-                                       jQuery.extend( saved.shift(), jQuery.Event.prototype ),
-                                       saved,
-                                       this
-                               ) );
+                               dataPriv.set( this, type, {
+                                       value: jQuery.event.trigger(
+
+                                               // Support: IE <=9 - 11+
+                                               // Extend with the prototype to reset the above stopImmediatePropagation()
+                                               jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
+                                               saved.slice( 1 ),
+                                               this
+                                       )
+                               } );
 
                                // Abort handling of the native event
                                event.stopImmediatePropagation();
index c7497b9b0f44e83f719814133b09f83a5ffd1caf..17706a8b196457c1dbbfb941114429a098851bdc 100644 (file)
@@ -3041,6 +3041,49 @@ QUnit.test( "focus-blur order (#12868)", function( assert ) {
        }, 50 );
 } );
 
+QUnit.test( "Event handling works with multiple async focus events (gh-4350)", function( assert ) {
+       assert.expect( 3 );
+
+       var remaining = 3,
+               input = jQuery( "#name" ),
+
+               // Support: IE <=9 - 11+
+               // focus and blur events are asynchronous; this is the resulting mess.
+               // The browser window must be topmost for this to work properly!!
+               done = assert.async();
+
+       input
+               .on( "focus", function() {
+                       remaining--;
+                       assert.ok( true, "received focus event, expecting " + remaining + " more" );
+                       if ( remaining > 0 ) {
+                               input.trigger( "blur" );
+                       } else {
+                               done();
+                       }
+               } )
+               .on( "blur", function() {
+                       setTimeout( function() {
+                               input.trigger( "focus" );
+                       } );
+               } );
+
+       // gain focus
+       input.trigger( "focus" );
+
+       // DOM focus is unreliable in TestSwarm
+       setTimeout( function() {
+               if ( QUnit.isSwarm && remaining === 3 ) {
+                       assert.ok( true, "GAP: Could not observe focus change" );
+                       assert.ok( true, "GAP: Could not observe focus change" );
+                       assert.ok( true, "GAP: Could not observe focus change" );
+                       setTimeout( function() {
+                               done();
+                       } );
+               }
+       } );
+} );
+
 QUnit.test( "native-backed events preserve trigger data (gh-1741, gh-4139)", function( assert ) {
        assert.expect( 17 );