Skip to content
Permalink
Browse files

Event: Fix handling of multiple async focus events

Fixes gh-4350
Closes gh-4354
  • Loading branch information...
gibson042 authored and mgol committed Apr 29, 2019
1 parent b4fadc9 commit 24d71ac70406f522fc1b09bf7c4025251ec3aee6
Showing with 61 additions and 12 deletions.
  1. +18 −12 src/event.js
  2. +43 −0 test/unit/event.js
@@ -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();
@@ -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 );

0 comments on commit 24d71ac

Please sign in to comment.
You can’t perform that action at this time.