diff --git a/src/event.js b/src/event.js index 6bb4fa816..621464fdd 100644 --- a/src/event.js +++ b/src/event.js @@ -391,6 +391,7 @@ jQuery.event = { delegateCount = handlers.delegateCount, args = [].slice.call( arguments, 0 ), run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, handlerQueue = [], i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; @@ -398,6 +399,11 @@ jQuery.event = { args[0] = event; event.delegateTarget = this; + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + 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") ) { @@ -407,7 +413,7 @@ jQuery.event = { jqcur.context = this.ownerDocument || this; for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { - + // Don't process events on disabled elements (#6911, #8165) if ( cur.disabled !== true ) { selMatch = {}; @@ -467,6 +473,11 @@ jQuery.event = { } } + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + return event.result; }, @@ -758,16 +769,23 @@ if ( !jQuery.support.submitBubbles ) { form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; if ( form && !form._submit_attached ) { jQuery.event.add( form, "submit._submit", function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } + event._submit_bubble = true; }); form._submit_attached = true; } }); // return undefined since we don't need an event listener }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, teardown: function() { // Only need this for delegated form submit events diff --git a/test/unit/event.js b/test/unit/event.js index dd4bbd55d..3c9a08109 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -1216,10 +1216,10 @@ test("Delegated events in SVG (#10791)", function() { test("Delegated events in forms (#10844; #11145; #8165)", function() { expect(3); - // Aliases names like "id" cause havoc + // Alias names like "id" cause havoc var form = jQuery( '
' ) .on( "submit", function( event ) { @@ -1259,6 +1259,44 @@ test("Delegated events in forms (#10844; #11145; #8165)", function() { form.remove(); }); +test("Submit event can be stopped (#11049)", function() { + expect(1); + + // Since we manually bubble in IE, make sure inner handlers get a chance to cancel + var form = jQuery( + '' + ) + .appendTo("body"); + + jQuery( "body" ) + .on( "submit", function() { + ok( true, "submit bubbled on first handler" ); + return false; + }) + .find( "#myform input[type=submit]" ) + .each( function(){ this.click(); } ) + .end() + .on( "submit", function() { + ok( false, "submit bubbled on second handler" ); + return false; + }) + .find( "#myform input[type=submit]" ) + .each( function(){ + jQuery( this.form ).on( "submit", function( e ) { + e.preventDefault(); + e.stopPropagation(); + }); + this.click(); + }) + .end() + .off( "submit" ); + + form.remove(); +}); + test("jQuery.Event( type, props )", function() { expect(5); @@ -2664,7 +2702,7 @@ test("clone() delegated events (#11076)", function() { clicked = function( event ) { counter[ jQuery(this).text().replace(/\s+/, "") ]++; }, - table = + table = jQuery( "center | fold |