From 71efbdd3b26f3a283f8d4bfdcc7b6343142027b9 Mon Sep 17 00:00:00 2001 From: Brandon Aaron Date: Thu, 30 Apr 2009 21:44:25 +0000 Subject: [PATCH] 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 --- src/event.js | 75 ++++++++++++++++++++++++---------------------------- test/unit/event.js | 5 +++- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/event.js b/src/event.js index 7a28080..6987300 100644 --- a/src/event.js +++ b/src/event.js @@ -60,10 +60,15 @@ jQuery.event = { handler.type = namespaces.slice().sort().join("."); // Get the current list of functions bound to this event - var handlers = events[ type ]; - - if ( this.specialAll[ type ] ) { - this.specialAll[ type ].setup.call( elem, data, namespaces ); + var handlers = events[ type ], + special = this.special[ type ] || {}; + + if ( special.add ) { + 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 @@ -73,7 +78,7 @@ jQuery.event = { // Check for a special event handler // Only use addEventListener/attachEvent if the special // 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 if ( elem.addEventListener ) { elem.addEventListener( type, handle, false ); @@ -128,9 +133,10 @@ jQuery.event = { var namespaces = type.split("."); type = namespaces.shift(); 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 if ( handler ) { delete events[ type ][ handler.guid ]; @@ -145,8 +151,8 @@ jQuery.event = { } } - if ( this.specialAll[ type ] ) { - this.specialAll[ type ].teardown.call( elem, namespaces ); + if ( special.remove ) { + special.remove.call( elem, namespaces ); } // remove generic event handler if no more handlers exist @@ -381,28 +387,17 @@ jQuery.event = { // Make sure the ready event is setup setup: bindReady, teardown: function() {} - } - }, - - specialAll: { + }, + live: { - setup: function( selector, namespaces ) { - jQuery.event.add( this, namespaces[0], liveHandler ); + add: function( proxy, data, namespaces ) { + jQuery.extend( proxy, data || {} ); + proxy.guid += data.selector + data.live; + jQuery.event.add( this, data.live, liveHandler ); }, - teardown: function( namespaces ) { - if ( namespaces.length ) { - var remove = 0, name = new 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 ); - } - } + + teardown: function( namespaces ) { + jQuery.event.remove( this, namespaces[0], liveHandler ); } } } @@ -592,28 +587,25 @@ jQuery.fn.extend({ return this; }, - live: function( type, fn ) { - var proxy = jQuery.event.proxy( fn ); - proxy.guid += this.selector + type; - - jQuery( this.context ).bind( liveConvert( type, this.selector ), this.selector, proxy ); - + live: function( type, data, fn ) { + jQuery( this.context ).bind( liveConvert( type, this.selector ), { + data: fn && data, selector: this.selector, live: type + }, fn || data ); return this; }, 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; } }); function liveHandler( event ) { - var check = new RegExp("(^|\\.)" + event.type + "(\\.|$)"), - stop = true, elems = []; + var stop = true, elems = []; 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 ( fn.live === event.type ) { + var elem = jQuery( event.target ).closest( fn.selector )[0]; if ( elem ) { elems.push({ elem: elem, fn: fn }); } @@ -626,7 +618,8 @@ function liveHandler( event ) { jQuery.each(elems, function() { 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); } }); diff --git a/test/unit/event.js b/test/unit/event.js index 8906728..b2270ad 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -490,7 +490,7 @@ test("toggle(Function, Function, ...)", function() { }); test(".live()/.die()", function() { - expect(52); + expect(53); var submit = 0, div = 0, livea = 0, liveb = 0; @@ -579,6 +579,9 @@ test(".live()/.die()", function() { jQuery("#foo").trigger('click'); 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 jQuery("#anchor2").live("click", function(){ return false; }); -- 1.7.10.4