Permalink
Browse files

Fix #13103. Add .finish() method. Close gh-1118.

  • Loading branch information...
gnarf authored and dmethvin committed Jan 8, 2013
1 parent 62acda8 commit b6abb31df4d5be80dc13844d9988fb0c990ae5ae
Showing with 105 additions and 4 deletions.
  1. +55 −4 src/effects.js
  2. +1 −0 src/queue.js
  3. +49 −0 test/unit/effects.js
@@ -72,13 +72,17 @@ function createTweens( animation, props ) {

function Animation( elem, properties, options ) {
var result,
stopped,
index = 0,
length = animationPrefilters.length,
deferred = jQuery.Deferred().always( function() {
// don't match elem in the :animated selector
delete tick.elem;
}),
tick = function() {
if ( stopped ) {
return false;
}
var currentTime = fxNow || createFxNow(),
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
@@ -120,7 +124,10 @@ function Animation( elem, properties, options ) {
// if we are going to the end, we want to run all the tweens
// otherwise we skip this part
length = gotoEnd ? animation.tweens.length : 0;

if ( stopped ) {
return this;
}
stopped = true;
for ( ; index < length ; index++ ) {
animation.tweens[ index ].run( 1 );
}
@@ -468,12 +475,15 @@ jQuery.fn.extend({
doAnimation = function() {
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation( this, jQuery.extend( {}, prop ), optall );

// Empty animations resolve immediately
if ( empty ) {
doAnimation.finish = function() {
anim.stop( true );
};
// Empty animations, or finishing resolves immediately
if ( empty || jQuery._data( this, "finish" ) ) {
anim.stop( true );
}
};
doAnimation.finish = doAnimation;

return empty || optall.queue === false ?
this.each( doAnimation ) :
@@ -528,6 +538,47 @@ jQuery.fn.extend({
jQuery.dequeue( this, type );
}
});
},
finish: function( type ) {
if ( type !== false ) {
type = type || "fx";
}
return this.each(function() {
var index,
data = jQuery._data( this ),
queue = data[ type + "queue" ],
hooks = data[ type + "queueHooks" ],
timers = jQuery.timers,
length = queue ? queue.length : 0;

// enable finishing flag on private data
data.finish = true;

// empty the queue first
jQuery.queue( this, type, [] );

if ( hooks && hooks.cur && hooks.cur.finish ) {
hooks.cur.finish.call( this );
}

// look for any active animations, and finish them
for ( index = timers.length; index--; ) {
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
timers[ index ].anim.stop( true );
timers.splice( index, 1 );
}
}

// look for any animations in the old queue and finish them
for ( index = 0; index < length; index++ ) {
if ( queue[ index ] && queue[ index ].finish ) {
queue[ index ].finish.call( this );
}
}

// turn off finishing flag
delete data.finish;
});
}
});

@@ -35,6 +35,7 @@ jQuery.extend({
startLength--;
}

hooks.cur = fn;
if ( fn ) {

// Add a progress sentinel to prevent the fx queue from being
@@ -1875,4 +1875,53 @@ test( "jQuery.fx.start & jQuery.fx.stop hook points", function() {
jQuery.fx.stop = oldStop;
});

test( ".finish() completes all queued animations", function() {
var animations = {
top: 100,
left: 100,
height: 100,
width: 100
},
div = jQuery("<div>");

expect( 11 );

jQuery.each( animations, function( prop, value ) {
var anim = {};
anim[ prop ] = value;
// the delay shouldn't matter at all!
div.css( prop, 1 ).animate( anim, function() {
ok( true, "Called animation callback" );
}).delay( 100 );
});
equal( div.queue().length, 8, "8 animations in the queue" );
div.finish();
jQuery.each( animations, function( prop, value ) {
equal( parseFloat( div.css( prop ) ), value, prop + " finished at correct value" );
});
equal( div.queue().length, 0, "empty queue when done" );
equal( div.is(":animated"), false, ":animated doesn't match" );

// cleanup
div.remove();
// leaves a "shadow timer" which does nothing around, need to force a tick
jQuery.fx.tick();
});

test( ".finish() calls finish of custom queue functions", function() {
function queueTester( next ) {

}
var div = jQuery( "<div>" );

expect( 3 );
queueTester.finish = function() {
ok( true, "Finish called on custom queue function" );
};

div.queue( queueTester ).queue( queueTester ).queue( queueTester ).finish();

div.remove();
});

} // if ( jQuery.fx )

0 comments on commit b6abb31

Please sign in to comment.