1 import { jQuery } from "./core.js";
2 import { document } from "./var/document.js";
3 import { rcssNum } from "./var/rcssNum.js";
4 import { rnothtmlwhite } from "./var/rnothtmlwhite.js";
5 import { cssExpand } from "./css/var/cssExpand.js";
6 import { isHiddenWithinTree } from "./css/var/isHiddenWithinTree.js";
7 import { adjustCSS } from "./css/adjustCSS.js";
8 import { cssCamelCase } from "./css/cssCamelCase.js";
9 import { dataPriv } from "./data/var/dataPriv.js";
10 import { showHide } from "./css/showHide.js";
12 import "./core/init.js";
14 import "./deferred.js";
15 import "./traversing.js";
16 import "./manipulation.js";
18 import "./effects/Tween.js";
22 rfxtypes = /^(?:toggle|show|hide)$/,
27 if ( document.hidden === false && window.requestAnimationFrame ) {
28 window.requestAnimationFrame( schedule );
30 window.setTimeout( schedule, 13 );
37 // Animations created synchronously will run synchronously
38 function createFxNow() {
39 window.setTimeout( function() {
42 return ( fxNow = Date.now() );
45 // Generate parameters to create a standard animation
46 function genFx( type, includeWidth ) {
49 attrs = { height: type };
51 // If we include width, step value is 1 to do all cssExpand values,
52 // otherwise step value is 2 to skip over Left and Right
53 includeWidth = includeWidth ? 1 : 0;
54 for ( ; i < 4; i += 2 - includeWidth ) {
55 which = cssExpand[ i ];
56 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
60 attrs.opacity = attrs.width = type;
66 function createTween( value, prop, animation ) {
68 collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
70 length = collection.length;
71 for ( ; index < length; index++ ) {
72 if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
74 // We're done with this property
80 function defaultPrefilter( elem, props, opts ) {
81 var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
82 isBox = "width" in props || "height" in props,
86 hidden = elem.nodeType && isHiddenWithinTree( elem ),
87 dataShow = dataPriv.get( elem, "fxshow" );
89 // Queue-skipping animations hijack the fx hooks
91 hooks = jQuery._queueHooks( elem, "fx" );
92 if ( hooks.unqueued == null ) {
94 oldfire = hooks.empty.fire;
95 hooks.empty.fire = function() {
96 if ( !hooks.unqueued ) {
103 anim.always( function() {
105 // Ensure the complete handler is called before this completes
106 anim.always( function() {
108 if ( !jQuery.queue( elem, "fx" ).length ) {
115 // Detect show/hide animations
116 for ( prop in props ) {
117 value = props[ prop ];
118 if ( rfxtypes.test( value ) ) {
119 delete props[ prop ];
120 toggle = toggle || value === "toggle";
121 if ( value === ( hidden ? "hide" : "show" ) ) {
123 // Pretend to be hidden if this is a "show" and
124 // there is still data from a stopped show/hide
125 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
128 // Ignore all other no-op show/hide data
133 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
137 // Bail out if this is a no-op like .hide().hide()
138 propTween = !jQuery.isEmptyObject( props );
139 if ( !propTween && jQuery.isEmptyObject( orig ) ) {
143 // Restrict "overflow" and "display" styles during box animations
144 if ( isBox && elem.nodeType === 1 ) {
146 // Support: IE <=9 - 11+
147 // Record all 3 overflow attributes because IE does not infer the shorthand
148 // from identically-valued overflowX and overflowY.
149 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
151 // Identify a display type, preferring old show/hide data over the CSS cascade
152 restoreDisplay = dataShow && dataShow.display;
153 if ( restoreDisplay == null ) {
154 restoreDisplay = dataPriv.get( elem, "display" );
156 display = jQuery.css( elem, "display" );
157 if ( display === "none" ) {
158 if ( restoreDisplay ) {
159 display = restoreDisplay;
162 // Get nonempty value(s) by temporarily forcing visibility
163 showHide( [ elem ], true );
164 restoreDisplay = elem.style.display || restoreDisplay;
165 display = jQuery.css( elem, "display" );
166 showHide( [ elem ] );
170 // Animate inline elements as inline-block
171 if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
172 if ( jQuery.css( elem, "float" ) === "none" ) {
174 // Restore the original display value at the end of pure show/hide animations
176 anim.done( function() {
177 style.display = restoreDisplay;
179 if ( restoreDisplay == null ) {
180 display = style.display;
181 restoreDisplay = display === "none" ? "" : display;
184 style.display = "inline-block";
189 if ( opts.overflow ) {
190 style.overflow = "hidden";
191 anim.always( function() {
192 style.overflow = opts.overflow[ 0 ];
193 style.overflowX = opts.overflow[ 1 ];
194 style.overflowY = opts.overflow[ 2 ];
198 // Implement show/hide animations
200 for ( prop in orig ) {
202 // General show/hide setup for this element animation
205 if ( "hidden" in dataShow ) {
206 hidden = dataShow.hidden;
209 dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
212 // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
214 dataShow.hidden = !hidden;
217 // Show elements before animating them
219 showHide( [ elem ], true );
222 // eslint-disable-next-line no-loop-func
223 anim.done( function() {
225 // The final step of a "hide" animation is actually hiding the element
227 showHide( [ elem ] );
229 dataPriv.remove( elem, "fxshow" );
230 for ( prop in orig ) {
231 jQuery.style( elem, prop, orig[ prop ] );
236 // Per-property setup
237 propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
238 if ( !( prop in dataShow ) ) {
239 dataShow[ prop ] = propTween.start;
241 propTween.end = propTween.start;
248 function propFilter( props, specialEasing ) {
249 var index, name, easing, value, hooks;
251 // camelCase, specialEasing and expand cssHook pass
252 for ( index in props ) {
253 name = cssCamelCase( index );
254 easing = specialEasing[ name ];
255 value = props[ index ];
256 if ( Array.isArray( value ) ) {
258 value = props[ index ] = value[ 0 ];
261 if ( index !== name ) {
262 props[ name ] = value;
263 delete props[ index ];
266 hooks = jQuery.cssHooks[ name ];
267 if ( hooks && "expand" in hooks ) {
268 value = hooks.expand( value );
269 delete props[ name ];
271 // Not quite $.extend, this won't overwrite existing keys.
272 // Reusing 'index' because we have the correct "name"
273 for ( index in value ) {
274 if ( !( index in props ) ) {
275 props[ index ] = value[ index ];
276 specialEasing[ index ] = easing;
280 specialEasing[ name ] = easing;
285 function Animation( elem, properties, options ) {
289 length = Animation.prefilters.length,
290 deferred = jQuery.Deferred().always( function() {
292 // Don't match elem in the :animated selector
299 var currentTime = fxNow || createFxNow(),
300 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
302 percent = 1 - ( remaining / animation.duration || 0 ),
304 length = animation.tweens.length;
306 for ( ; index < length; index++ ) {
307 animation.tweens[ index ].run( percent );
310 deferred.notifyWith( elem, [ animation, percent, remaining ] );
312 // If there's more to do, yield
313 if ( percent < 1 && length ) {
317 // If this was an empty animation, synthesize a final progress notification
319 deferred.notifyWith( elem, [ animation, 1, 0 ] );
322 // Resolve the animation and report its conclusion
323 deferred.resolveWith( elem, [ animation ] );
326 animation = deferred.promise( {
328 props: jQuery.extend( {}, properties ),
329 opts: jQuery.extend( true, {
331 easing: jQuery.easing._default
333 originalProperties: properties,
334 originalOptions: options,
335 startTime: fxNow || createFxNow(),
336 duration: options.duration,
338 createTween: function( prop, end ) {
339 var tween = jQuery.Tween( elem, animation.opts, prop, end,
340 animation.opts.specialEasing[ prop ] || animation.opts.easing );
341 animation.tweens.push( tween );
344 stop: function( gotoEnd ) {
347 // If we are going to the end, we want to run all the tweens
348 // otherwise we skip this part
349 length = gotoEnd ? animation.tweens.length : 0;
354 for ( ; index < length; index++ ) {
355 animation.tweens[ index ].run( 1 );
358 // Resolve when we played the last frame; otherwise, reject
360 deferred.notifyWith( elem, [ animation, 1, 0 ] );
361 deferred.resolveWith( elem, [ animation, gotoEnd ] );
363 deferred.rejectWith( elem, [ animation, gotoEnd ] );
368 props = animation.props;
370 propFilter( props, animation.opts.specialEasing );
372 for ( ; index < length; index++ ) {
373 result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
375 if ( typeof result.stop === "function" ) {
376 jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
377 result.stop.bind( result );
383 jQuery.map( props, createTween, animation );
385 if ( typeof animation.opts.start === "function" ) {
386 animation.opts.start.call( elem, animation );
389 // Attach callbacks from options
391 .progress( animation.opts.progress )
392 .done( animation.opts.done, animation.opts.complete )
393 .fail( animation.opts.fail )
394 .always( animation.opts.always );
397 jQuery.extend( tick, {
400 queue: animation.opts.queue
407 jQuery.Animation = jQuery.extend( Animation, {
410 "*": [ function( prop, value ) {
411 var tween = this.createTween( prop, value );
412 adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
417 tweener: function( props, callback ) {
418 if ( typeof props === "function" ) {
422 props = props.match( rnothtmlwhite );
427 length = props.length;
429 for ( ; index < length; index++ ) {
430 prop = props[ index ];
431 Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
432 Animation.tweeners[ prop ].unshift( callback );
436 prefilters: [ defaultPrefilter ],
438 prefilter: function( callback, prepend ) {
440 Animation.prefilters.unshift( callback );
442 Animation.prefilters.push( callback );
447 jQuery.speed = function( speed, easing, fn ) {
448 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
449 complete: fn || easing ||
450 typeof speed === "function" && speed,
452 easing: fn && easing || easing && typeof easing !== "function" && easing
455 // Go to the end state if fx are off
456 if ( jQuery.fx.off ) {
460 if ( typeof opt.duration !== "number" ) {
461 if ( opt.duration in jQuery.fx.speeds ) {
462 opt.duration = jQuery.fx.speeds[ opt.duration ];
465 opt.duration = jQuery.fx.speeds._default;
470 // Normalize opt.queue - true/undefined/null -> "fx"
471 if ( opt.queue == null || opt.queue === true ) {
476 opt.old = opt.complete;
478 opt.complete = function() {
479 if ( typeof opt.old === "function" ) {
480 opt.old.call( this );
484 jQuery.dequeue( this, opt.queue );
492 fadeTo: function( speed, to, easing, callback ) {
494 // Show any hidden elements after setting opacity to 0
495 return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
497 // Animate to the value specified
498 .end().animate( { opacity: to }, speed, easing, callback );
500 animate: function( prop, speed, easing, callback ) {
501 var empty = jQuery.isEmptyObject( prop ),
502 optall = jQuery.speed( speed, easing, callback ),
503 doAnimation = function() {
505 // Operate on a copy of prop so per-property easing won't be lost
506 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
508 // Empty animations, or finishing resolves immediately
509 if ( empty || dataPriv.get( this, "finish" ) ) {
514 doAnimation.finish = doAnimation;
516 return empty || optall.queue === false ?
517 this.each( doAnimation ) :
518 this.queue( optall.queue, doAnimation );
520 stop: function( type, clearQueue, gotoEnd ) {
521 var stopQueue = function( hooks ) {
522 var stop = hooks.stop;
527 if ( typeof type !== "string" ) {
528 gotoEnd = clearQueue;
533 this.queue( type || "fx", [] );
536 return this.each( function() {
538 index = type != null && type + "queueHooks",
539 timers = jQuery.timers,
540 data = dataPriv.get( this );
543 if ( data[ index ] && data[ index ].stop ) {
544 stopQueue( data[ index ] );
547 for ( index in data ) {
548 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
549 stopQueue( data[ index ] );
554 for ( index = timers.length; index--; ) {
555 if ( timers[ index ].elem === this &&
556 ( type == null || timers[ index ].queue === type ) ) {
558 timers[ index ].anim.stop( gotoEnd );
560 timers.splice( index, 1 );
564 // Start the next in the queue if the last step wasn't forced.
565 // Timers currently will call their complete callbacks, which
566 // will dequeue but only if they were gotoEnd.
567 if ( dequeue || !gotoEnd ) {
568 jQuery.dequeue( this, type );
572 finish: function( type ) {
573 if ( type !== false ) {
576 return this.each( function() {
578 data = dataPriv.get( this ),
579 queue = data[ type + "queue" ],
580 hooks = data[ type + "queueHooks" ],
581 timers = jQuery.timers,
582 length = queue ? queue.length : 0;
584 // Enable finishing flag on private data
587 // Empty the queue first
588 jQuery.queue( this, type, [] );
590 if ( hooks && hooks.stop ) {
591 hooks.stop.call( this, true );
594 // Look for any active animations, and finish them
595 for ( index = timers.length; index--; ) {
596 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
597 timers[ index ].anim.stop( true );
598 timers.splice( index, 1 );
602 // Look for any animations in the old queue and finish them
603 for ( index = 0; index < length; index++ ) {
604 if ( queue[ index ] && queue[ index ].finish ) {
605 queue[ index ].finish.call( this );
609 // Turn off finishing flag
615 jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) {
616 var cssFn = jQuery.fn[ name ];
617 jQuery.fn[ name ] = function( speed, easing, callback ) {
618 return speed == null || typeof speed === "boolean" ?
619 cssFn.apply( this, arguments ) :
620 this.animate( genFx( name, true ), speed, easing, callback );
624 // Generate shortcuts for custom animations
626 slideDown: genFx( "show" ),
627 slideUp: genFx( "hide" ),
628 slideToggle: genFx( "toggle" ),
629 fadeIn: { opacity: "show" },
630 fadeOut: { opacity: "hide" },
631 fadeToggle: { opacity: "toggle" }
632 }, function( name, props ) {
633 jQuery.fn[ name ] = function( speed, easing, callback ) {
634 return this.animate( props, speed, easing, callback );
639 jQuery.fx.tick = function() {
642 timers = jQuery.timers;
646 for ( ; i < timers.length; i++ ) {
649 // Run the timer and safely remove it when done (allowing for external removal)
650 if ( !timer() && timers[ i ] === timer ) {
651 timers.splice( i--, 1 );
655 if ( !timers.length ) {
661 jQuery.fx.timer = function( timer ) {
662 jQuery.timers.push( timer );
666 jQuery.fx.start = function() {
675 jQuery.fx.stop = function() {
687 export { jQuery, jQuery as $ };