Added a new liveQuery/event delegation hybrid method: .live and .die. Easily adapts event delegation to the jQuery style. $("div").live("click", fn); $("div > #foo").live("submit", fn); $("div").die("click");
This commit is contained in:
parent
67ded9a36a
commit
c03a280155
96
src/event.js
96
src/event.js
|
@ -53,12 +53,15 @@ jQuery.event = {
|
|||
// jQuery(...).bind("mouseover mouseout", fn);
|
||||
jQuery.each(types.split(/\s+/), function(index, type) {
|
||||
// Namespaced event handlers
|
||||
var parts = type.split(".");
|
||||
type = parts.shift();
|
||||
handler.type = parts.sort().join(".");
|
||||
var namespaces = type.split(".");
|
||||
type = namespaces.shift();
|
||||
handler.type = namespaces.slice().sort().join(".");
|
||||
|
||||
// Get the current list of functions bound to this event
|
||||
var handlers = events[type];
|
||||
|
||||
if ( jQuery.event.specialAll[type] )
|
||||
jQuery.event.specialAll[type].setup.call(elem, data, namespaces);
|
||||
|
||||
// Init the event handler queue
|
||||
if (!handlers) {
|
||||
|
@ -67,7 +70,7 @@ jQuery.event = {
|
|||
// Check for a special event handler
|
||||
// Only use addEventListener/attachEvent if the special
|
||||
// events handler returns false
|
||||
if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem,data) === false ) {
|
||||
if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem, data, namespaces) === false ) {
|
||||
// Bind the global event handler to the element
|
||||
if (elem.addEventListener)
|
||||
elem.addEventListener(type, handle, false);
|
||||
|
@ -114,9 +117,9 @@ jQuery.event = {
|
|||
// jQuery(...).unbind("mouseover mouseout", fn);
|
||||
jQuery.each(types.split(/\s+/), function(index, type){
|
||||
// Namespaced event handlers
|
||||
var namespace = type.split(".");
|
||||
type = namespace.shift();
|
||||
namespace = RegExp("(^|\\.)" + namespace.sort().join(".*\\.") + "(\\.|$)");
|
||||
var namespaces = type.split(".");
|
||||
type = namespaces.shift();
|
||||
var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
|
||||
|
||||
if ( events[type] ) {
|
||||
// remove the given handler for the given type
|
||||
|
@ -129,11 +132,14 @@ jQuery.event = {
|
|||
// Handle the removal of namespaced events
|
||||
if ( namespace.test(events[type][handler].type) )
|
||||
delete events[type][handler];
|
||||
|
||||
if ( jQuery.event.specialAll[type] )
|
||||
jQuery.event.specialAll[type].teardown.call(elem, namespaces);
|
||||
|
||||
// remove generic event handler if no more handlers exist
|
||||
for ( ret in events[type] ) break;
|
||||
if ( !ret ) {
|
||||
if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
|
||||
if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem, namespaces) === false ) {
|
||||
if (elem.removeEventListener)
|
||||
elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
|
||||
else if (elem.detachEvent)
|
||||
|
@ -157,7 +163,7 @@ jQuery.event = {
|
|||
}
|
||||
},
|
||||
|
||||
trigger: function(type, data, elem, donative, extra) {
|
||||
trigger: function(type, data, elem, donative, extra, dohandlers) {
|
||||
// Clone the incoming data, if any
|
||||
data = jQuery.makeArray(data);
|
||||
|
||||
|
@ -203,14 +209,16 @@ jQuery.event = {
|
|||
if ( exclusive )
|
||||
data[0].exclusive = true;
|
||||
|
||||
// Trigger the event, it is assumed that "handle" is a function
|
||||
var handle = jQuery.data(elem, "handle");
|
||||
if ( handle )
|
||||
val = handle.apply( elem, data );
|
||||
if ( dohandlers !== false ) {
|
||||
// Trigger the event, it is assumed that "handle" is a function
|
||||
var handle = jQuery.data(elem, "handle");
|
||||
if ( handle )
|
||||
val = handle.apply( elem, data );
|
||||
|
||||
// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
|
||||
if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
|
||||
val = false;
|
||||
// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
|
||||
if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
|
||||
val = false;
|
||||
}
|
||||
|
||||
if ( donative !== false && val !== false ) {
|
||||
var parent = elem.parentNode || elem.ownerDocument;
|
||||
|
@ -248,18 +256,18 @@ jQuery.event = {
|
|||
|
||||
handle: function(event) {
|
||||
// returned undefined or false
|
||||
var val, ret, namespace, all, handlers;
|
||||
var val, ret, all, handlers;
|
||||
|
||||
event = arguments[0] = jQuery.event.fix( event || window.event );
|
||||
|
||||
// Namespaced event handlers
|
||||
namespace = event.type.split(".");
|
||||
event.type = namespace.shift();
|
||||
var namespaces = event.type.split(".");
|
||||
event.type = namespaces.shift();
|
||||
|
||||
// Cache this now, all = true means, any handler
|
||||
all = !namespace.length && !event.exclusive;
|
||||
all = !namespaces.length && !event.exclusive;
|
||||
|
||||
namespace = RegExp("(^|\\.)" + namespace.sort().join(".*\\.") + "(\\.|$)");
|
||||
var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
|
||||
|
||||
handlers = ( jQuery.data(this, "events") || {} )[event.type];
|
||||
|
||||
|
@ -381,6 +389,27 @@ jQuery.event = {
|
|||
setup: bindReady,
|
||||
teardown: function() {}
|
||||
}
|
||||
},
|
||||
|
||||
specialAll: {
|
||||
live: {
|
||||
setup: function( selector, namespaces ){
|
||||
jQuery.event.add( this, namespaces[0], liveHandler );
|
||||
},
|
||||
teardown: function( namespaces ){
|
||||
if ( namespaces.length ) {
|
||||
var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
|
||||
|
||||
jQuery.each( (jQuery.data(this, "events").live || {}), function(){
|
||||
if ( name.test(this.type) )
|
||||
remove++;
|
||||
});
|
||||
|
||||
if ( remove <= 1 )
|
||||
jQuery.event.remove( this, namespaces[0], liveHandler );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -493,9 +522,34 @@ jQuery.fn.extend({
|
|||
jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
live: function( type, fn ){
|
||||
jQuery(document).bind( liveConvert(type, this.selector), this.selector, fn );
|
||||
return this;
|
||||
},
|
||||
|
||||
die: function( type, fn ){
|
||||
jQuery(document).unbind( liveConvert(type, this.selector), fn );
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
function liveHandler( event ){
|
||||
var check = RegExp("(^|\\.)" + event.type + "(\\.|$)");
|
||||
jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){
|
||||
if ( check.test(fn.type) ) {
|
||||
var elem = jQuery(event.target).closest(fn.data)[0];
|
||||
if ( elem )
|
||||
jQuery.event.trigger( event.type, fn.data, elem, false, fn, false );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function liveConvert(type, selector){
|
||||
return ["live", type, selector.replace(/\./g, "_")].join(".");
|
||||
}
|
||||
|
||||
jQuery.extend({
|
||||
isReady: false,
|
||||
readyList: [],
|
||||
|
|
|
@ -418,6 +418,72 @@ test("toggle(Function, Function, ...)", function() {
|
|||
var data = jQuery.data( $div[0], 'events' );
|
||||
ok( !data, "Unbinding one function from toggle unbinds them all");
|
||||
});
|
||||
|
||||
test(".live()/.die()", function() {
|
||||
expect(28);
|
||||
|
||||
var submit = 0, div = 0, livea = 0, liveb = 0;
|
||||
|
||||
jQuery("div").live("submit", function(){ submit++; return false; });
|
||||
jQuery("div").live("click", function(){ div++; });
|
||||
jQuery("div#nothiddendiv").live("click", function(){ livea++; });
|
||||
jQuery("div#nothiddendivchild").live("click", function(){ liveb++; });
|
||||
|
||||
// Nothing should trigger on the body
|
||||
jQuery("body").trigger("click");
|
||||
equals( submit, 0, "Click on body" );
|
||||
equals( div, 0, "Click on body" );
|
||||
equals( livea, 0, "Click on body" );
|
||||
equals( liveb, 0, "Click on body" );
|
||||
|
||||
// This should trigger two events
|
||||
jQuery("div#nothiddendiv").trigger("click");
|
||||
equals( submit, 0, "Click on div" );
|
||||
equals( div, 1, "Click on div" );
|
||||
equals( livea, 1, "Click on div" );
|
||||
equals( liveb, 0, "Click on div" );
|
||||
|
||||
// This should trigger three events (w/ bubbling)
|
||||
jQuery("div#nothiddendivchild").trigger("click");
|
||||
equals( submit, 0, "Click on inner div" );
|
||||
equals( div, 2, "Click on inner div" );
|
||||
equals( livea, 2, "Click on inner div" );
|
||||
equals( liveb, 1, "Click on inner div" );
|
||||
|
||||
// This should trigger one submit
|
||||
jQuery("div#nothiddendivchild").trigger("submit");
|
||||
equals( submit, 1, "Submit on div" );
|
||||
equals( div, 2, "Submit on div" );
|
||||
equals( livea, 2, "Submit on div" );
|
||||
equals( liveb, 1, "Submit on div" );
|
||||
|
||||
// Make sure no other events were removed in the process
|
||||
jQuery("div#nothiddendivchild").trigger("click");
|
||||
equals( submit, 1, "die Click on inner div" );
|
||||
equals( div, 3, "die Click on inner div" );
|
||||
equals( livea, 3, "die Click on inner div" );
|
||||
equals( liveb, 2, "die Click on inner div" );
|
||||
|
||||
// Now make sure that the removal works
|
||||
jQuery("div#nothiddendivchild").die("click");
|
||||
jQuery("div#nothiddendivchild").trigger("click");
|
||||
equals( submit, 1, "die Click on inner div" );
|
||||
equals( div, 4, "die Click on inner div" );
|
||||
equals( livea, 4, "die Click on inner div" );
|
||||
equals( liveb, 2, "die Click on inner div" );
|
||||
|
||||
// Make sure that the click wasn't removed too early
|
||||
jQuery("div#nothiddendiv").trigger("click");
|
||||
equals( submit, 1, "die Click on inner div" );
|
||||
equals( div, 5, "die Click on inner div" );
|
||||
equals( livea, 5, "die Click on inner div" );
|
||||
equals( liveb, 2, "die Click on inner div" );
|
||||
|
||||
jQuery("div#nothiddendiv").die("click");
|
||||
jQuery("div").die("click");
|
||||
jQuery("div").die("submit");
|
||||
});
|
||||
|
||||
/*
|
||||
test("jQuery(function($) {})", function() {
|
||||
stop();
|
||||
|
|
Loading…
Reference in a new issue