Skip to content

Commit 0a2181d

Browse files
timmywiltimmywil
timmywil
authored andcommitted
Animation state is tracked on toggled/stopped animations using the private data cache. Tests added. Fixes #8685.
- Example: http://jsfiddle.net/timmywil/gqZL5/17/ - http://bugs.jquery.com/ticket/8685
1 parent fa0a33a commit 0a2181d

File tree

2 files changed

+163
-96
lines changed

2 files changed

+163
-96
lines changed

src/effects.js

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ jQuery.fn.extend({
141141
isElement = this.nodeType === 1,
142142
hidden = isElement && jQuery(this).is(":hidden"),
143143
name, val, p, e,
144-
parts, start, end, unit;
144+
parts, start, end, unit,
145+
method;
145146

146147
// will store per property easing and be used to determine when an animation is complete
147148
opt.animatedProperties = {};
@@ -203,7 +204,15 @@ jQuery.fn.extend({
203204
val = prop[ p ];
204205

205206
if ( rfxtypes.test( val ) ) {
206-
e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();
207+
// Tracks whether to show or hide based on private
208+
// data attached to the element
209+
method = jQuery._data( this, "toggle" + p ) || (val === "toggle" ? hidden ? "show" : "hide" : 0);
210+
if ( method ) {
211+
jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
212+
e[ method ]();
213+
} else {
214+
e[ val ]();
215+
}
207216

208217
} else {
209218
parts = rfxnum.exec( val );
@@ -246,6 +255,7 @@ jQuery.fn.extend({
246255
this.each(function() {
247256
var timers = jQuery.timers,
248257
i = timers.length;
258+
249259
// clear marker counters if we know they won't be
250260
if ( !gotoEnd ) {
251261
jQuery._unmark( true, this );
@@ -255,6 +265,8 @@ jQuery.fn.extend({
255265
if ( gotoEnd ) {
256266
// force the next step to be the last
257267
timers[ i ]( true );
268+
} else {
269+
timers[ i ].saveState();
258270
}
259271

260272
timers.splice(i, 1);
@@ -398,6 +410,11 @@ jQuery.fx.prototype = {
398410
}
399411

400412
t.elem = this.elem;
413+
t.saveState = function() {
414+
if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
415+
jQuery._data( self.elem, "fxshow" + self.prop, self.start );
416+
}
417+
};
401418

402419
if ( t() && jQuery.timers.push(t) && !timerId ) {
403420
// Use requestAnimationFrame instead of setInterval if available
@@ -419,14 +436,20 @@ jQuery.fx.prototype = {
419436

420437
// Simple 'show' function
421438
show: function() {
439+
var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
440+
422441
// Remember where we started, so that we can go back to it later
423-
this.options.orig[ this.prop ] = jQuery.style( this.elem, this.prop );
442+
this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
424443
this.options.show = true;
425444

426445
// Begin the animation
427-
// Make sure that we start at a small width/height to avoid any
428-
// flash of content
429-
this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
446+
// Make sure that we start at a small width/height to avoid any flash of content
447+
if ( dataShow !== undefined ) {
448+
// This show is picking up where a previous hide or show left off
449+
this.custom( this.cur(), dataShow );
450+
} else {
451+
this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
452+
}
430453

431454
// Start by showing the element
432455
jQuery( this.elem ).show();
@@ -435,7 +458,7 @@ jQuery.fx.prototype = {
435458
// Simple 'hide' function
436459
hide: function() {
437460
// Remember where we started, so that we can go back to it later
438-
this.options.orig[ this.prop ] = jQuery.style( this.elem, this.prop );
461+
this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
439462
this.options.hide = true;
440463

441464
// Begin the animation
@@ -448,7 +471,7 @@ jQuery.fx.prototype = {
448471
done = true,
449472
elem = this.elem,
450473
options = this.options,
451-
i, n;
474+
p, n;
452475

453476
if ( gotoEnd || t >= options.duration + this.startTime ) {
454477
this.now = this.end;
@@ -457,8 +480,8 @@ jQuery.fx.prototype = {
457480

458481
options.animatedProperties[ this.prop ] = true;
459482

460-
for ( i in options.animatedProperties ) {
461-
if ( options.animatedProperties[ i ] !== true ) {
483+
for ( p in options.animatedProperties ) {
484+
if ( options.animatedProperties[ p ] !== true ) {
462485
done = false;
463486
}
464487
}
@@ -479,8 +502,11 @@ jQuery.fx.prototype = {
479502

480503
// Reset the properties, if the item has been hidden or shown
481504
if ( options.hide || options.show ) {
482-
for ( var p in options.animatedProperties ) {
483-
jQuery.style( elem, p, options.orig[p] );
505+
for ( p in options.animatedProperties ) {
506+
jQuery.style( elem, p, options.orig[ p ] );
507+
jQuery.removeData( elem, "fxshow" + p, true );
508+
// Toggle data is no longer needed
509+
jQuery.removeData( elem, "toggle" + p, true );
484510
}
485511
}
486512

@@ -512,7 +538,7 @@ jQuery.fx.prototype = {
512538

513539
jQuery.extend( jQuery.fx, {
514540
tick: function() {
515-
for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) {
541+
for ( var timers = jQuery.timers, i = 0; i < timers.length; i++ ) {
516542
if ( !timers[ i ]() ) {
517543
timers.splice(i--, 1);
518544
}

0 commit comments

Comments
 (0)