refactor specialAll into add and remove hooks for existing special events, live now accepts optional data param like bind, fixes #4612 and #4613, thanks to Mike Helgeson

This commit is contained in:
Brandon Aaron 2009-04-30 21:44:25 +00:00
parent 287ecdbf67
commit 71efbdd3b2
2 changed files with 37 additions and 41 deletions

View file

@ -60,10 +60,15 @@ jQuery.event = {
handler.type = namespaces.slice().sort().join("."); handler.type = namespaces.slice().sort().join(".");
// 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 ],
special = this.special[ type ] || {};
if ( this.specialAll[ type ] ) { if ( special.add ) {
this.specialAll[ type ].setup.call( elem, data, namespaces ); var modifiedHandler = special.add.call( elem, handler, data, namespaces );
if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
modifiedHandler.guid = handler.guid;
handler = modifiedHandler;
}
} }
// Init the event handler queue // Init the event handler queue
@ -73,7 +78,7 @@ jQuery.event = {
// Check for a special event handler // Check for a special event handler
// Only use addEventListener/attachEvent if the special // Only use addEventListener/attachEvent if the special
// events handler returns false // events handler returns false
if ( !this.special[ type ] || this.special[ type ].setup.call( elem, data, namespaces ) === false ) { if ( !special.setup || special.setup.call( elem, data, namespaces ) === false ) {
// Bind the global event handler to the element // Bind the global event handler to the element
if ( elem.addEventListener ) { if ( elem.addEventListener ) {
elem.addEventListener( type, handle, false ); elem.addEventListener( type, handle, false );
@ -128,9 +133,10 @@ jQuery.event = {
var namespaces = type.split("."); var namespaces = type.split(".");
type = namespaces.shift(); type = namespaces.shift();
var all = !namespaces.length, var all = !namespaces.length,
namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)"); namespace = new RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)"),
special = this.special[ type ] || {};
if ( events[type] ) { if ( events[ type ] ) {
// remove the given handler for the given type // remove the given handler for the given type
if ( handler ) { if ( handler ) {
delete events[ type ][ handler.guid ]; delete events[ type ][ handler.guid ];
@ -145,8 +151,8 @@ jQuery.event = {
} }
} }
if ( this.specialAll[ type ] ) { if ( special.remove ) {
this.specialAll[ type ].teardown.call( elem, namespaces ); special.remove.call( elem, namespaces );
} }
// remove generic event handler if no more handlers exist // remove generic event handler if no more handlers exist
@ -381,28 +387,17 @@ jQuery.event = {
// Make sure the ready event is setup // Make sure the ready event is setup
setup: bindReady, setup: bindReady,
teardown: function() {} teardown: function() {}
} },
},
specialAll: {
live: { live: {
setup: function( selector, namespaces ) { add: function( proxy, data, namespaces ) {
jQuery.event.add( this, namespaces[0], liveHandler ); jQuery.extend( proxy, data || {} );
proxy.guid += data.selector + data.live;
jQuery.event.add( this, data.live, liveHandler );
}, },
teardown: function( namespaces ) {
if ( namespaces.length ) { teardown: function( namespaces ) {
var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)"); jQuery.event.remove( this, namespaces[0], liveHandler );
jQuery.each( (jQuery.data(this, "events").live || {}), function() {
if ( name.test(this.type) ) {
remove++;
}
});
if ( remove < 1 ) {
jQuery.event.remove( this, namespaces[0], liveHandler );
}
}
} }
} }
} }
@ -592,28 +587,25 @@ jQuery.fn.extend({
return this; return this;
}, },
live: function( type, fn ) { live: function( type, data, fn ) {
var proxy = jQuery.event.proxy( fn ); jQuery( this.context ).bind( liveConvert( type, this.selector ), {
proxy.guid += this.selector + type; data: fn && data, selector: this.selector, live: type
}, fn || data );
jQuery( this.context ).bind( liveConvert( type, this.selector ), this.selector, proxy );
return this; return this;
}, },
die: function( type, fn ) { die: function( type, fn ) {
jQuery( this.context ).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null ); jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
return this; return this;
} }
}); });
function liveHandler( event ) { function liveHandler( event ) {
var check = new RegExp("(^|\\.)" + event.type + "(\\.|$)"), var stop = true, elems = [];
stop = true, elems = [];
jQuery.each( jQuery.data( this, "events" ).live || [], function( i, fn ) { jQuery.each( jQuery.data( this, "events" ).live || [], function( i, fn ) {
if ( check.test( fn.type ) ) { if ( fn.live === event.type ) {
var elem = jQuery( event.target ).closest( fn.data )[0]; var elem = jQuery( event.target ).closest( fn.selector )[0];
if ( elem ) { if ( elem ) {
elems.push({ elem: elem, fn: fn }); elems.push({ elem: elem, fn: fn });
} }
@ -626,7 +618,8 @@ function liveHandler( event ) {
jQuery.each(elems, function() { jQuery.each(elems, function() {
event.currentTarget = this.elem; event.currentTarget = this.elem;
if ( this.fn.call( this.elem, event, this.fn.data ) === false ) { event.data = this.fn.data
if ( this.fn.call( this.elem, event, this.fn.selector ) === false ) {
return (stop = false); return (stop = false);
} }
}); });

View file

@ -490,7 +490,7 @@ test("toggle(Function, Function, ...)", function() {
}); });
test(".live()/.die()", function() { test(".live()/.die()", function() {
expect(52); expect(53);
var submit = 0, div = 0, livea = 0, liveb = 0; var submit = 0, div = 0, livea = 0, liveb = 0;
@ -579,6 +579,9 @@ test(".live()/.die()", function() {
jQuery("#foo").trigger('click'); jQuery("#foo").trigger('click');
equals( clicked, 2, "die with a context"); equals( clicked, 2, "die with a context");
// Test binding with event data
jQuery("#foo").live("click", true, function(e){ equals( e.data, true, "live with event data" ); });
jQuery("#foo").trigger("click").die("click");
// Verify that return false prevents default action // Verify that return false prevents default action
jQuery("#anchor2").live("click", function(){ return false; }); jQuery("#anchor2").live("click", function(){ return false; });