Commit 0a3cab8d authored by Dave Methvin's avatar Dave Methvin

Fix #10489. Disconnected elements don't bubble to document.

parent 7bef99e9
...@@ -261,17 +261,7 @@ jQuery.event = { ...@@ -261,17 +261,7 @@ jQuery.event = {
// Event object or event type // Event object or event type
var type = event.type || event, var type = event.type || event,
namespaces = [], namespaces = [],
cache, exclusive, i, cur, old, ontype, special, doc, eventPath, bubbleType, cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
addHandlers = function( elem, type ) {
// Defer getting handler so we don't waste time in case propagation is stopped
if ( (jQuery._data( elem, "events" ) || {})[ type ] ) {
eventPath.push({ elem: elem, type: type /*, handler: jQuery._data( elem, "handle" ) */ });
}
// IE doesn't like method names with a colon (#3533, #8272)
if ( ontype && jQuery.acceptData( elem ) && elem[ ontype ] ) {
eventPath.push({ elem: elem, type: type, handler: elem[ ontype ] });
}
};
if ( type.indexOf( "!" ) >= 0 ) { if ( type.indexOf( "!" ) >= 0 ) {
// Exclusive events trigger only for the exact event (no namespaces) // Exclusive events trigger only for the exact event (no namespaces)
...@@ -310,7 +300,6 @@ jQuery.event = { ...@@ -310,7 +300,6 @@ jQuery.event = {
// triggerHandler() and global events don't bubble or run the default action // triggerHandler() and global events don't bubble or run the default action
if ( onlyHandlers || !elem ) { if ( onlyHandlers || !elem ) {
event.preventDefault(); event.preventDefault();
event.stopPropagation();
} }
// Handle a global trigger // Handle a global trigger
...@@ -318,6 +307,7 @@ jQuery.event = { ...@@ -318,6 +307,7 @@ jQuery.event = {
// TODO: Stop taunting the data cache; remove global events and always attach to document // TODO: Stop taunting the data cache; remove global events and always attach to document
cache = jQuery.cache; cache = jQuery.cache;
event.stopPropagation();
for ( i in cache ) { for ( i in cache ) {
if ( cache[ i ].events && cache[ i ].events[ type ] ) { if ( cache[ i ].events && cache[ i ].events[ type ] ) {
jQuery.event.trigger( event, data, cache[ i ].handle.elem ); jQuery.event.trigger( event, data, cache[ i ].handle.elem );
...@@ -344,23 +334,37 @@ jQuery.event = { ...@@ -344,23 +334,37 @@ jQuery.event = {
// Determine event propagation path in advance, per W3C events spec (#9951) // Determine event propagation path in advance, per W3C events spec (#9951)
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
// Always fire handlers for the target, even if prop is stopped in advance eventPath = [[ elem, special.bindType || type ]];
eventPath = []; if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
addHandlers( elem, special.bindType || type );
doc = elem.ownerDocument;
if ( doc && !special.noBubble && !jQuery.isWindow( elem ) & !event.isPropagationStopped() ) {
bubbleType = special.delegateType || type; bubbleType = special.delegateType || type;
old = null;
for ( cur = elem.parentNode; cur; cur = cur.parentNode ) { for ( cur = elem.parentNode; cur; cur = cur.parentNode ) {
addHandlers( cur, bubbleType ); eventPath.push([ cur, bubbleType ]);
old = cur;
}
// Only add window if we got to document (e.g., not plain obj or detached DOM)
if ( old && old === elem.ownerDocument ) {
eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
} }
addHandlers( doc.defaultView || doc.parentWindow || window, bubbleType );
} }
// Bubble up the DOM tree // Fire handlers on the event path
for ( i = 0; i < eventPath.length; i++ ) { for ( i = 0; i < eventPath.length; i++ ) {
cur = eventPath[ i ];
event.type = cur.type; cur = eventPath[i][0];
( cur.handler || jQuery._data( cur.elem, "handle" ) ).apply( cur.elem, data ); event.type = eventPath[i][1];
handle = (jQuery._data( cur, "events" ) || {})[ event.type ] && jQuery._data( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
}
handle = ontype && cur[ ontype ];
if ( handle && jQuery.acceptData( cur ) ) {
handle.apply( cur, data );
}
if ( event.isPropagationStopped() ) { if ( event.isPropagationStopped() ) {
break; break;
} }
......
...@@ -34,30 +34,31 @@ test("bind(),live(),delegate() with non-null,defined data", function() { ...@@ -34,30 +34,31 @@ test("bind(),live(),delegate() with non-null,defined data", function() {
}); });
/*
Removed because Chrome 13 snaps/crashes on this 2011-09-07
test("Handler changes and .trigger() order", function() { test("Handler changes and .trigger() order", function() {
expect(1); expect(1);
var markup = jQuery( var markup = jQuery(
'<div><p><b class="a">b</b></p></div>' '<div><div><p><span><b class="a">b</b></span></p></div></div>'
).appendTo( "body" ); ),
path = "";
var path = ""; markup
jQuery( "b" ).parents().bind( "click", function(e){ .find( "*" ).andSelf().on( "click", function( e ) {
path += this.nodeName.toLowerCase() + " "; path += this.nodeName.toLowerCase() + " ";
// Should not change the event triggering order })
$(this).parent().remove(); .filter( "b" ).on( "click", function( e ) {
}); // Removing span should not stop propagation to original parents
if ( e.target === this ) {
jQuery(this).parent().remove();
}
});
markup.find( "b" ).trigger( "click" ); markup.find( "b" ).trigger( "click" );
equals( path, "p div body html ", "Delivered all events" ) equals( path, "b p div div ", "Delivered all events" );
markup.remove(); markup.remove();
}); });
*/
test("bind(), with data", function() { test("bind(), with data", function() {
expect(4); expect(4);
...@@ -1110,6 +1111,30 @@ test("trigger(eventObject, [data], [fn])", function() { ...@@ -1110,6 +1111,30 @@ test("trigger(eventObject, [data], [fn])", function() {
$parent.unbind().remove(); $parent.unbind().remove();
}); });
test(".trigger() bubbling on disconnected elements (#10489)", function() {
expect(2);
jQuery( window ).on( "click", function(){
ok( false, "click fired on window" );
});
jQuery( "<div><p>hi</p></div>" )
.on( "click", function() {
ok( true, "click fired on div" );
})
.find( "p" )
.on( "click", function() {
ok( true, "click fired on p" );
})
.click()
.off( "click" )
.end()
.off( "click" )
.remove();
jQuery( window ).off( "click" );
});
test("jQuery.Event( type, props )", function() { test("jQuery.Event( type, props )", function() {
expect(5); expect(5);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment