views:

87

answers:

2

So I have a animation chain (.animate().animate().animate()), and on the last .animate(), there is a callback to do some clean-up.

The animation is triggered by the hash in the address changing (#page1, #page2, etc.) -- so when the user changes the history state rapidly, if there is a currently executing animation, it needs to stop so they don't queue up. The problem is, if I add a .stop(true, true), it appears only to jump to end of the currently running animation -- and executes only its callback, if there is one. What I need is for it to jump to the end of all of the chained animations, and fire all of the callbacks (well, really just the last one).

Is this possible somehow? Huge thanks.

A: 

If you were to call

$("#myAnimatedElement").queue().last();

you should be able to retrieve the last animation that's meant to be run, but I don't know whether 1) there's a way to retrieve the callback and run it yourself or 2) whether, if you call that last function and then immediately call .stop(true, true), the callback would run for that last animation. Try it.

JacobM
Aha! A perfect excuse to explore `.queue()`. Turns out `.queue().last()` won't work b/c `.queue()` returns a standard JS array -- but this lead me to a working solution, so big thanks.
JKS
+1  A: 

The answer is very simple. Thanks to JacobM for inspiration.

(function($){
    $.fn.extend({
        hardStop: function(){
            return this.each(function(){
                var e = $(this);
                while (e.queue().length){
                    e.stop(false, true);
                }
            });
        }
    });
})(jQuery);

$("#element").hardStop();

Late edit: I noticed that on complicated animation chains it's necessary to make sure that completing a callback doesn't add more functions to the fx queue of an already "cleared" element (given that multiple elements are included in the original selector):

(function($){
    $.fn.extend({
        hardStop: function(){
            var stopped = false
            while (!stopped) {
                this.each(function(){
                    var e = $(this);
                    while (e.queue().length){
                        e.stop(false, true);
                    }
                });
                stopped = true;
                this.each(function(){
                    var e = $(this);
                    if (e.queue().length){
                        stopped = false;
                    }
                });
            }
        }
    });
})(jQuery);

I have a feeling this solution could be made simpler...

JKS