]> source.dussan.org Git - jquery.git/commitdiff
Fix #13180: don't delegate into SVG <use>
authorRichard Gibson <richard.gibson@gmail.com>
Mon, 14 Jan 2013 00:53:19 +0000 (19:53 -0500)
committerRichard Gibson <richard.gibson@gmail.com>
Mon, 14 Jan 2013 01:00:03 +0000 (20:00 -0500)
(cherry picked from commits 36457cb6afc12d4a755cf93442a502783a669517..f860e0bd2f7dd228a14704d78ed5208cbe870d01)

src/event.js
test/unit/event.js

index fa931231633e9f005db3aaaa99bfa07898e45acb..a880bb64721e61e2c0872480c297ed4698295e09 100644 (file)
@@ -331,11 +331,10 @@ jQuery.event = {
                // Make a writable jQuery.Event from the native event object
                event = jQuery.event.fix( event );
 
-               var i, j, cur, ret, selMatch, matched, matches, handleObj, sel,
+               var i, j, ret, matched, handleObj,
                        handlerQueue = [],
                        args = core_slice.call( arguments ),
                        handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
-                       delegateCount = handlers.delegateCount,
                        special = jQuery.event.special[ event.type ] || {};
 
                // Use the fix-ed jQuery.Event rather than the (read-only) native event
@@ -347,41 +346,8 @@ jQuery.event = {
                        return;
                }
 
-               // Determine handlers that should run if there are delegated events
-               // Avoid non-left-click bubbling in Firefox (#3861)
-               if ( delegateCount && !(event.button && event.type === "click") ) {
-
-                       for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
-
-                               // Ignore clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
-                               if ( cur.disabled !== true || event.type !== "click" ) {
-                                       selMatch = {};
-                                       matches = [];
-                                       i = 0;
-                                       for ( ; i < delegateCount; i++ ) {
-                                               handleObj = handlers[ i ];
-                                               sel = handleObj.selector;
-
-                                               if ( selMatch[ sel ] === undefined ) {
-                                                       selMatch[ sel ] = handleObj.needsContext ?
-                                                               jQuery( sel, this ).index( cur ) >= 0 :
-                                                               jQuery.find( sel, this, null, [ cur ] ).length;
-                                               }
-                                               if ( selMatch[ sel ] ) {
-                                                       matches.push( handleObj );
-                                               }
-                                       }
-                                       if ( matches.length ) {
-                                               handlerQueue.push({ elem: cur, handlers: matches });
-                                       }
-                               }
-                       }
-               }
-
-               // Add the remaining (directly-bound) handlers
-               if ( handlers.length > delegateCount ) {
-                       handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
-               }
+               // Determine handlers
+               handlerQueue = jQuery.event.handlers.call( this, event, handlers );
 
                // Run delegates first; they may want to stop propagation beneath us
                i = 0;
@@ -419,6 +385,50 @@ jQuery.event = {
                return event.result;
        },
 
+       handlers: function( event, handlers ) {
+               var i, matches, sel, handleObj,
+                       handlerQueue = [],
+                       delegateCount = handlers.delegateCount,
+                       cur = event.target;
+
+               // Find delegate handlers
+               // Black-hole SVG <use> instance trees (#13180)
+               // Avoid non-left-click bubbling in Firefox (#3861)
+               if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+                       for ( ; cur != this; cur = cur.parentNode || this ) {
+
+                               // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+                               if ( cur.disabled !== true || event.type !== "click" ) {
+                                       matches = [];
+                                       for ( i = 0; i < delegateCount; i++ ) {
+                                               handleObj = handlers[ i ];
+                                               sel = handleObj.selector;
+
+                                               if ( matches[ sel ] === undefined ) {
+                                                       matches[ sel ] = handleObj.needsContext ?
+                                                               jQuery( sel, this ).index( cur ) >= 0 :
+                                                               jQuery.find( sel, this, null, [ cur ] ).length;
+                                               }
+                                               if ( matches[ sel ] ) {
+                                                       matches.push( handleObj );
+                                               }
+                                       }
+                                       if ( matches.length ) {
+                                               handlerQueue.push({ elem: cur, handlers: matches });
+                                       }
+                               }
+                       }
+               }
+
+               // Add the remaining (directly-bound) handlers
+               if ( delegateCount < handlers.length ) {
+                       handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+               }
+
+               return handlerQueue;
+       },
+
        // Includes some event props shared by KeyEvent and MouseEvent
        props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
 
index ff2ea1dd5147b04c1e06457c9b2711c1f2f865fd..182e10b1a3227fac25c7e8378bfa2c88393eb714 100644 (file)
@@ -1231,17 +1231,21 @@ test(".trigger() doesn't bubble load event (#10717)", function() {
        jQuery( window ).off( "load" );
 });
 
-test("Delegated events in SVG (#10791)", function() {
+test("Delegated events in SVG (#10791; #13180)", function() {
        expect(2);
 
-       var svg = jQuery(
+       var e,
+               svg = jQuery(
                        "<svg height='1' version='1.1' width='1' xmlns='http://www.w3.org/2000/svg'>" +
+                       "<defs><rect id='ref' x='10' y='20' width='100' height='60' r='10' rx='10' ry='10'></rect></defs>" +
                        "<rect class='svg-by-class' x='10' y='20' width='100' height='60' r='10' rx='10' ry='10'></rect>" +
                        "<rect id='svg-by-id' x='10' y='20' width='100' height='60' r='10' rx='10' ry='10'></rect>" +
+                       "<use id='use' xlink:href='#ref'></use>" +
                        "</svg>"
-               ).appendTo( "body" );
+               );
 
-       jQuery( "body" )
+       jQuery("#qunit-fixture")
+               .append( svg )
                .on( "click", "#svg-by-id", function() {
                        ok( true, "delegated id selector" );
                })
@@ -1249,11 +1253,18 @@ test("Delegated events in SVG (#10791)", function() {
                        ok( true, "delegated class selector" );
                })
                .find( "#svg-by-id, [class~='svg-by-class']" )
-                       .trigger( "click" )
-               .end()
-               .off( "click" );
+                       .trigger("click")
+               .end();
+
+       // Fire a native click on an SVGElementInstance (the instance tree of an SVG <use>)
+       // to confirm that it doesn't break our event delegation handling (#13180)
+       if ( document.createEvent ) {
+               e = document.createEvent("MouseEvents");
+               e.initEvent( "click", true, true );
+               svg.find("#use")[0].instanceRoot.dispatchEvent( e );
+       }
 
-       svg.remove();
+       jQuery("#qunit-fixture").off("click");
 });
 
 test("Delegated events in forms (#10844; #11145; #8165; #11382, #11764)", function() {