Skip to content
Permalink
Browse files

Make sure that special remove and teardown events get called when .di…

…e() is used. Additionally made sure that default actions are triggered when namespaced events are used. Fixes #6202 and #6250.
  • Loading branch information
jeresig committed Mar 9, 2010
1 parent 2fbe3fb commit f68b46d7abb54cdcd3d1ce1713bc989f992d1448
Showing with 91 additions and 39 deletions.
  1. +20 −28 src/event.js
  2. +1 −1 src/manipulation.js
  3. +70 −10 test/unit/event.js
@@ -90,7 +90,9 @@ jQuery.event = {
}

handleObj.type = type;
handleObj.guid = handler.guid;
if ( !handleObj.guid ) {
handleObj.guid = handler.guid;
}

// Get the current list of functions bound to this event
var handlers = events[ type ],
@@ -335,31 +337,31 @@ jQuery.event = {
jQuery.event.trigger( event, data, parent, true );

} else if ( !event.isDefaultPrevented() ) {
var target = event.target, old,
isClick = jQuery.nodeName(target, "a") && type === "click",
special = jQuery.event.special[ type ] || {};
var target = event.target, old, targetType = type.replace(/\..*$/, ""),
isClick = jQuery.nodeName(target, "a") && targetType === "click",
special = jQuery.event.special[ targetType ] || {};

if ( (!special._default || special._default.call( elem, event ) === false) &&
!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {

try {
if ( target[ type ] ) {
if ( target[ targetType ] ) {
// Make sure that we don't accidentally re-trigger the onFOO events
old = target[ "on" + type ];
old = target[ "on" + targetType ];

if ( old ) {
target[ "on" + type ] = null;
target[ "on" + targetType ] = null;
}

jQuery.event.triggered = true;
target[ type ]();
target[ targetType ]();
}

// prevent IE from throwing an error for some elements with some event types, see #3533
} catch (triggerError) {}

if ( old ) {
target[ "on" + type ] = old;
target[ "on" + targetType ] = old;
}

jQuery.event.triggered = false;
@@ -381,9 +383,10 @@ jQuery.event = {
event.type = namespaces.shift();
namespace_sort = namespaces.slice(0).sort();
namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
event.namespace = namespace_sort.join(".");
}

event.namespace = event.namespace || namespace_sort.join(".");

events = jQuery.data(this, "events");
handlers = (events || {})[ event.type ];

@@ -495,25 +498,14 @@ jQuery.event = {

live: {
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 ) {
var remove = true,
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 );
}
jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
}

},

beforeunload: {
@@ -983,13 +975,13 @@ jQuery.each(["live", "die"], function( i, name ) {
if ( name === "live" ) {
// bind live handler
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 } );
}

} else {
// 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 ) {
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 " +
@@ -561,7 +561,7 @@ jQuery.extend({
if ( id ) {
data = cache[ id ];

if ( data.events ) {
if ( data && data.events ) {
for ( var type in data.events ) {
if ( special[ type ] ) {
jQuery.event.remove( elem, type );
@@ -978,17 +978,20 @@ test(".live()/.die()", function() {
jQuery("#nothiddendiv").trigger("click");
equals( called, 1, "Verify that only one click occurred." );

called = 0;
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
jQuery("#anchor2").die("click", callback);

called = 0;
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");
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,
// but the event type is different
@@ -997,11 +1000,13 @@ test(".live()/.die()", function() {
// Cleanup
jQuery("#nothiddendiv").die("click", callback);

called = 0;
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");
equals( called, 4, "Verify that one foo occurred." );
equals( called, 1, "Verify that one foo occurred." );

// Cleanup
jQuery("#nothiddendiv").die("foo", callback);
@@ -1307,6 +1312,56 @@ test("live with submit", function() {
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() {
expect(65);

@@ -1460,17 +1515,20 @@ test(".delegate()/.undelegate()", function() {
jQuery("#nothiddendiv").trigger("click");
equals( called, 1, "Verify that only one click occurred." );

called = 0;
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
jQuery("#body").undelegate("#anchor2", "click", callback);

called = 0;
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");
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,
// but the event type is different
@@ -1479,11 +1537,13 @@ test(".delegate()/.undelegate()", function() {
// Cleanup
jQuery("#body").undelegate("#nothiddendiv", "click", callback);

called = 0;
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");
equals( called, 4, "Verify that one foo occurred." );
equals( called, 1, "Verify that one foo occurred." );

// Cleanup
jQuery("#body").undelegate("#nothiddendiv", "foo", callback);

0 comments on commit f68b46d

Please sign in to comment.
You can’t perform that action at this time.