]> 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, 23 Oct 2013 02:03:20 +0000 (22:03 -0400)
src/event.js
test/data/event/focusinCrossFrame.html [new file with mode: 0644]
test/unit/event.js

index 2fd702c63156d0d7f2971016d4f45c7082c0be1b..ce5b453d27ba778702423419d8db3a6719202a54 100644 (file)
@@ -727,22 +727,29 @@ jQuery.each({
 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 = data_priv.access( doc, "focusCount" );
+
+                               if ( !attaches ) {
+                                       doc.addEventListener( orig, handler, true );
                                }
+                               data_priv.access( doc, "focusCount", ( attaches || 0 ) + 1 );
                        },
                        teardown: function() {
-                               if ( --attaches === 0 ) {
-                                       document.removeEventListener( orig, handler, true );
+                               var doc = this.ownerDocument,
+                                       attaches = data_priv.access( doc, "focusCount" ) - 1;
+
+                               if ( !attaches ) {
+                                       doc.removeEventListener( orig, handler, true );
                                }
+                               data_priv.access( doc, "focusCount", 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 26f2191951fb7d084fece70e40ea7698e18e46c2..21dda5a0f55d1a928f748f235b60ec9e1df2b202 100644 (file)
@@ -2434,6 +2434,33 @@ 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" );
+
+       // 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" );
+});
+
 testIframeWithCallback( "jQuery.ready promise", "event/promiseReady.html", function( isOk ) {
        expect(1);
        ok( isOk, "$.when( $.ready ) works" );