From 8a741376937dfacf9f82b2b88f93b239fe267435 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 29 Apr 2019 21:13:36 +0200 Subject: [PATCH] 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 --- README.md | 3 +-- src/event/focusin.js | 55 -------------------------------------------- src/event/support.js | 11 --------- src/jquery.js | 1 - test/unit/event.js | 45 +++++++++++++++++++++++++++--------- test/unit/support.js | 13 ----------- 6 files changed, 35 insertions(+), 93 deletions(-) delete mode 100644 src/event/focusin.js delete mode 100644 src/event/support.js diff --git a/README.md b/README.md index 958b171bc..c68362420 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/src/event/focusin.js b/src/event/focusin.js deleted file mode 100644 index 7faef2981..000000000 --- a/src/event/focusin.js +++ /dev/null @@ -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; -} ); diff --git a/src/event/support.js b/src/event/support.js deleted file mode 100644 index e3db9ad83..000000000 --- a/src/event/support.js +++ /dev/null @@ -1,11 +0,0 @@ -define( [ - "../var/support" -], function( support ) { - -"use strict"; - -support.focusin = "onfocusin" in window; - -return support; - -} ); diff --git a/src/jquery.js b/src/jquery.js index 0e026a6c1..aee1a6387 100644 --- a/src/jquery.js +++ b/src/jquery.js @@ -11,7 +11,6 @@ define( [ "./queue/delay", "./attributes", "./event", - "./event/focusin", "./manipulation", "./manipulation/_evalUrl", "./wrap", diff --git a/test/unit/event.js b/test/unit/event.js index 17706a8b1..e5b36c13d 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -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, + parent = jQuery( "
" ), + input = jQuery( "" ), + inputExternal = jQuery( "" ); - var focus, blur, - input = jQuery( "#name" ); + 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" ); } diff --git a/test/unit/support.js b/test/unit/support.js index db9991a76..b0309ffe7 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -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, -- 2.39.5