Make sure that special remove and teardown events get called when .die() is used. Additionally made sure that default actions are triggered when namespaced events are used. Fixes #6202 and #6250.
This commit is contained in:
parent
2fbe3fbf68
commit
f68b46d7ab
48
src/event.js
48
src/event.js
|
@ -90,7 +90,9 @@ jQuery.event = {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleObj.type = type;
|
handleObj.type = type;
|
||||||
handleObj.guid = handler.guid;
|
if ( !handleObj.guid ) {
|
||||||
|
handleObj.guid = handler.guid;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the current list of functions bound to this event
|
// Get the current list of functions bound to this event
|
||||||
var handlers = events[ type ],
|
var handlers = events[ type ],
|
||||||
|
@ -335,31 +337,31 @@ jQuery.event = {
|
||||||
jQuery.event.trigger( event, data, parent, true );
|
jQuery.event.trigger( event, data, parent, true );
|
||||||
|
|
||||||
} else if ( !event.isDefaultPrevented() ) {
|
} else if ( !event.isDefaultPrevented() ) {
|
||||||
var target = event.target, old,
|
var target = event.target, old, targetType = type.replace(/\..*$/, ""),
|
||||||
isClick = jQuery.nodeName(target, "a") && type === "click",
|
isClick = jQuery.nodeName(target, "a") && targetType === "click",
|
||||||
special = jQuery.event.special[ type ] || {};
|
special = jQuery.event.special[ targetType ] || {};
|
||||||
|
|
||||||
if ( (!special._default || special._default.call( elem, event ) === false) &&
|
if ( (!special._default || special._default.call( elem, event ) === false) &&
|
||||||
!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
|
!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ( target[ type ] ) {
|
if ( target[ targetType ] ) {
|
||||||
// Make sure that we don't accidentally re-trigger the onFOO events
|
// Make sure that we don't accidentally re-trigger the onFOO events
|
||||||
old = target[ "on" + type ];
|
old = target[ "on" + targetType ];
|
||||||
|
|
||||||
if ( old ) {
|
if ( old ) {
|
||||||
target[ "on" + type ] = null;
|
target[ "on" + targetType ] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery.event.triggered = true;
|
jQuery.event.triggered = true;
|
||||||
target[ type ]();
|
target[ targetType ]();
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent IE from throwing an error for some elements with some event types, see #3533
|
// prevent IE from throwing an error for some elements with some event types, see #3533
|
||||||
} catch (triggerError) {}
|
} catch (triggerError) {}
|
||||||
|
|
||||||
if ( old ) {
|
if ( old ) {
|
||||||
target[ "on" + type ] = old;
|
target[ "on" + targetType ] = old;
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery.event.triggered = false;
|
jQuery.event.triggered = false;
|
||||||
|
@ -381,9 +383,10 @@ jQuery.event = {
|
||||||
event.type = namespaces.shift();
|
event.type = namespaces.shift();
|
||||||
namespace_sort = namespaces.slice(0).sort();
|
namespace_sort = namespaces.slice(0).sort();
|
||||||
namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
|
namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
|
||||||
event.namespace = namespace_sort.join(".");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event.namespace = event.namespace || namespace_sort.join(".");
|
||||||
|
|
||||||
events = jQuery.data(this, "events");
|
events = jQuery.data(this, "events");
|
||||||
handlers = (events || {})[ event.type ];
|
handlers = (events || {})[ event.type ];
|
||||||
|
|
||||||
|
@ -495,25 +498,14 @@ jQuery.event = {
|
||||||
|
|
||||||
live: {
|
live: {
|
||||||
add: function( handleObj ) {
|
add: function( handleObj ) {
|
||||||
jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) );
|
jQuery.event.add( this,
|
||||||
|
liveConvert( handleObj.origType, handleObj.selector ),
|
||||||
|
jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
|
||||||
},
|
},
|
||||||
|
|
||||||
remove: function( handleObj ) {
|
remove: function( handleObj ) {
|
||||||
var remove = true,
|
jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
|
||||||
type = handleObj.origType.replace(rnamespaces, "");
|
|
||||||
|
|
||||||
jQuery.each( jQuery.data(this, "events").live || [], function() {
|
|
||||||
if ( type === this.origType.replace(rnamespaces, "") ) {
|
|
||||||
remove = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if ( remove ) {
|
|
||||||
jQuery.event.remove( this, handleObj.origType, liveHandler );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeunload: {
|
beforeunload: {
|
||||||
|
@ -983,13 +975,13 @@ jQuery.each(["live", "die"], function( i, name ) {
|
||||||
if ( name === "live" ) {
|
if ( name === "live" ) {
|
||||||
// bind live handler
|
// bind live handler
|
||||||
for ( var j = 0, l = context.length; j < l; j++ ) {
|
for ( var j = 0, l = context.length; j < l; j++ ) {
|
||||||
jQuery.event.add( context[j], liveConvert( type, selector ),
|
jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
|
||||||
{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
|
{ data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// unbind live handler
|
// unbind live handler
|
||||||
context.unbind( liveConvert( type, selector ), fn );
|
context.unbind( "live." + liveConvert( type, selector ), fn );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1077,7 +1069,7 @@ function liveHandler( event ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function liveConvert( type, selector ) {
|
function liveConvert( type, selector ) {
|
||||||
return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
|
return (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
|
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
|
||||||
|
|
|
@ -561,7 +561,7 @@ jQuery.extend({
|
||||||
if ( id ) {
|
if ( id ) {
|
||||||
data = cache[ id ];
|
data = cache[ id ];
|
||||||
|
|
||||||
if ( data.events ) {
|
if ( data && data.events ) {
|
||||||
for ( var type in data.events ) {
|
for ( var type in data.events ) {
|
||||||
if ( special[ type ] ) {
|
if ( special[ type ] ) {
|
||||||
jQuery.event.remove( elem, type );
|
jQuery.event.remove( elem, type );
|
||||||
|
|
|
@ -978,17 +978,20 @@ test(".live()/.die()", function() {
|
||||||
jQuery("#nothiddendiv").trigger("click");
|
jQuery("#nothiddendiv").trigger("click");
|
||||||
equals( called, 1, "Verify that only one click occurred." );
|
equals( called, 1, "Verify that only one click occurred." );
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#anchor2").trigger("click");
|
jQuery("#anchor2").trigger("click");
|
||||||
equals( called, 2, "Verify that only one click occurred." );
|
equals( called, 1, "Verify that only one click occurred." );
|
||||||
|
|
||||||
// Make sure that only one callback is removed
|
// Make sure that only one callback is removed
|
||||||
jQuery("#anchor2").die("click", callback);
|
jQuery("#anchor2").die("click", callback);
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#nothiddendiv").trigger("click");
|
jQuery("#nothiddendiv").trigger("click");
|
||||||
equals( called, 3, "Verify that only one click occurred." );
|
equals( called, 1, "Verify that only one click occurred." );
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#anchor2").trigger("click");
|
jQuery("#anchor2").trigger("click");
|
||||||
equals( called, 3, "Verify that no click occurred." );
|
equals( called, 0, "Verify that no click occurred." );
|
||||||
|
|
||||||
// Make sure that it still works if the selector is the same,
|
// Make sure that it still works if the selector is the same,
|
||||||
// but the event type is different
|
// but the event type is different
|
||||||
|
@ -997,11 +1000,13 @@ test(".live()/.die()", function() {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
jQuery("#nothiddendiv").die("click", callback);
|
jQuery("#nothiddendiv").die("click", callback);
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#nothiddendiv").trigger("click");
|
jQuery("#nothiddendiv").trigger("click");
|
||||||
equals( called, 3, "Verify that no click occurred." );
|
equals( called, 0, "Verify that no click occurred." );
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#nothiddendiv").trigger("foo");
|
jQuery("#nothiddendiv").trigger("foo");
|
||||||
equals( called, 4, "Verify that one foo occurred." );
|
equals( called, 1, "Verify that one foo occurred." );
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
jQuery("#nothiddendiv").die("foo", callback);
|
jQuery("#nothiddendiv").die("foo", callback);
|
||||||
|
@ -1307,6 +1312,56 @@ test("live with submit", function() {
|
||||||
jQuery("body").die("submit");
|
jQuery("body").die("submit");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("live with special events", function() {
|
||||||
|
expect(13);
|
||||||
|
|
||||||
|
jQuery.event.special.foo = {
|
||||||
|
setup: function( data, namespaces, handler ) {
|
||||||
|
ok( true, "Setup run." );
|
||||||
|
},
|
||||||
|
teardown: function( namespaces ) {
|
||||||
|
ok( true, "Teardown run." );
|
||||||
|
},
|
||||||
|
add: function( handleObj ) {
|
||||||
|
ok( true, "Add run." );
|
||||||
|
},
|
||||||
|
remove: function( handleObj ) {
|
||||||
|
ok( true, "Remove run." );
|
||||||
|
},
|
||||||
|
_default: function( event ) {
|
||||||
|
ok( true, "Default run." );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run: setup, add
|
||||||
|
jQuery("#liveSpan1").live("foo.a", function(e){
|
||||||
|
ok( true, "Handler 1 run." );
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run: add
|
||||||
|
jQuery("#liveSpan1").live("foo.b", function(e){
|
||||||
|
ok( true, "Handler 2 run." );
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run: Handler 1, Handler 2, Default
|
||||||
|
jQuery("#liveSpan1").trigger("foo");
|
||||||
|
|
||||||
|
// Run: Handler 1, Default
|
||||||
|
// TODO: Namespace doesn't trigger default (?)
|
||||||
|
jQuery("#liveSpan1").trigger("foo.a");
|
||||||
|
|
||||||
|
// Run: remove
|
||||||
|
jQuery("#liveSpan1").die("foo.a");
|
||||||
|
|
||||||
|
// Run: Handler 2, Default
|
||||||
|
jQuery("#liveSpan1").trigger("foo");
|
||||||
|
|
||||||
|
// Run: remove, teardown
|
||||||
|
jQuery("#liveSpan1").die("foo");
|
||||||
|
|
||||||
|
delete jQuery.event.special.foo;
|
||||||
|
});
|
||||||
|
|
||||||
test(".delegate()/.undelegate()", function() {
|
test(".delegate()/.undelegate()", function() {
|
||||||
expect(65);
|
expect(65);
|
||||||
|
|
||||||
|
@ -1460,17 +1515,20 @@ test(".delegate()/.undelegate()", function() {
|
||||||
jQuery("#nothiddendiv").trigger("click");
|
jQuery("#nothiddendiv").trigger("click");
|
||||||
equals( called, 1, "Verify that only one click occurred." );
|
equals( called, 1, "Verify that only one click occurred." );
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#anchor2").trigger("click");
|
jQuery("#anchor2").trigger("click");
|
||||||
equals( called, 2, "Verify that only one click occurred." );
|
equals( called, 1, "Verify that only one click occurred." );
|
||||||
|
|
||||||
// Make sure that only one callback is removed
|
// Make sure that only one callback is removed
|
||||||
jQuery("#body").undelegate("#anchor2", "click", callback);
|
jQuery("#body").undelegate("#anchor2", "click", callback);
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#nothiddendiv").trigger("click");
|
jQuery("#nothiddendiv").trigger("click");
|
||||||
equals( called, 3, "Verify that only one click occurred." );
|
equals( called, 1, "Verify that only one click occurred." );
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#anchor2").trigger("click");
|
jQuery("#anchor2").trigger("click");
|
||||||
equals( called, 3, "Verify that no click occurred." );
|
equals( called, 0, "Verify that no click occurred." );
|
||||||
|
|
||||||
// Make sure that it still works if the selector is the same,
|
// Make sure that it still works if the selector is the same,
|
||||||
// but the event type is different
|
// but the event type is different
|
||||||
|
@ -1479,11 +1537,13 @@ test(".delegate()/.undelegate()", function() {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
jQuery("#body").undelegate("#nothiddendiv", "click", callback);
|
jQuery("#body").undelegate("#nothiddendiv", "click", callback);
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#nothiddendiv").trigger("click");
|
jQuery("#nothiddendiv").trigger("click");
|
||||||
equals( called, 3, "Verify that no click occurred." );
|
equals( called, 0, "Verify that no click occurred." );
|
||||||
|
|
||||||
|
called = 0;
|
||||||
jQuery("#nothiddendiv").trigger("foo");
|
jQuery("#nothiddendiv").trigger("foo");
|
||||||
equals( called, 4, "Verify that one foo occurred." );
|
equals( called, 1, "Verify that one foo occurred." );
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
jQuery("#body").undelegate("#nothiddendiv", "foo", callback);
|
jQuery("#body").undelegate("#nothiddendiv", "foo", callback);
|
||||||
|
|
Loading…
Reference in a new issue