Skip to content

Commit 2fadbc0

Browse files
committed
Event: Make focus re-triggering not focus the original element back
If during a focus handler another focus event is triggered: ```js elem1.on( "focus", function() { elem2.trigger( "focus" ); } ); ``` due to their synchronous nature everywhere outside of IE the hack added in gh-4279 to leverage native events causes the native `.focus()` method to be called last for the initial element, making it steal the focus back. Since the native method is already being called in `leverageNative`, we can skip that final call. This aligns with changes to the `_default` method for the `click` event that were added when `leverageNative` was introduced there. A side effect of this change is that now `focusin` will only propagate to the document for the last focused element. This is a change in behavior but it also aligns us better with how this works with native methods. Fixes gh-4382 Closes gh-4813 Ref gh-4279 (cherry picked from commit dbcffb3)
1 parent 07829a1 commit 2fadbc0

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

src/event.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,12 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp
778778
return true;
779779
},
780780

781+
// Suppress native focus or blur as it's already being fired
782+
// in leverageNative.
783+
_default: function() {
784+
return true;
785+
},
786+
781787
delegateType: delegateType
782788
};
783789
} );

test/unit/event.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3263,6 +3263,40 @@ QUnit.test( "native-backed events preserve trigger data (gh-1741, gh-4139)", fun
32633263
}, 50 );
32643264
} );
32653265

3266+
QUnit.test( "focus change during a focus handler (gh-4382)", function( assert ) {
3267+
assert.expect( 2 );
3268+
3269+
var done = assert.async(),
3270+
select = jQuery( "<select><option selected='selected'>A</option></select>" ),
3271+
button = jQuery( "<button>Focus target</button>" );
3272+
3273+
jQuery( "#qunit-fixture" )
3274+
.append( select )
3275+
.append( button );
3276+
3277+
select.on( "focus", function() {
3278+
button.trigger( "focus" );
3279+
} );
3280+
3281+
jQuery( document ).on( "focusin.focusTests", function( ev ) {
3282+
// Support: IE 11+
3283+
// In IE focus is async so focusin on document is fired multiple times,
3284+
// for each of the elements. In other browsers it's fired just once, for
3285+
// the last one.
3286+
if ( ev.target === button[ 0 ] ) {
3287+
assert.ok( true, "focusin propagated to document from the button" );
3288+
}
3289+
} );
3290+
3291+
select.trigger( "focus" );
3292+
3293+
setTimeout( function() {
3294+
assert.strictEqual( document.activeElement, button[ 0 ], "Focus redirect worked" );
3295+
jQuery( document ).off( ".focusTests" );
3296+
done();
3297+
} );
3298+
} );
3299+
32663300
// TODO replace with an adaptation of
32673301
// https://github.com/jquery/jquery/pull/1367/files#diff-a215316abbaabdf71857809e8673ea28R2464
32683302
( function() {

0 commit comments

Comments
 (0)