Build: update node dependencies barring jscs
[jquery.git] / src / effects.js
blob225b31240d8f07a7a870da9201eb3b62a1ccde72
1 define([
2         "./core",
3         "./var/pnum",
4         "./css/var/cssExpand",
5         "./css/var/isHidden",
6         "./css/defaultDisplay",
7         "./effects/support",
9         "./core/init",
10         "./effects/Tween",
11         "./queue",
12         "./css",
13         "./deferred",
14         "./traversing"
15 ], function( jQuery, pnum, cssExpand, isHidden, defaultDisplay, support ) {
17 var
18         fxNow, timerId,
19         rfxtypes = /^(?:toggle|show|hide)$/,
20         rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
21         rrun = /queueHooks$/,
22         animationPrefilters = [ defaultPrefilter ],
23         tweeners = {
24                 "*": [ function( prop, value ) {
25                         var tween = this.createTween( prop, value ),
26                                 target = tween.cur(),
27                                 parts = rfxnum.exec( value ),
28                                 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
30                                 // Starting value computation is required for potential unit mismatches
31                                 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
32                                         rfxnum.exec( jQuery.css( tween.elem, prop ) ),
33                                 scale = 1,
34                                 maxIterations = 20;
36                         if ( start && start[ 3 ] !== unit ) {
37                                 // Trust units reported by jQuery.css
38                                 unit = unit || start[ 3 ];
40                                 // Make sure we update the tween properties later on
41                                 parts = parts || [];
43                                 // Iteratively approximate from a nonzero starting point
44                                 start = +target || 1;
46                                 do {
47                                         // If previous iteration zeroed out, double until we get *something*
48                                         // Use a string for doubling factor so we don't accidentally see scale as unchanged below
49                                         scale = scale || ".5";
51                                         // Adjust and apply
52                                         start = start / scale;
53                                         jQuery.style( tween.elem, prop, start + unit );
55                                 // Update scale, tolerating zero or NaN from tween.cur()
56                                 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
57                                 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
58                         }
60                         // Update tween properties
61                         if ( parts ) {
62                                 start = tween.start = +start || +target || 0;
63                                 tween.unit = unit;
64                                 // If a +=/-= token was provided, we're doing a relative animation
65                                 tween.end = parts[ 1 ] ?
66                                         start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
67                                         +parts[ 2 ];
68                         }
70                         return tween;
71                 } ]
72         };
74 function raf() {
75         if ( timerId ) {
76                 window.requestAnimationFrame( raf );
77                 jQuery.fx.tick();
78         }
81 // Animations created synchronously will run synchronously
82 function createFxNow() {
83         setTimeout(function() {
84                 fxNow = undefined;
85         });
86         return ( fxNow = jQuery.now() );
89 // Generate parameters to create a standard animation
90 function genFx( type, includeWidth ) {
91         var which,
92                 attrs = { height: type },
93                 i = 0;
95         // if we include width, step value is 1 to do all cssExpand values,
96         // if we don't include width, step value is 2 to skip over Left and Right
97         includeWidth = includeWidth ? 1 : 0;
98         for ( ; i < 4 ; i += 2 - includeWidth ) {
99                 which = cssExpand[ i ];
100                 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
101         }
103         if ( includeWidth ) {
104                 attrs.opacity = attrs.width = type;
105         }
107         return attrs;
110 function createTween( value, prop, animation ) {
111         var tween,
112                 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
113                 index = 0,
114                 length = collection.length;
115         for ( ; index < length; index++ ) {
116                 if ( (tween = collection[ index ].call( animation, prop, value )) ) {
118                         // we're done with this property
119                         return tween;
120                 }
121         }
124 function defaultPrefilter( elem, props, opts ) {
125         /* jshint validthis: true */
126         var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
127                 anim = this,
128                 orig = {},
129                 style = elem.style,
130                 hidden = elem.nodeType && isHidden( elem ),
131                 dataShow = jQuery._data( elem, "fxshow" );
133         // handle queue: false promises
134         if ( !opts.queue ) {
135                 hooks = jQuery._queueHooks( elem, "fx" );
136                 if ( hooks.unqueued == null ) {
137                         hooks.unqueued = 0;
138                         oldfire = hooks.empty.fire;
139                         hooks.empty.fire = function() {
140                                 if ( !hooks.unqueued ) {
141                                         oldfire();
142                                 }
143                         };
144                 }
145                 hooks.unqueued++;
147                 anim.always(function() {
148                         // doing this makes sure that the complete handler will be called
149                         // before this completes
150                         anim.always(function() {
151                                 hooks.unqueued--;
152                                 if ( !jQuery.queue( elem, "fx" ).length ) {
153                                         hooks.empty.fire();
154                                 }
155                         });
156                 });
157         }
159         // height/width overflow pass
160         if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
161                 // Make sure that nothing sneaks out
162                 // Record all 3 overflow attributes because IE does not
163                 // change the overflow attribute when overflowX and
164                 // overflowY are set to the same value
165                 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
167                 // Set display property to inline-block for height/width
168                 // animations on inline elements that are having width/height animated
169                 display = jQuery.css( elem, "display" );
171                 // Test default display if display is currently "none"
172                 checkDisplay = display === "none" ?
173                         jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
175                 if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
177                         // inline-level elements accept inline-block;
178                         // block-level elements need to be inline with layout
179                         if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
180                                 style.display = "inline-block";
181                         } else {
182                                 style.zoom = 1;
183                         }
184                 }
185         }
187         if ( opts.overflow ) {
188                 style.overflow = "hidden";
189                 if ( !support.shrinkWrapBlocks() ) {
190                         anim.always(function() {
191                                 style.overflow = opts.overflow[ 0 ];
192                                 style.overflowX = opts.overflow[ 1 ];
193                                 style.overflowY = opts.overflow[ 2 ];
194                         });
195                 }
196         }
198         // show/hide pass
199         for ( prop in props ) {
200                 value = props[ prop ];
201                 if ( rfxtypes.exec( value ) ) {
202                         delete props[ prop ];
203                         toggle = toggle || value === "toggle";
204                         if ( value === ( hidden ? "hide" : "show" ) ) {
206                                 // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
207                                 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
208                                         hidden = true;
209                                 } else {
210                                         continue;
211                                 }
212                         }
213                         orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
215                 // Any non-fx value stops us from restoring the original display value
216                 } else {
217                         display = undefined;
218                 }
219         }
221         if ( !jQuery.isEmptyObject( orig ) ) {
222                 if ( dataShow ) {
223                         if ( "hidden" in dataShow ) {
224                                 hidden = dataShow.hidden;
225                         }
226                 } else {
227                         dataShow = jQuery._data( elem, "fxshow", {} );
228                 }
230                 // store state if its toggle - enables .stop().toggle() to "reverse"
231                 if ( toggle ) {
232                         dataShow.hidden = !hidden;
233                 }
234                 if ( hidden ) {
235                         jQuery( elem ).show();
236                 } else {
237                         anim.done(function() {
238                                 jQuery( elem ).hide();
239                         });
240                 }
241                 anim.done(function() {
242                         var prop;
243                         jQuery._removeData( elem, "fxshow" );
244                         for ( prop in orig ) {
245                                 jQuery.style( elem, prop, orig[ prop ] );
246                         }
247                 });
248                 for ( prop in orig ) {
249                         tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
251                         if ( !( prop in dataShow ) ) {
252                                 dataShow[ prop ] = tween.start;
253                                 if ( hidden ) {
254                                         tween.end = tween.start;
255                                         tween.start = prop === "width" || prop === "height" ? 1 : 0;
256                                 }
257                         }
258                 }
260         // If this is a noop like .hide().hide(), restore an overwritten display value
261         } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
262                 style.display = display;
263         }
266 function propFilter( props, specialEasing ) {
267         var index, name, easing, value, hooks;
269         // camelCase, specialEasing and expand cssHook pass
270         for ( index in props ) {
271                 name = jQuery.camelCase( index );
272                 easing = specialEasing[ name ];
273                 value = props[ index ];
274                 if ( jQuery.isArray( value ) ) {
275                         easing = value[ 1 ];
276                         value = props[ index ] = value[ 0 ];
277                 }
279                 if ( index !== name ) {
280                         props[ name ] = value;
281                         delete props[ index ];
282                 }
284                 hooks = jQuery.cssHooks[ name ];
285                 if ( hooks && "expand" in hooks ) {
286                         value = hooks.expand( value );
287                         delete props[ name ];
289                         // not quite $.extend, this wont overwrite keys already present.
290                         // also - reusing 'index' from above because we have the correct "name"
291                         for ( index in value ) {
292                                 if ( !( index in props ) ) {
293                                         props[ index ] = value[ index ];
294                                         specialEasing[ index ] = easing;
295                                 }
296                         }
297                 } else {
298                         specialEasing[ name ] = easing;
299                 }
300         }
303 function Animation( elem, properties, options ) {
304         var result,
305                 stopped,
306                 index = 0,
307                 length = animationPrefilters.length,
308                 deferred = jQuery.Deferred().always( function() {
309                         // don't match elem in the :animated selector
310                         delete tick.elem;
311                 }),
312                 tick = function() {
313                         if ( stopped ) {
314                                 return false;
315                         }
316                         var currentTime = fxNow || createFxNow(),
317                                 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
318                                 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
319                                 temp = remaining / animation.duration || 0,
320                                 percent = 1 - temp,
321                                 index = 0,
322                                 length = animation.tweens.length;
324                         for ( ; index < length ; index++ ) {
325                                 animation.tweens[ index ].run( percent );
326                         }
328                         deferred.notifyWith( elem, [ animation, percent, remaining ]);
330                         if ( percent < 1 && length ) {
331                                 return remaining;
332                         } else {
333                                 deferred.resolveWith( elem, [ animation ] );
334                                 return false;
335                         }
336                 },
337                 animation = deferred.promise({
338                         elem: elem,
339                         props: jQuery.extend( {}, properties ),
340                         opts: jQuery.extend( true, { specialEasing: {} }, options ),
341                         originalProperties: properties,
342                         originalOptions: options,
343                         startTime: fxNow || createFxNow(),
344                         duration: options.duration,
345                         tweens: [],
346                         createTween: function( prop, end ) {
347                                 var tween = jQuery.Tween( elem, animation.opts, prop, end,
348                                                 animation.opts.specialEasing[ prop ] || animation.opts.easing );
349                                 animation.tweens.push( tween );
350                                 return tween;
351                         },
352                         stop: function( gotoEnd ) {
353                                 var index = 0,
354                                         // if we are going to the end, we want to run all the tweens
355                                         // otherwise we skip this part
356                                         length = gotoEnd ? animation.tweens.length : 0;
357                                 if ( stopped ) {
358                                         return this;
359                                 }
360                                 stopped = true;
361                                 for ( ; index < length ; index++ ) {
362                                         animation.tweens[ index ].run( 1 );
363                                 }
365                                 // resolve when we played the last frame
366                                 // otherwise, reject
367                                 if ( gotoEnd ) {
368                                         deferred.resolveWith( elem, [ animation, gotoEnd ] );
369                                 } else {
370                                         deferred.rejectWith( elem, [ animation, gotoEnd ] );
371                                 }
372                                 return this;
373                         }
374                 }),
375                 props = animation.props;
377         propFilter( props, animation.opts.specialEasing );
379         for ( ; index < length ; index++ ) {
380                 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
381                 if ( result ) {
382                         return result;
383                 }
384         }
386         jQuery.map( props, createTween, animation );
388         if ( jQuery.isFunction( animation.opts.start ) ) {
389                 animation.opts.start.call( elem, animation );
390         }
392         jQuery.fx.timer(
393                 jQuery.extend( tick, {
394                         elem: elem,
395                         anim: animation,
396                         queue: animation.opts.queue
397                 })
398         );
400         // attach callbacks from options
401         return animation.progress( animation.opts.progress )
402                 .done( animation.opts.done, animation.opts.complete )
403                 .fail( animation.opts.fail )
404                 .always( animation.opts.always );
407 jQuery.Animation = jQuery.extend( Animation, {
408         tweener: function( props, callback ) {
409                 if ( jQuery.isFunction( props ) ) {
410                         callback = props;
411                         props = [ "*" ];
412                 } else {
413                         props = props.split(" ");
414                 }
416                 var prop,
417                         index = 0,
418                         length = props.length;
420                 for ( ; index < length ; index++ ) {
421                         prop = props[ index ];
422                         tweeners[ prop ] = tweeners[ prop ] || [];
423                         tweeners[ prop ].unshift( callback );
424                 }
425         },
427         prefilter: function( callback, prepend ) {
428                 if ( prepend ) {
429                         animationPrefilters.unshift( callback );
430                 } else {
431                         animationPrefilters.push( callback );
432                 }
433         }
436 jQuery.speed = function( speed, easing, fn ) {
437         var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
438                 complete: fn || !fn && easing ||
439                         jQuery.isFunction( speed ) && speed,
440                 duration: speed,
441                 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
442         };
444                 // Go to the end state if fx are off or if document is hidden
445         if ( jQuery.fx.off || document.hidden ) {
446                 opt.duration = 0;
448         } else {
449                 opt.duration = typeof opt.duration === "number" ?
450                         opt.duration : opt.duration in jQuery.fx.speeds ?
451                                 jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
452         }
454         // normalize opt.queue - true/undefined/null -> "fx"
455         if ( opt.queue == null || opt.queue === true ) {
456                 opt.queue = "fx";
457         }
459         // Queueing
460         opt.old = opt.complete;
462         opt.complete = function() {
463                 if ( jQuery.isFunction( opt.old ) ) {
464                         opt.old.call( this );
465                 }
467                 if ( opt.queue ) {
468                         jQuery.dequeue( this, opt.queue );
469                 }
470         };
472         return opt;
475 jQuery.fn.extend({
476         fadeTo: function( speed, to, easing, callback ) {
477                 // show any hidden elements after setting opacity to 0
478                 return this.filter( isHidden ).css( "opacity", 0 ).show()
480                         // animate to the value specified
481                         .end().animate({ opacity: to }, speed, easing, callback );
482         },
483         animate: function( prop, speed, easing, callback ) {
484                 var empty = jQuery.isEmptyObject( prop ),
485                         optall = jQuery.speed( speed, easing, callback ),
486                         doAnimation = function() {
487                                 // Operate on a copy of prop so per-property easing won't be lost
488                                 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
490                                 // Empty animations, or finishing resolves immediately
491                                 if ( empty || jQuery._data( this, "finish" ) ) {
492                                         anim.stop( true );
493                                 }
494                         };
495                         doAnimation.finish = doAnimation;
497                 return empty || optall.queue === false ?
498                         this.each( doAnimation ) :
499                         this.queue( optall.queue, doAnimation );
500         },
501         stop: function( type, clearQueue, gotoEnd ) {
502                 var stopQueue = function( hooks ) {
503                         var stop = hooks.stop;
504                         delete hooks.stop;
505                         stop( gotoEnd );
506                 };
508                 if ( typeof type !== "string" ) {
509                         gotoEnd = clearQueue;
510                         clearQueue = type;
511                         type = undefined;
512                 }
513                 if ( clearQueue && type !== false ) {
514                         this.queue( type || "fx", [] );
515                 }
517                 return this.each(function() {
518                         var dequeue = true,
519                                 index = type != null && type + "queueHooks",
520                                 timers = jQuery.timers,
521                                 data = jQuery._data( this );
523                         if ( index ) {
524                                 if ( data[ index ] && data[ index ].stop ) {
525                                         stopQueue( data[ index ] );
526                                 }
527                         } else {
528                                 for ( index in data ) {
529                                         if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
530                                                 stopQueue( data[ index ] );
531                                         }
532                                 }
533                         }
535                         for ( index = timers.length; index--; ) {
536                                 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
537                                         timers[ index ].anim.stop( gotoEnd );
538                                         dequeue = false;
539                                         timers.splice( index, 1 );
540                                 }
541                         }
543                         // start the next in the queue if the last step wasn't forced
544                         // timers currently will call their complete callbacks, which will dequeue
545                         // but only if they were gotoEnd
546                         if ( dequeue || !gotoEnd ) {
547                                 jQuery.dequeue( this, type );
548                         }
549                 });
550         },
551         finish: function( type ) {
552                 if ( type !== false ) {
553                         type = type || "fx";
554                 }
555                 return this.each(function() {
556                         var index,
557                                 data = jQuery._data( this ),
558                                 queue = data[ type + "queue" ],
559                                 hooks = data[ type + "queueHooks" ],
560                                 timers = jQuery.timers,
561                                 length = queue ? queue.length : 0;
563                         // enable finishing flag on private data
564                         data.finish = true;
566                         // empty the queue first
567                         jQuery.queue( this, type, [] );
569                         if ( hooks && hooks.stop ) {
570                                 hooks.stop.call( this, true );
571                         }
573                         // look for any active animations, and finish them
574                         for ( index = timers.length; index--; ) {
575                                 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
576                                         timers[ index ].anim.stop( true );
577                                         timers.splice( index, 1 );
578                                 }
579                         }
581                         // look for any animations in the old queue and finish them
582                         for ( index = 0; index < length; index++ ) {
583                                 if ( queue[ index ] && queue[ index ].finish ) {
584                                         queue[ index ].finish.call( this );
585                                 }
586                         }
588                         // turn off finishing flag
589                         delete data.finish;
590                 });
591         }
594 jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
595         var cssFn = jQuery.fn[ name ];
596         jQuery.fn[ name ] = function( speed, easing, callback ) {
597                 return speed == null || typeof speed === "boolean" ?
598                         cssFn.apply( this, arguments ) :
599                         this.animate( genFx( name, true ), speed, easing, callback );
600         };
603 // Generate shortcuts for custom animations
604 jQuery.each({
605         slideDown: genFx("show"),
606         slideUp: genFx("hide"),
607         slideToggle: genFx("toggle"),
608         fadeIn: { opacity: "show" },
609         fadeOut: { opacity: "hide" },
610         fadeToggle: { opacity: "toggle" }
611 }, function( name, props ) {
612         jQuery.fn[ name ] = function( speed, easing, callback ) {
613                 return this.animate( props, speed, easing, callback );
614         };
617 jQuery.timers = [];
618 jQuery.fx.tick = function() {
619         var timer,
620                 timers = jQuery.timers,
621                 i = 0;
623         fxNow = jQuery.now();
625         for ( ; i < timers.length; i++ ) {
626                 timer = timers[ i ];
627                 // Checks the timer has not already been removed
628                 if ( !timer() && timers[ i ] === timer ) {
629                         timers.splice( i--, 1 );
630                 }
631         }
633         if ( !timers.length ) {
634                 jQuery.fx.stop();
635         }
636         fxNow = undefined;
639 jQuery.fx.timer = function( timer ) {
640         jQuery.timers.push( timer );
641         if ( timer() ) {
642                 jQuery.fx.start();
643         } else {
644                 jQuery.timers.pop();
645         }
648 jQuery.fx.interval = 13;
650 jQuery.fx.start = function() {
651         timerId = window.requestAnimationFrame ?
652                 window.requestAnimationFrame( raf ) :
653                 setInterval( jQuery.fx.tick, jQuery.fx.interval );
656 jQuery.fx.stop = function() {
657         if ( window.cancelAnimationFrame ) {
658                 window.cancelAnimationFrame( timerId );
659         } else {
660                 clearInterval( timerId );
661         }
663         timerId = null;
666 jQuery.fx.speeds = {
667         slow: 600,
668         fast: 200,
669         // Default speed
670         _default: 400
673 return jQuery;