11 ], function( jQuery, pnum, cssExpand, isHidden, Tween ) {
14 rfxtypes = /^(?:toggle|show|hide)$/,
15 rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
17 animationPrefilters = [ defaultPrefilter ],
19 "*": [function( prop, value ) {
20 var tween = this.createTween( prop, value ),
22 parts = rfxnum.exec( value ),
23 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
25 // Starting value computation is required for potential unit mismatches
26 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
27 rfxnum.exec( jQuery.css( tween.elem, prop ) ),
31 if ( start && start[ 3 ] !== unit ) {
32 // Trust units reported by jQuery.css
33 unit = unit || start[ 3 ];
35 // Make sure we update the tween properties later on
38 // Iteratively approximate from a nonzero starting point
42 // If previous iteration zeroed out, double until we get *something*
43 // Use a string for doubling factor so we don't accidentally see scale as unchanged below
44 scale = scale || ".5";
47 start = start / scale;
48 jQuery.style( tween.elem, prop, start + unit );
50 // Update scale, tolerating zero or NaN from tween.cur()
51 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
52 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
55 // Update tween properties
57 start = tween.start = +start || +target || 0;
59 // If a +=/-= token was provided, we're doing a relative animation
60 tween.end = parts[ 1 ] ?
61 start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
69 // Animations created synchronously will run synchronously
70 function createFxNow() {
71 setTimeout(function() {
74 return ( fxNow = jQuery.now() );
77 function createTween( value, prop, animation ) {
79 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
81 length = collection.length;
82 for ( ; index < length; index++ ) {
83 if ( (tween = collection[ index ].call( animation, prop, value )) ) {
85 // we're done with this property
91 function Animation( elem, properties, options ) {
95 length = animationPrefilters.length,
96 deferred = jQuery.Deferred().always( function() {
97 // don't match elem in the :animated selector
104 var currentTime = fxNow || createFxNow(),
105 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
106 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
107 temp = remaining / animation.duration || 0,
110 length = animation.tweens.length;
112 for ( ; index < length ; index++ ) {
113 animation.tweens[ index ].run( percent );
116 deferred.notifyWith( elem, [ animation, percent, remaining ]);
118 if ( percent < 1 && length ) {
121 deferred.resolveWith( elem, [ animation ] );
125 animation = deferred.promise({
127 props: jQuery.extend( {}, properties ),
128 opts: jQuery.extend( true, { specialEasing: {} }, options ),
129 originalProperties: properties,
130 originalOptions: options,
131 startTime: fxNow || createFxNow(),
132 duration: options.duration,
134 createTween: function( prop, end ) {
135 var tween = jQuery.Tween( elem, animation.opts, prop, end,
136 animation.opts.specialEasing[ prop ] || animation.opts.easing );
137 animation.tweens.push( tween );
140 stop: function( gotoEnd ) {
142 // if we are going to the end, we want to run all the tweens
143 // otherwise we skip this part
144 length = gotoEnd ? animation.tweens.length : 0;
149 for ( ; index < length ; index++ ) {
150 animation.tweens[ index ].run( 1 );
153 // resolve when we played the last frame
156 deferred.resolveWith( elem, [ animation, gotoEnd ] );
158 deferred.rejectWith( elem, [ animation, gotoEnd ] );
163 props = animation.props;
165 propFilter( props, animation.opts.specialEasing );
167 for ( ; index < length ; index++ ) {
168 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
174 jQuery.map( props, createTween, animation );
176 if ( jQuery.isFunction( animation.opts.start ) ) {
177 animation.opts.start.call( elem, animation );
181 jQuery.extend( tick, {
184 queue: animation.opts.queue
188 // attach callbacks from options
189 return animation.progress( animation.opts.progress )
190 .done( animation.opts.done, animation.opts.complete )
191 .fail( animation.opts.fail )
192 .always( animation.opts.always );
195 function propFilter( props, specialEasing ) {
196 var index, name, easing, value, hooks;
198 // camelCase, specialEasing and expand cssHook pass
199 for ( index in props ) {
200 name = jQuery.camelCase( index );
201 easing = specialEasing[ name ];
202 value = props[ index ];
203 if ( jQuery.isArray( value ) ) {
205 value = props[ index ] = value[ 0 ];
208 if ( index !== name ) {
209 props[ name ] = value;
210 delete props[ index ];
213 hooks = jQuery.cssHooks[ name ];
214 if ( hooks && "expand" in hooks ) {
215 value = hooks.expand( value );
216 delete props[ name ];
218 // not quite $.extend, this wont overwrite keys already present.
219 // also - reusing 'index' from above because we have the correct "name"
220 for ( index in value ) {
221 if ( !( index in props ) ) {
222 props[ index ] = value[ index ];
223 specialEasing[ index ] = easing;
227 specialEasing[ name ] = easing;
232 jQuery.Animation = jQuery.extend( Animation, {
234 tweener: function( props, callback ) {
235 if ( jQuery.isFunction( props ) ) {
239 props = props.split(" ");
244 length = props.length;
246 for ( ; index < length ; index++ ) {
247 prop = props[ index ];
248 tweeners[ prop ] = tweeners[ prop ] || [];
249 tweeners[ prop ].unshift( callback );
253 prefilter: function( callback, prepend ) {
255 animationPrefilters.unshift( callback );
257 animationPrefilters.push( callback );
262 function defaultPrefilter( elem, props, opts ) {
263 /* jshint validthis: true */
264 var prop, value, toggle, tween, hooks, oldfire,
268 hidden = elem.nodeType && isHidden( elem ),
269 dataShow = jQuery._data( elem, "fxshow" );
271 // handle queue: false promises
273 hooks = jQuery._queueHooks( elem, "fx" );
274 if ( hooks.unqueued == null ) {
276 oldfire = hooks.empty.fire;
277 hooks.empty.fire = function() {
278 if ( !hooks.unqueued ) {
285 anim.always(function() {
286 // doing this makes sure that the complete handler will be called
287 // before this completes
288 anim.always(function() {
290 if ( !jQuery.queue( elem, "fx" ).length ) {
297 // height/width overflow pass
298 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
299 // Make sure that nothing sneaks out
300 // Record all 3 overflow attributes because IE does not
301 // change the overflow attribute when overflowX and
302 // overflowY are set to the same value
303 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
305 // Set display property to inline-block for height/width
306 // animations on inline elements that are having width/height animated
307 if ( jQuery.css( elem, "display" ) === "inline" &&
308 jQuery.css( elem, "float" ) === "none" ) {
310 // inline-level elements accept inline-block;
311 // block-level elements need to be inline with layout
312 if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
313 style.display = "inline-block";
321 if ( opts.overflow ) {
322 style.overflow = "hidden";
323 if ( !jQuery.support.shrinkWrapBlocks ) {
324 anim.always(function() {
325 style.overflow = opts.overflow[ 0 ];
326 style.overflowX = opts.overflow[ 1 ];
327 style.overflowY = opts.overflow[ 2 ];
334 for ( prop in props ) {
335 value = props[ prop ];
336 if ( rfxtypes.exec( value ) ) {
337 delete props[ prop ];
338 toggle = toggle || value === "toggle";
339 if ( value === ( hidden ? "hide" : "show" ) ) {
342 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
346 if ( !jQuery.isEmptyObject( orig ) ) {
348 if ( "hidden" in dataShow ) {
349 hidden = dataShow.hidden;
352 dataShow = jQuery._data( elem, "fxshow", {} );
355 // store state if its toggle - enables .stop().toggle() to "reverse"
357 dataShow.hidden = !hidden;
360 jQuery( elem ).show();
362 anim.done(function() {
363 jQuery( elem ).hide();
366 anim.done(function() {
368 jQuery._removeData( elem, "fxshow" );
369 for ( prop in orig ) {
370 jQuery.style( elem, prop, orig[ prop ] );
373 for ( prop in orig ) {
374 tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
376 if ( !( prop in dataShow ) ) {
377 dataShow[ prop ] = tween.start;
379 tween.end = tween.start;
380 tween.start = prop === "width" || prop === "height" ? 1 : 0;
387 jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
388 var cssFn = jQuery.fn[ name ];
389 jQuery.fn[ name ] = function( speed, easing, callback ) {
390 return speed == null || typeof speed === "boolean" ?
391 cssFn.apply( this, arguments ) :
392 this.animate( genFx( name, true ), speed, easing, callback );
397 fadeTo: function( speed, to, easing, callback ) {
399 // show any hidden elements after setting opacity to 0
400 return this.filter( isHidden ).css( "opacity", 0 ).show()
402 // animate to the value specified
403 .end().animate({ opacity: to }, speed, easing, callback );
405 animate: function( prop, speed, easing, callback ) {
406 var empty = jQuery.isEmptyObject( prop ),
407 optall = jQuery.speed( speed, easing, callback ),
408 doAnimation = function() {
409 // Operate on a copy of prop so per-property easing won't be lost
410 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
412 // Empty animations, or finishing resolves immediately
413 if ( empty || jQuery._data( this, "finish" ) ) {
417 doAnimation.finish = doAnimation;
419 return empty || optall.queue === false ?
420 this.each( doAnimation ) :
421 this.queue( optall.queue, doAnimation );
423 stop: function( type, clearQueue, gotoEnd ) {
424 var stopQueue = function( hooks ) {
425 var stop = hooks.stop;
430 if ( typeof type !== "string" ) {
431 gotoEnd = clearQueue;
435 if ( clearQueue && type !== false ) {
436 this.queue( type || "fx", [] );
439 return this.each(function() {
441 index = type != null && type + "queueHooks",
442 timers = jQuery.timers,
443 data = jQuery._data( this );
446 if ( data[ index ] && data[ index ].stop ) {
447 stopQueue( data[ index ] );
450 for ( index in data ) {
451 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
452 stopQueue( data[ index ] );
457 for ( index = timers.length; index--; ) {
458 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
459 timers[ index ].anim.stop( gotoEnd );
461 timers.splice( index, 1 );
465 // start the next in the queue if the last step wasn't forced
466 // timers currently will call their complete callbacks, which will dequeue
467 // but only if they were gotoEnd
468 if ( dequeue || !gotoEnd ) {
469 jQuery.dequeue( this, type );
473 finish: function( type ) {
474 if ( type !== false ) {
477 return this.each(function() {
479 data = jQuery._data( this ),
480 queue = data[ type + "queue" ],
481 hooks = data[ type + "queueHooks" ],
482 timers = jQuery.timers,
483 length = queue ? queue.length : 0;
485 // enable finishing flag on private data
488 // empty the queue first
489 jQuery.queue( this, type, [] );
491 if ( hooks && hooks.stop ) {
492 hooks.stop.call( this, true );
495 // look for any active animations, and finish them
496 for ( index = timers.length; index--; ) {
497 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
498 timers[ index ].anim.stop( true );
499 timers.splice( index, 1 );
503 // look for any animations in the old queue and finish them
504 for ( index = 0; index < length; index++ ) {
505 if ( queue[ index ] && queue[ index ].finish ) {
506 queue[ index ].finish.call( this );
510 // turn off finishing flag
516 // Generate parameters to create a standard animation
517 function genFx( type, includeWidth ) {
519 attrs = { height: type },
522 // if we include width, step value is 1 to do all cssExpand values,
523 // if we don't include width, step value is 2 to skip over Left and Right
524 includeWidth = includeWidth? 1 : 0;
525 for( ; i < 4 ; i += 2 - includeWidth ) {
526 which = cssExpand[ i ];
527 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
530 if ( includeWidth ) {
531 attrs.opacity = attrs.width = type;
537 // Generate shortcuts for custom animations
539 slideDown: genFx("show"),
540 slideUp: genFx("hide"),
541 slideToggle: genFx("toggle"),
542 fadeIn: { opacity: "show" },
543 fadeOut: { opacity: "hide" },
544 fadeToggle: { opacity: "toggle" }
545 }, function( name, props ) {
546 jQuery.fn[ name ] = function( speed, easing, callback ) {
547 return this.animate( props, speed, easing, callback );
551 jQuery.speed = function( speed, easing, fn ) {
552 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
553 complete: fn || !fn && easing ||
554 jQuery.isFunction( speed ) && speed,
556 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
559 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
560 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
562 // normalize opt.queue - true/undefined/null -> "fx"
563 if ( opt.queue == null || opt.queue === true ) {
568 opt.old = opt.complete;
570 opt.complete = function() {
571 if ( jQuery.isFunction( opt.old ) ) {
572 opt.old.call( this );
576 jQuery.dequeue( this, opt.queue );
584 jQuery.fx.tick = function() {
586 timers = jQuery.timers,
589 fxNow = jQuery.now();
591 for ( ; i < timers.length; i++ ) {
593 // Checks the timer has not already been removed
594 if ( !timer() && timers[ i ] === timer ) {
595 timers.splice( i--, 1 );
599 if ( !timers.length ) {
605 jQuery.fx.timer = function( timer ) {
606 if ( timer() && jQuery.timers.push( timer ) ) {
611 jQuery.fx.interval = 13;
613 jQuery.fx.start = function() {
615 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
619 jQuery.fx.stop = function() {
620 clearInterval( timerId );