You know, this is the kind of thing you can write yourself in just a few
lines of code, without having to save state in the DOM (which I find
distasteful). Here's a standalone version that doesn't do anything tricky
like that. The only state it keeps is right there in the function itself.

While we're at it, we'll make it more general so it can sequence callbacks
for any event, and we'll give it a better name. (toggle specifically implies
*two* states, not many.)

$.fn.bindSequence = function( name ) {
    var args = arguments, i = 1;
    this.bind( name, function( event ) {
        args[i].call( this, event );
        if( ++i >= args.length ) i = 1;
    });
    return this;
};

You can use it like this:

$('.testClass').bindSequence( 'click',
    function() { console.log( this.className + ' X' ); },
    function() { console.log( this.className + ' Y' ); },
    function() { console.log( this.className + ' Z' ); }
);

Looking at the toggle() source code, I see that it does some extra work
having to do with unbinding. But you don't really need that either. Since
bindSequence() lets you pass in the event name, you can bind and unbind like
this:

$('.testClass').bindSequence( 'click.mysequence',
    ...
);

$('.testClass').unbind( 'click.mysequence' );

Here's a test page:

http://mg.to/jquery/bindsequence.html

Try the "click me" button several times, and then click the "unbind" button
and go back and click the "click me" button again.

Now you don't have to patch jQuery! :-)

-Mike


On Fri, Sep 18, 2009 at 6:40 PM, Mr Speaker <mrspea...@gmail.com> wrote:

>
> I recently deadline forced me to make a change to the jQuery core to
> fix an issue I was having. Now that I'm refactoring the code, I'd like
> to know if I've missed something obvious, or if there's a better way
> to do it. I couldn't find any reference to this issue on the forums or
> bug tracker.
>
> <div id="btnClose" class="icon">Close</div>
>
> $(".icon").toggle(
>        function(){ $(this).removeClass('two2').addClass('two1') },
>        function(){ $(this).removeClass('two1').addClass('two2') }
> );
>
> $("#btnClose").toggle(
>        function(){ $(this).removeClass('one2 one3').addClass('one1'); },
>        function(){ $(this).removeClass('one1 one3').addClass('one2'); },
>        function(){ $(this).removeClass('one1 one2').addClass('one3'); }
> );
>
> This doesn't work with jQuery (stable or nightly), as internally the
> current toggle state is stored on the DOM node itself as "lastToggle"
> and so increments multiple times per click.
>
> I had to modify the return statement of the toggle function so that I
> could use the proxy guid as part of the counter identifier:
>
> var proxy = jQuery.event.proxy( fn, function(event) {
>        // Figure out which function to execute
>        this[ 'lastToggle' + proxy.guid ] = ( this[ 'lastToggle' +
> proxy.guid ] || 0 ) % i;
>
>        // Make sure that clicks stop
>        event.preventDefault();
>
>        // and execute the function
>        return args[ this[ 'lastToggle' + proxy.guid ]++ ].apply( this,
> arguments ) || false;
> })
> return this.click( proxy );
>
> Which appears to work perfectly (and got me through my deadline ;) but
> I'm sure isn't the most elegant way to do it. Am I even supposed to be
> able to add multiple toggle event handlers?
>
> Thanks!
>
> Earle
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"jQuery Development" group.
To post to this group, send email to jquery-dev@googlegroups.com
To unsubscribe from this group, send email to 
jquery-dev+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/jquery-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to