Merging in jQuery.proxy() branch.
authorjeresig <jeresig@gmail.com>
Wed, 6 Jan 2010 00:18:39 +0000 (19:18 -0500)
committerjeresig <jeresig@gmail.com>
Wed, 6 Jan 2010 00:18:39 +0000 (19:18 -0500)
src/core.js
src/event.js
test/unit/core.js
test/unit/event.js

index 8bd8044..975d23c 100644 (file)
@@ -619,6 +619,37 @@ jQuery.extend({
                return ret.concat.apply( [], ret );
        },
 
+       // A global GUID counter for objects
+       guid: 1,
+
+       proxy: function( fn, proxy, thisObject ) {
+               if ( arguments.length === 2 ) {
+                       if ( typeof proxy === "string" ) {
+                               thisObject = fn;
+                               fn = thisObject[ proxy ];
+                               proxy = undefined;
+
+                       } else if ( proxy && !jQuery.isFunction( proxy ) ) {
+                               thisObject = proxy;
+                               proxy = undefined;
+                       }
+               }
+
+               if ( !proxy && fn ) {
+                       proxy = function() {
+                               return fn.apply( thisObject || this, arguments );
+                       };
+               }
+
+               // Set the guid of unique handler to the same of original handler, so it can be removed
+               if ( fn ) {
+                       proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+               }
+
+               // So proxy can be declared as an argument
+               return proxy;
+       },
+
        // Use of jQuery.browser is frowned upon.
        // More details: http://docs.jquery.com/Utilities/jQuery.browser
        uaMatch: function( ua ) {
index 64b202d..fe98794 100644 (file)
@@ -26,7 +26,7 @@ jQuery.event = {
 
                // Make sure that the function being executed has a unique ID
                if ( !handler.guid ) {
-                       handler.guid = this.guid++;
+                       handler.guid = jQuery.guid++;
                }
 
                // if data is passed, bind to handler
@@ -35,7 +35,7 @@ jQuery.event = {
                        var fn = handler;
 
                        // Create unique handler function, wrapped around original handler
-                       handler = this.proxy( fn );
+                       handler = jQuery.proxy( fn );
 
                        // Store data in unique handler
                        handler.data = data;
@@ -114,7 +114,6 @@ jQuery.event = {
                elem = null;
        },
 
-       guid: 1,
        global: {},
 
        // Detach an event or set of events from an element
@@ -405,23 +404,11 @@ jQuery.event = {
                return event;
        },
 
-       proxy: function( fn, proxy, thisObject ) {
-               if ( proxy !== undefined && !jQuery.isFunction( proxy ) ) {
-                       thisObject = proxy;
-                       proxy = undefined;
-               }
-
-               // FIXME: Should proxy be redefined to be applied with thisObject if defined?
-               proxy = proxy || function() {
-                       return fn.apply( thisObject !== undefined ? thisObject : this, arguments );
-               };
+       // Deprecated, use jQuery.guid instead
+       guid: 1E8,
 
-               // Set the guid of unique handler to the same of original handler, so it can be removed
-               proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
-
-               // So proxy can be declared as an argument
-               return proxy;
-       },
+       // Deprecated, use jQuery.proxy instead
+       proxy: jQuery.proxy,
 
        special: {
                ready: {
@@ -759,7 +746,7 @@ if ( document.addEventListener ) {
 }
 
 jQuery.each(["bind", "one"], function( i, name ) {
-       jQuery.fn[ name ] = function( type, data, fn, thisObject ) {
+       jQuery.fn[ name ] = function( type, data, fn ) {
                // Handle object literals
                if ( typeof type === "object" ) {
                        for ( var key in type ) {
@@ -773,11 +760,12 @@ jQuery.each(["bind", "one"], function( i, name ) {
                        fn = data;
                        data = undefined;
                }
-               fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
-               var handler = name === "one" ? jQuery.event.proxy( fn, function( event ) {
+
+               var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
                        jQuery( this ).unbind( event, handler );
                        return fn.apply( this, arguments );
                }) : fn;
+
                return type === "unload" && name !== "one" ?
                        this.one( type, data, fn, thisObject ) :
                        this.each(function() {
@@ -822,10 +810,10 @@ jQuery.fn.extend({
 
                // link all the functions, so any of them can unbind this click handler
                while ( i < args.length ) {
-                       jQuery.event.proxy( fn, args[ i++ ] );
+                       jQuery.proxy( fn, args[ i++ ] );
                }
 
-               return this.click( jQuery.event.proxy( fn, function( event ) {
+               return this.click( jQuery.proxy( fn, function( event ) {
                        // Figure out which function to execute
                        var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
                        jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
@@ -842,17 +830,16 @@ jQuery.fn.extend({
                return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
        },
 
-       live: function( type, data, fn, thisObject ) {
+       live: function( type, data, fn ) {
                if ( jQuery.isFunction( data ) ) {
-                       if ( fn !== undefined ) {
-                               thisObject = fn;
-                       }
                        fn = data;
                        data = undefined;
                }
+
                jQuery( this.context ).bind( liveConvert( type, this.selector ), {
                        data: data, selector: this.selector, live: type
-               }, fn, thisObject );
+               }, fn );
+
                return this;
        },
 
index 3020543..d50997b 100644 (file)
@@ -825,3 +825,22 @@ test("jQuery.isEmptyObject", function(){
        // What about this ?
        // equals(true, jQuery.isEmptyObject(null), "isEmptyObject on null" );
 });
+
+test("jQuery.proxy", function(){
+       expect(4);
+
+       var test = function(){ equals( this, thisObject, "Make sure that scope is set properly." ); };
+       var thisObject = { foo: "bar", method: test };
+
+       // Make sure normal works
+       test.call( thisObject );
+
+       // Basic scoping
+       jQuery.proxy( test, thisObject )();
+
+       // Make sure it doesn't freak out
+       equals( jQuery.proxy( null, thisObject ), undefined, "Make sure no function was returned." );
+
+       // Use the string shortcut
+       jQuery.proxy( thisObject, "method" )();
+});
index 70c721f..8a9e48b 100644 (file)
@@ -232,8 +232,8 @@ test("bind(), with different this object", function() {
                };
        
        jQuery("#firstp")
-               .bind("click", handler1, thisObject).click().unbind("click", handler1)
-               .bind("click", data, handler2, thisObject).click().unbind("click", handler2);
+               .bind("click", jQuery.proxy(handler1, thisObject)).click().unbind("click", handler1)
+               .bind("click", data, jQuery.proxy(handler2, thisObject)).click().unbind("click", handler2);
 
        ok( !jQuery.data(jQuery("#firstp")[0], "events"), "Event handler unbound when using different this object and data." );
 });
@@ -706,15 +706,15 @@ test(".live()/.die()", function() {
        jQuery("#foo").trigger("click", true).die("click");
 
        // Test binding with different this object
-       jQuery("#foo").live("click", function(e){ equals( this.foo, "bar", "live with event scope" ); }, { foo: "bar" });
+       jQuery("#foo").live("click", jQuery.proxy(function(e){ equals( this.foo, "bar", "live with event scope" ); }, { foo: "bar" }));
        jQuery("#foo").trigger("click").die("click");
 
        // Test binding with different this object, event data, and trigger data
-       jQuery("#foo").live("click", true, function(e, data){
+       jQuery("#foo").live("click", true, jQuery.proxy(function(e, data){
                equals( e.data, true, "live with with different this object, event data, and trigger data" );
                equals( this.foo, "bar", "live with with different this object, event data, and trigger data" ); 
                equals( data, true, "live with with different this object, event data, and trigger data")
-       }, { foo: "bar" });
+       }, { foo: "bar" }));
        jQuery("#foo").trigger("click", true).die("click");
 
        // Verify that return false prevents default action