effects.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. define( [
  2. "./core",
  3. "./var/document",
  4. "./var/rcssNum",
  5. "./var/rnothtmlwhite",
  6. "./css/var/cssExpand",
  7. "./css/var/isHiddenWithinTree",
  8. "./css/var/swap",
  9. "./css/adjustCSS",
  10. "./data/var/dataPriv",
  11. "./css/showHide",
  12. "./core/init",
  13. "./queue",
  14. "./deferred",
  15. "./traversing",
  16. "./manipulation",
  17. "./css",
  18. "./effects/Tween"
  19. ], function( jQuery, document, rcssNum, rnothtmlwhite, cssExpand, isHiddenWithinTree, swap,
  20. adjustCSS, dataPriv, showHide ) {
  21. "use strict";
  22. var
  23. fxNow, inProgress,
  24. rfxtypes = /^(?:toggle|show|hide)$/,
  25. rrun = /queueHooks$/;
  26. function schedule() {
  27. if ( inProgress ) {
  28. if ( document.hidden === false && window.requestAnimationFrame ) {
  29. window.requestAnimationFrame( schedule );
  30. } else {
  31. window.setTimeout( schedule, jQuery.fx.interval );
  32. }
  33. jQuery.fx.tick();
  34. }
  35. }
  36. // Animations created synchronously will run synchronously
  37. function createFxNow() {
  38. window.setTimeout( function() {
  39. fxNow = undefined;
  40. } );
  41. return ( fxNow = jQuery.now() );
  42. }
  43. // Generate parameters to create a standard animation
  44. function genFx( type, includeWidth ) {
  45. var which,
  46. i = 0,
  47. attrs = { height: type };
  48. // If we include width, step value is 1 to do all cssExpand values,
  49. // otherwise step value is 2 to skip over Left and Right
  50. includeWidth = includeWidth ? 1 : 0;
  51. for ( ; i < 4; i += 2 - includeWidth ) {
  52. which = cssExpand[ i ];
  53. attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
  54. }
  55. if ( includeWidth ) {
  56. attrs.opacity = attrs.width = type;
  57. }
  58. return attrs;
  59. }
  60. function createTween( value, prop, animation ) {
  61. var tween,
  62. collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
  63. index = 0,
  64. length = collection.length;
  65. for ( ; index < length; index++ ) {
  66. if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
  67. // We're done with this property
  68. return tween;
  69. }
  70. }
  71. }
  72. function defaultPrefilter( elem, props, opts ) {
  73. var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
  74. isBox = "width" in props || "height" in props,
  75. anim = this,
  76. orig = {},
  77. style = elem.style,
  78. hidden = elem.nodeType && isHiddenWithinTree( elem ),
  79. dataShow = dataPriv.get( elem, "fxshow" );
  80. // Queue-skipping animations hijack the fx hooks
  81. if ( !opts.queue ) {
  82. hooks = jQuery._queueHooks( elem, "fx" );
  83. if ( hooks.unqueued == null ) {
  84. hooks.unqueued = 0;
  85. oldfire = hooks.empty.fire;
  86. hooks.empty.fire = function() {
  87. if ( !hooks.unqueued ) {
  88. oldfire();
  89. }
  90. };
  91. }
  92. hooks.unqueued++;
  93. anim.always( function() {
  94. // Ensure the complete handler is called before this completes
  95. anim.always( function() {
  96. hooks.unqueued--;
  97. if ( !jQuery.queue( elem, "fx" ).length ) {
  98. hooks.empty.fire();
  99. }
  100. } );
  101. } );
  102. }
  103. // Detect show/hide animations
  104. for ( prop in props ) {
  105. value = props[ prop ];
  106. if ( rfxtypes.test( value ) ) {
  107. delete props[ prop ];
  108. toggle = toggle || value === "toggle";
  109. if ( value === ( hidden ? "hide" : "show" ) ) {
  110. // Pretend to be hidden if this is a "show" and
  111. // there is still data from a stopped show/hide
  112. if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
  113. hidden = true;
  114. // Ignore all other no-op show/hide data
  115. } else {
  116. continue;
  117. }
  118. }
  119. orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
  120. }
  121. }
  122. // Bail out if this is a no-op like .hide().hide()
  123. propTween = !jQuery.isEmptyObject( props );
  124. if ( !propTween && jQuery.isEmptyObject( orig ) ) {
  125. return;
  126. }
  127. // Restrict "overflow" and "display" styles during box animations
  128. if ( isBox && elem.nodeType === 1 ) {
  129. // Support: IE <=9 - 11, Edge 12 - 13
  130. // Record all 3 overflow attributes because IE does not infer the shorthand
  131. // from identically-valued overflowX and overflowY
  132. opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
  133. // Identify a display type, preferring old show/hide data over the CSS cascade
  134. restoreDisplay = dataShow && dataShow.display;
  135. if ( restoreDisplay == null ) {
  136. restoreDisplay = dataPriv.get( elem, "display" );
  137. }
  138. display = jQuery.css( elem, "display" );
  139. if ( display === "none" ) {
  140. if ( restoreDisplay ) {
  141. display = restoreDisplay;
  142. } else {
  143. // Get nonempty value(s) by temporarily forcing visibility
  144. showHide( [ elem ], true );
  145. restoreDisplay = elem.style.display || restoreDisplay;
  146. display = jQuery.css( elem, "display" );
  147. showHide( [ elem ] );
  148. }
  149. }
  150. // Animate inline elements as inline-block
  151. if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
  152. if ( jQuery.css( elem, "float" ) === "none" ) {
  153. // Restore the original display value at the end of pure show/hide animations
  154. if ( !propTween ) {
  155. anim.done( function() {
  156. style.display = restoreDisplay;
  157. } );
  158. if ( restoreDisplay == null ) {
  159. display = style.display;
  160. restoreDisplay = display === "none" ? "" : display;
  161. }
  162. }
  163. style.display = "inline-block";
  164. }
  165. }
  166. }
  167. if ( opts.overflow ) {
  168. style.overflow = "hidden";
  169. anim.always( function() {
  170. style.overflow = opts.overflow[ 0 ];
  171. style.overflowX = opts.overflow[ 1 ];
  172. style.overflowY = opts.overflow[ 2 ];
  173. } );
  174. }
  175. // Implement show/hide animations
  176. propTween = false;
  177. for ( prop in orig ) {
  178. // General show/hide setup for this element animation
  179. if ( !propTween ) {
  180. if ( dataShow ) {
  181. if ( "hidden" in dataShow ) {
  182. hidden = dataShow.hidden;
  183. }
  184. } else {
  185. dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
  186. }
  187. // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
  188. if ( toggle ) {
  189. dataShow.hidden = !hidden;
  190. }
  191. // Show elements before animating them
  192. if ( hidden ) {
  193. showHide( [ elem ], true );
  194. }
  195. /* eslint-disable no-loop-func */
  196. anim.done( function() {
  197. /* eslint-enable no-loop-func */
  198. // The final step of a "hide" animation is actually hiding the element
  199. if ( !hidden ) {
  200. showHide( [ elem ] );
  201. }
  202. dataPriv.remove( elem, "fxshow" );
  203. for ( prop in orig ) {
  204. jQuery.style( elem, prop, orig[ prop ] );
  205. }
  206. } );
  207. }
  208. // Per-property setup
  209. propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
  210. if ( !( prop in dataShow ) ) {
  211. dataShow[ prop ] = propTween.start;
  212. if ( hidden ) {
  213. propTween.end = propTween.start;
  214. propTween.start = 0;
  215. }
  216. }
  217. }
  218. }
  219. function propFilter( props, specialEasing ) {
  220. var index, name, easing, value, hooks;
  221. // camelCase, specialEasing and expand cssHook pass
  222. for ( index in props ) {
  223. name = jQuery.camelCase( index );
  224. easing = specialEasing[ name ];
  225. value = props[ index ];
  226. if ( Array.isArray( value ) ) {
  227. easing = value[ 1 ];
  228. value = props[ index ] = value[ 0 ];
  229. }
  230. if ( index !== name ) {
  231. props[ name ] = value;
  232. delete props[ index ];
  233. }
  234. hooks = jQuery.cssHooks[ name ];
  235. if ( hooks && "expand" in hooks ) {
  236. value = hooks.expand( value );
  237. delete props[ name ];
  238. // Not quite $.extend, this won't overwrite existing keys.
  239. // Reusing 'index' because we have the correct "name"
  240. for ( index in value ) {
  241. if ( !( index in props ) ) {
  242. props[ index ] = value[ index ];
  243. specialEasing[ index ] = easing;
  244. }
  245. }
  246. } else {
  247. specialEasing[ name ] = easing;
  248. }
  249. }
  250. }
  251. function Animation( elem, properties, options ) {
  252. var result,
  253. stopped,
  254. index = 0,
  255. length = Animation.prefilters.length,
  256. deferred = jQuery.Deferred().always( function() {
  257. // Don't match elem in the :animated selector
  258. delete tick.elem;
  259. } ),
  260. tick = function() {
  261. if ( stopped ) {
  262. return false;
  263. }
  264. var currentTime = fxNow || createFxNow(),
  265. remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
  266. // Support: Android 2.3 only
  267. // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
  268. temp = remaining / animation.duration || 0,
  269. percent = 1 - temp,
  270. index = 0,
  271. length = animation.tweens.length;
  272. for ( ; index < length; index++ ) {
  273. animation.tweens[ index ].run( percent );
  274. }
  275. deferred.notifyWith( elem, [ animation, percent, remaining ] );
  276. // If there's more to do, yield
  277. if ( percent < 1 && length ) {
  278. return remaining;
  279. }
  280. // If this was an empty animation, synthesize a final progress notification
  281. if ( !length ) {
  282. deferred.notifyWith( elem, [ animation, 1, 0 ] );
  283. }
  284. // Resolve the animation and report its conclusion
  285. deferred.resolveWith( elem, [ animation ] );
  286. return false;
  287. },
  288. animation = deferred.promise( {
  289. elem: elem,
  290. props: jQuery.extend( {}, properties ),
  291. opts: jQuery.extend( true, {
  292. specialEasing: {},
  293. easing: jQuery.easing._default
  294. }, options ),
  295. originalProperties: properties,
  296. originalOptions: options,
  297. startTime: fxNow || createFxNow(),
  298. duration: options.duration,
  299. tweens: [],
  300. createTween: function( prop, end ) {
  301. var tween = jQuery.Tween( elem, animation.opts, prop, end,
  302. animation.opts.specialEasing[ prop ] || animation.opts.easing );
  303. animation.tweens.push( tween );
  304. return tween;
  305. },
  306. stop: function( gotoEnd ) {
  307. var index = 0,
  308. // If we are going to the end, we want to run all the tweens
  309. // otherwise we skip this part
  310. length = gotoEnd ? animation.tweens.length : 0;
  311. if ( stopped ) {
  312. return this;
  313. }
  314. stopped = true;
  315. for ( ; index < length; index++ ) {
  316. animation.tweens[ index ].run( 1 );
  317. }
  318. // Resolve when we played the last frame; otherwise, reject
  319. if ( gotoEnd ) {
  320. deferred.notifyWith( elem, [ animation, 1, 0 ] );
  321. deferred.resolveWith( elem, [ animation, gotoEnd ] );
  322. } else {
  323. deferred.rejectWith( elem, [ animation, gotoEnd ] );
  324. }
  325. return this;
  326. }
  327. } ),
  328. props = animation.props;
  329. propFilter( props, animation.opts.specialEasing );
  330. for ( ; index < length; index++ ) {
  331. result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
  332. if ( result ) {
  333. if ( jQuery.isFunction( result.stop ) ) {
  334. jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
  335. jQuery.proxy( result.stop, result );
  336. }
  337. return result;
  338. }
  339. }
  340. jQuery.map( props, createTween, animation );
  341. if ( jQuery.isFunction( animation.opts.start ) ) {
  342. animation.opts.start.call( elem, animation );
  343. }
  344. // Attach callbacks from options
  345. animation
  346. .progress( animation.opts.progress )
  347. .done( animation.opts.done, animation.opts.complete )
  348. .fail( animation.opts.fail )
  349. .always( animation.opts.always );
  350. jQuery.fx.timer(
  351. jQuery.extend( tick, {
  352. elem: elem,
  353. anim: animation,
  354. queue: animation.opts.queue
  355. } )
  356. );
  357. return animation;
  358. }
  359. jQuery.Animation = jQuery.extend( Animation, {
  360. tweeners: {
  361. "*": [ function( prop, value ) {
  362. var tween = this.createTween( prop, value );
  363. adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
  364. return tween;
  365. } ]
  366. },
  367. tweener: function( props, callback ) {
  368. if ( jQuery.isFunction( props ) ) {
  369. callback = props;
  370. props = [ "*" ];
  371. } else {
  372. props = props.match( rnothtmlwhite );
  373. }
  374. var prop,
  375. index = 0,
  376. length = props.length;
  377. for ( ; index < length; index++ ) {
  378. prop = props[ index ];
  379. Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
  380. Animation.tweeners[ prop ].unshift( callback );
  381. }
  382. },
  383. prefilters: [ defaultPrefilter ],
  384. prefilter: function( callback, prepend ) {
  385. if ( prepend ) {
  386. Animation.prefilters.unshift( callback );
  387. } else {
  388. Animation.prefilters.push( callback );
  389. }
  390. }
  391. } );
  392. jQuery.speed = function( speed, easing, fn ) {
  393. var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
  394. complete: fn || !fn && easing ||
  395. jQuery.isFunction( speed ) && speed,
  396. duration: speed,
  397. easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
  398. };
  399. // Go to the end state if fx are off
  400. if ( jQuery.fx.off ) {
  401. opt.duration = 0;
  402. } else {
  403. if ( typeof opt.duration !== "number" ) {
  404. if ( opt.duration in jQuery.fx.speeds ) {
  405. opt.duration = jQuery.fx.speeds[ opt.duration ];
  406. } else {
  407. opt.duration = jQuery.fx.speeds._default;
  408. }
  409. }
  410. }
  411. // Normalize opt.queue - true/undefined/null -> "fx"
  412. if ( opt.queue == null || opt.queue === true ) {
  413. opt.queue = "fx";
  414. }
  415. // Queueing
  416. opt.old = opt.complete;
  417. opt.complete = function() {
  418. if ( jQuery.isFunction( opt.old ) ) {
  419. opt.old.call( this );
  420. }
  421. if ( opt.queue ) {
  422. jQuery.dequeue( this, opt.queue );
  423. }
  424. };
  425. return opt;
  426. };
  427. jQuery.fn.extend( {
  428. fadeTo: function( speed, to, easing, callback ) {
  429. // Show any hidden elements after setting opacity to 0
  430. return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
  431. // Animate to the value specified
  432. .end().animate( { opacity: to }, speed, easing, callback );
  433. },
  434. animate: function( prop, speed, easing, callback ) {
  435. var empty = jQuery.isEmptyObject( prop ),
  436. optall = jQuery.speed( speed, easing, callback ),
  437. doAnimation = function() {
  438. // Operate on a copy of prop so per-property easing won't be lost
  439. var anim = Animation( this, jQuery.extend( {}, prop ), optall );
  440. // Empty animations, or finishing resolves immediately
  441. if ( empty || dataPriv.get( this, "finish" ) ) {
  442. anim.stop( true );
  443. }
  444. };
  445. doAnimation.finish = doAnimation;
  446. return empty || optall.queue === false ?
  447. this.each( doAnimation ) :
  448. this.queue( optall.queue, doAnimation );
  449. },
  450. stop: function( type, clearQueue, gotoEnd ) {
  451. var stopQueue = function( hooks ) {
  452. var stop = hooks.stop;
  453. delete hooks.stop;
  454. stop( gotoEnd );
  455. };
  456. if ( typeof type !== "string" ) {
  457. gotoEnd = clearQueue;
  458. clearQueue = type;
  459. type = undefined;
  460. }
  461. if ( clearQueue && type !== false ) {
  462. this.queue( type || "fx", [] );
  463. }
  464. return this.each( function() {
  465. var dequeue = true,
  466. index = type != null && type + "queueHooks",
  467. timers = jQuery.timers,
  468. data = dataPriv.get( this );
  469. if ( index ) {
  470. if ( data[ index ] && data[ index ].stop ) {
  471. stopQueue( data[ index ] );
  472. }
  473. } else {
  474. for ( index in data ) {
  475. if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
  476. stopQueue( data[ index ] );
  477. }
  478. }
  479. }
  480. for ( index = timers.length; index--; ) {
  481. if ( timers[ index ].elem === this &&
  482. ( type == null || timers[ index ].queue === type ) ) {
  483. timers[ index ].anim.stop( gotoEnd );
  484. dequeue = false;
  485. timers.splice( index, 1 );
  486. }
  487. }
  488. // Start the next in the queue if the last step wasn't forced.
  489. // Timers currently will call their complete callbacks, which
  490. // will dequeue but only if they were gotoEnd.
  491. if ( dequeue || !gotoEnd ) {
  492. jQuery.dequeue( this, type );
  493. }
  494. } );
  495. },
  496. finish: function( type ) {
  497. if ( type !== false ) {
  498. type = type || "fx";
  499. }
  500. return this.each( function() {
  501. var index,
  502. data = dataPriv.get( this ),
  503. queue = data[ type + "queue" ],
  504. hooks = data[ type + "queueHooks" ],
  505. timers = jQuery.timers,
  506. length = queue ? queue.length : 0;
  507. // Enable finishing flag on private data
  508. data.finish = true;
  509. // Empty the queue first
  510. jQuery.queue( this, type, [] );
  511. if ( hooks && hooks.stop ) {
  512. hooks.stop.call( this, true );
  513. }
  514. // Look for any active animations, and finish them
  515. for ( index = timers.length; index--; ) {
  516. if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
  517. timers[ index ].anim.stop( true );
  518. timers.splice( index, 1 );
  519. }
  520. }
  521. // Look for any animations in the old queue and finish them
  522. for ( index = 0; index < length; index++ ) {
  523. if ( queue[ index ] && queue[ index ].finish ) {
  524. queue[ index ].finish.call( this );
  525. }
  526. }
  527. // Turn off finishing flag
  528. delete data.finish;
  529. } );
  530. }
  531. } );
  532. jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
  533. var cssFn = jQuery.fn[ name ];
  534. jQuery.fn[ name ] = function( speed, easing, callback ) {
  535. return speed == null || typeof speed === "boolean" ?
  536. cssFn.apply( this, arguments ) :
  537. this.animate( genFx( name, true ), speed, easing, callback );
  538. };
  539. } );
  540. // Generate shortcuts for custom animations
  541. jQuery.each( {
  542. slideDown: genFx( "show" ),
  543. slideUp: genFx( "hide" ),
  544. slideToggle: genFx( "toggle" ),
  545. fadeIn: { opacity: "show" },
  546. fadeOut: { opacity: "hide" },
  547. fadeToggle: { opacity: "toggle" }
  548. }, function( name, props ) {
  549. jQuery.fn[ name ] = function( speed, easing, callback ) {
  550. return this.animate( props, speed, easing, callback );
  551. };
  552. } );
  553. jQuery.timers = [];
  554. jQuery.fx.tick = function() {
  555. var timer,
  556. i = 0,
  557. timers = jQuery.timers;
  558. fxNow = jQuery.now();
  559. for ( ; i < timers.length; i++ ) {
  560. timer = timers[ i ];
  561. // Run the timer and safely remove it when done (allowing for external removal)
  562. if ( !timer() && timers[ i ] === timer ) {
  563. timers.splice( i--, 1 );
  564. }
  565. }
  566. if ( !timers.length ) {
  567. jQuery.fx.stop();
  568. }
  569. fxNow = undefined;
  570. };
  571. jQuery.fx.timer = function( timer ) {
  572. jQuery.timers.push( timer );
  573. jQuery.fx.start();
  574. };
  575. jQuery.fx.interval = 13;
  576. jQuery.fx.start = function() {
  577. if ( inProgress ) {
  578. return;
  579. }
  580. inProgress = true;
  581. schedule();
  582. };
  583. jQuery.fx.stop = function() {
  584. inProgress = null;
  585. };
  586. jQuery.fx.speeds = {
  587. slow: 600,
  588. fast: 200,
  589. // Default speed
  590. _default: 400
  591. };
  592. return jQuery;
  593. } );