Event: Stop shimming focusin & focusout events

Latest versions of all browsers now implement focusin & focusout natively
and they all converged on a common event order so it doesn't make much sense
for us to normalize it to a different order anymore.

Note that it means we no longer guarantee that focusin fires before focus
and focusout before blur.

Fixes gh-4300
Closes gh-4362
This commit is contained in:
Michał Gołębiowski-Owczarek 2019-04-29 21:13:36 +02:00 committed by GitHub
parent 8fae21200e
commit 8a74137693
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 93 deletions

View File

@ -92,8 +92,7 @@ Some example modules that can be excluded are:
- **effects**: The `.animate()` method and its shorthands such as `.slideUp()` or `.hide("slow")`.
- **event**: The `.on()` and `.off()` methods and all event functionality. Also removes `event/alias`.
- **event/alias**: All event attaching/triggering shorthands like `.click()` or `.mouseover()`.
- **event/focusin**: Cross-browser support for the focusin and focusout events.
- **event/trigger**: The `.trigger()` and `.triggerHandler()` methods. Used by **alias** and **focusin** modules.
- **event/trigger**: The `.trigger()` and `.triggerHandler()` methods. Used by the **alias** module.
- **offset**: The `.offset()`, `.position()`, `.offsetParent()`, `.scrollLeft()`, and `.scrollTop()` methods.
- **wrap**: The `.wrap()`, `.wrapAll()`, `.wrapInner()`, and `.unwrap()` methods.
- **core/ready**: Exclude the ready module if you place your scripts at the end of the body. Any ready callbacks bound with `jQuery()` will simply be called immediately. However, `jQuery(document).ready()` will not be a function and `.on("ready", ...)` or similar will not be triggered.

View File

@ -1,55 +0,0 @@
define( [
"../core",
"../data/var/dataPriv",
"./support",
"../event",
"./trigger"
], function( jQuery, dataPriv, support ) {
"use strict";
// Support: Firefox <=44
// Firefox doesn't have focus(in | out) events
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
//
// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
// focus(in | out) events fire after focus & blur events,
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
if ( !support.focusin ) {
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
// Attach a single capturing handler on the document while someone wants focusin/focusout
var handler = function( event ) {
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
};
jQuery.event.special[ fix ] = {
setup: function() {
var doc = this.ownerDocument || this,
attaches = dataPriv.access( doc, fix );
if ( !attaches ) {
doc.addEventListener( orig, handler, true );
}
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
},
teardown: function() {
var doc = this.ownerDocument || this,
attaches = dataPriv.access( doc, fix ) - 1;
if ( !attaches ) {
doc.removeEventListener( orig, handler, true );
dataPriv.remove( doc, fix );
} else {
dataPriv.access( doc, fix, attaches );
}
}
};
} );
}
return jQuery;
} );

View File

@ -1,11 +0,0 @@
define( [
"../var/support"
], function( support ) {
"use strict";
support.focusin = "onfocusin" in window;
return support;
} );

1
src/jquery.js vendored
View File

@ -11,7 +11,6 @@ define( [
"./queue/delay",
"./attributes",
"./event",
"./event/focusin",
"./manipulation",
"./manipulation/_evalUrl",
"./wrap",

View File

@ -2946,39 +2946,62 @@ QUnit.test( "VML with special event handlers (trac-7071)", function( assert ) {
ns.remove();
} );
QUnit.test( "Check order of focusin/focusout events", function( assert ) {
assert.expect( 2 );
QUnit.test( "focusout/focusin support", function( assert ) {
assert.expect( 6 );
var focus, blur,
input = jQuery( "#name" );
var focus,
parent = jQuery( "<div>" ),
input = jQuery( "<input>" ),
inputExternal = jQuery( "<input>" );
parent.append( input );
jQuery( "#qunit-fixture" ).append( parent ).append( inputExternal );
parent
.on( "focus", function() {
assert.ok( false, "parent: focus not fired" );
} )
.on( "focusin", function() {
assert.ok( true, "parent: focusin fired" );
} )
.on( "blur", function() {
assert.ok( false, "parent: blur not fired" );
} )
.on( "focusout", function() {
assert.ok( true, "parent: focusout fired" );
} );
input
.on( "focus", function() {
assert.ok( true, "element: focus fired" );
focus = true;
} )
.on( "focusin", function() {
assert.ok( !focus, "Focusin event should fire before focus does" );
focus = true;
assert.ok( true, "element: focusin fired" );
} )
.on( "blur", function() {
blur = true;
assert.ok( true, "parent: blur fired" );
} )
.on( "focusout", function() {
assert.ok( !blur, "Focusout event should fire before blur does" );
blur = true;
assert.ok( true, "element: focusout fired" );
} );
// gain focus
input.trigger( "focus" );
// then lose it
jQuery( "#search" ).trigger( "focus" );
inputExternal.trigger( "focus" );
// cleanup
parent.off();
input.off();
// DOM focus is unreliable in TestSwarm
if ( !focus ) {
if ( QUnit.isSwarm && !focus ) {
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" );
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" );
}

View File

@ -66,7 +66,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": true,
@ -83,7 +82,6 @@ testIframe(
"clearCloneStyle": false,
"cors": true,
"createHTMLDocument": true,
"focusin": true,
"noCloneChecked": false,
"optSelected": false,
"pixelBoxStyles": true,
@ -100,7 +98,6 @@ testIframe(
"clearCloneStyle": false,
"cors": false,
"createHTMLDocument": true,
"focusin": true,
"noCloneChecked": false,
"optSelected": false,
"pixelBoxStyles": true,
@ -117,7 +114,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": true,
@ -134,7 +130,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": true,
@ -151,7 +146,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": false,
@ -168,7 +162,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": true,
@ -185,7 +178,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": true,
@ -202,7 +194,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": true,
@ -219,7 +210,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": false,
@ -236,7 +226,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": false,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": false,
@ -253,7 +242,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": false,
@ -270,7 +258,6 @@ testIframe(
"clearCloneStyle": true,
"cors": true,
"createHTMLDocument": true,
"focusin": false,
"noCloneChecked": true,
"optSelected": true,
"pixelBoxStyles": false,