]> source.dussan.org Git - jquery.git/commitdiff
Fix #14180. Allow cross-frame use of focusin/out. Close gh-1369.
authorDave Methvin <dave.methvin@gmail.com>
Tue, 17 Sep 2013 22:51:54 +0000 (18:51 -0400)
committerDave Methvin <dave.methvin@gmail.com>
Wed, 13 Nov 2013 02:24:20 +0000 (21:24 -0500)
(cherry picked from commit ebdb467761d756d4e52608a0df4a4d9b17da8092)
(conflicts with .data() resolved manually)

src/event.js
test/data/event/focusinCrossFrame.html [new file with mode: 0644]
test/unit/event.js

index 2ca50aba45ca691de3d3b41600e0e97fdc5e4338..3f19bab305252e50367cf2c9d1e18b5c17cba0f8 100644 (file)
@@ -892,21 +892,30 @@ if ( !support.changeBubbles ) {
 if ( !support.focusinBubbles ) {
        jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
 
-               // Attach a single capturing handler while someone wants focusin/focusout
-               var attaches = 0,
-                       handler = function( event ) {
+               // 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 ), true );
                        };
 
                jQuery.event.special[ fix ] = {
                        setup: function() {
-                               if ( attaches++ === 0 ) {
-                                       document.addEventListener( orig, handler, true );
+                               var doc = this.ownerDocument,
+                                       attaches = jQuery._data( doc, fix );
+
+                               if ( !attaches ) {
+                                       doc.addEventListener( orig, handler, true );
                                }
+                               jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
                        },
                        teardown: function() {
-                               if ( --attaches === 0 ) {
-                                       document.removeEventListener( orig, handler, true );
+                               var doc = this.ownerDocument,
+                                       attaches = jQuery._data( doc, fix ) - 1;
+
+                               if ( !attaches ) {
+                                       doc.removeEventListener( orig, handler, true );
+                                       jQuery._removeData( doc, fix );
+                               } else {
+                                       jQuery._data( doc, fix, attaches );
                                }
                        }
                };
diff --git a/test/data/event/focusinCrossFrame.html b/test/data/event/focusinCrossFrame.html
new file mode 100644 (file)
index 0000000..487f8de
--- /dev/null
@@ -0,0 +1,18 @@
+<!doctype html>
+<html>
+<head>
+       <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+       <title>focusin event cross-frame (#14180)</title>
+
+       <script src="../../jquery.js"></script>
+</head>
+<body>
+       <input type="text" id="frame-input" />
+       <script>
+               // Call parent when this frame is fully loaded, it will mess with #frame-input
+               jQuery( window ).one( "load", function() {
+                       window.parent.iframeCallback( document );
+               });
+       </script>
+</body>
+</html>
index b099ef2b9fa448ab0dba56f6a1854e4c81d68094..454943718c363e72718532e123ba42cbe072f29d 100644 (file)
@@ -2462,6 +2462,39 @@ test("fixHooks extensions", function() {
        jQuery.event.fixHooks.click = saved;
 });
 
+testIframeWithCallback( "focusin from an iframe", "event/focusinCrossFrame.html", function( frameDoc ) {
+       expect(1);
+
+       var input = jQuery( frameDoc ).find( "#frame-input" );
+
+       if ( input.length ) {
+               // Create a focusin handler on the parent; shouldn't affect the iframe's fate
+               jQuery ( "body" ).on( "focusin.iframeTest", function() {
+                       ok( false, "fired a focusin event in the parent document" );
+               });
+
+               input.on( "focusin", function() {
+                       ok( true, "fired a focusin event in the iframe" );
+               });
+
+               // Avoid a native event; Chrome can't force focus to another frame
+               input.trigger( "focusin" );
+
+               // Must manually remove handler to avoid leaks in our data store
+               input.remove();
+
+               // Be sure it was removed; nothing should happen
+               input.trigger( "focusin" );
+
+               // Remove body handler manually since it's outside the fixture
+               jQuery( "body" ).off( "focusin.iframeTest" );
+
+       } else {
+               // Opera 12 (pre-Blink) doesn't select anything
+               ok( true, "SOFTFAIL: no focus event fired in the iframe" );
+       }
+});
+
 testIframeWithCallback( "jQuery.ready promise", "event/promiseReady.html", function( isOk ) {
        expect(1);
        ok( isOk, "$.when( $.ready ) works" );