effects.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. var fxNow, timerId,
  2. rfxtypes = /^(?:toggle|show|hide)$/,
  3. rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
  4. rrun = /queueHooks$/,
  5. animationPrefilters = [ defaultPrefilter ],
  6. tweeners = {
  7. "*": [function( prop, value ) {
  8. var tween = this.createTween( prop, value ),
  9. target = tween.cur(),
  10. parts = rfxnum.exec( value ),
  11. unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
  12. // Starting value computation is required for potential unit mismatches
  13. start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
  14. rfxnum.exec( jQuery.css( tween.elem, prop ) ),
  15. scale = 1,
  16. maxIterations = 20;
  17. if ( start && start[ 3 ] !== unit ) {
  18. // Trust units reported by jQuery.css
  19. unit = unit || start[ 3 ];
  20. // Make sure we update the tween properties later on
  21. parts = parts || [];
  22. // Iteratively approximate from a nonzero starting point
  23. start = +target || 1;
  24. do {
  25. // If previous iteration zeroed out, double until we get *something*
  26. // Use a string for doubling factor so we don't accidentally see scale as unchanged below
  27. scale = scale || ".5";
  28. // Adjust and apply
  29. start = start / scale;
  30. jQuery.style( tween.elem, prop, start + unit );
  31. // Update scale, tolerating zero or NaN from tween.cur()
  32. // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
  33. } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
  34. }
  35. // Update tween properties
  36. if ( parts ) {
  37. start = tween.start = +start || +target || 0;
  38. tween.unit = unit;
  39. // If a +=/-= token was provided, we're doing a relative animation
  40. tween.end = parts[ 1 ] ?
  41. start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
  42. +parts[ 2 ];
  43. }
  44. return tween;
  45. }]
  46. };
  47. // Animations created synchronously will run synchronously
  48. function createFxNow() {
  49. setTimeout(function() {
  50. fxNow = undefined;
  51. });
  52. return ( fxNow = jQuery.now() );
  53. }
  54. function createTween( value, prop, animation ) {
  55. var tween,
  56. collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
  57. index = 0,
  58. length = collection.length;
  59. for ( ; index < length; index++ ) {
  60. if ( (tween = collection[ index ].call( animation, prop, value )) ) {
  61. // we're done with this property
  62. return tween;
  63. }
  64. }
  65. }
  66. function Animation( elem, properties, options ) {
  67. var result,
  68. stopped,
  69. index = 0,
  70. length = animationPrefilters.length,
  71. deferred = jQuery.Deferred().always( function() {
  72. // don't match elem in the :animated selector
  73. delete tick.elem;
  74. }),
  75. tick = function() {
  76. if ( stopped ) {
  77. return false;
  78. }
  79. var currentTime = fxNow || createFxNow(),
  80. remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
  81. // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
  82. temp = remaining / animation.duration || 0,
  83. percent = 1 - temp,
  84. index = 0,
  85. length = animation.tweens.length;
  86. for ( ; index < length ; index++ ) {
  87. animation.tweens[ index ].run( percent );
  88. }
  89. deferred.notifyWith( elem, [ animation, percent, remaining ]);
  90. if ( percent < 1 && length ) {
  91. return remaining;
  92. } else {
  93. deferred.resolveWith( elem, [ animation ] );
  94. return false;
  95. }
  96. },
  97. animation = deferred.promise({
  98. elem: elem,
  99. props: jQuery.extend( {}, properties ),
  100. opts: jQuery.extend( true, { specialEasing: {} }, options ),
  101. originalProperties: properties,
  102. originalOptions: options,
  103. startTime: fxNow || createFxNow(),
  104. duration: options.duration,
  105. tweens: [],
  106. createTween: function( prop, end ) {
  107. var tween = jQuery.Tween( elem, animation.opts, prop, end,
  108. animation.opts.specialEasing[ prop ] || animation.opts.easing );
  109. animation.tweens.push( tween );
  110. return tween;
  111. },
  112. stop: function( gotoEnd ) {
  113. var index = 0,
  114. // if we are going to the end, we want to run all the tweens
  115. // otherwise we skip this part
  116. length = gotoEnd ? animation.tweens.length : 0;
  117. if ( stopped ) {
  118. return this;
  119. }
  120. stopped = true;
  121. for ( ; index < length ; index++ ) {
  122. animation.tweens[ index ].run( 1 );
  123. }
  124. // resolve when we played the last frame
  125. // otherwise, reject
  126. if ( gotoEnd ) {
  127. deferred.resolveWith( elem, [ animation, gotoEnd ] );
  128. } else {
  129. deferred.rejectWith( elem, [ animation, gotoEnd ] );
  130. }
  131. return this;
  132. }
  133. }),
  134. props = animation.props;
  135. propFilter( props, animation.opts.specialEasing );
  136. for ( ; index < length ; index++ ) {
  137. result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
  138. if ( result ) {
  139. return result;
  140. }
  141. }
  142. jQuery.map( props, createTween, animation );
  143. if ( jQuery.isFunction( animation.opts.start ) ) {
  144. animation.opts.start.call( elem, animation );
  145. }
  146. jQuery.fx.timer(
  147. jQuery.extend( tick, {
  148. elem: elem,
  149. anim: animation,
  150. queue: animation.opts.queue
  151. })
  152. );
  153. // attach callbacks from options
  154. return animation.progress( animation.opts.progress )
  155. .done( animation.opts.done, animation.opts.complete )
  156. .fail( animation.opts.fail )
  157. .always( animation.opts.always );
  158. }
  159. function propFilter( props, specialEasing ) {
  160. var index, name, easing, value, hooks;
  161. // camelCase, specialEasing and expand cssHook pass
  162. for ( index in props ) {
  163. name = jQuery.camelCase( index );
  164. easing = specialEasing[ name ];
  165. value = props[ index ];
  166. if ( jQuery.isArray( value ) ) {
  167. easing = value[ 1 ];
  168. value = props[ index ] = value[ 0 ];
  169. }
  170. if ( index !== name ) {
  171. props[ name ] = value;
  172. delete props[ index ];
  173. }
  174. hooks = jQuery.cssHooks[ name ];
  175. if ( hooks && "expand" in hooks ) {
  176. value = hooks.expand( value );
  177. delete props[ name ];
  178. // not quite $.extend, this wont overwrite keys already present.
  179. // also - reusing 'index' from above because we have the correct "name"
  180. for ( index in value ) {
  181. if ( !( index in props ) ) {
  182. props[ index ] = value[ index ];
  183. specialEasing[ index ] = easing;
  184. }
  185. }
  186. } else {
  187. specialEasing[ name ] = easing;
  188. }
  189. }
  190. }
  191. jQuery.Animation = jQuery.extend( Animation, {
  192. tweener: function( props, callback ) {
  193. if ( jQuery.isFunction( props ) ) {
  194. callback = props;
  195. props = [ "*" ];
  196. } else {
  197. props = props.split(" ");
  198. }
  199. var prop,
  200. index = 0,
  201. length = props.length;
  202. for ( ; index < length ; index++ ) {
  203. prop = props[ index ];
  204. tweeners[ prop ] = tweeners[ prop ] || [];
  205. tweeners[ prop ].unshift( callback );
  206. }
  207. },
  208. prefilter: function( callback, prepend ) {
  209. if ( prepend ) {
  210. animationPrefilters.unshift( callback );
  211. } else {
  212. animationPrefilters.push( callback );
  213. }
  214. }
  215. });
  216. function defaultPrefilter( elem, props, opts ) {
  217. /* jshint validthis: true */
  218. var prop, value, toggle, tween, hooks, oldfire,
  219. anim = this,
  220. orig = {},
  221. style = elem.style,
  222. hidden = elem.nodeType && isHidden( elem ),
  223. dataShow = data_priv.get( elem, "fxshow" );
  224. // handle queue: false promises
  225. if ( !opts.queue ) {
  226. hooks = jQuery._queueHooks( elem, "fx" );
  227. if ( hooks.unqueued == null ) {
  228. hooks.unqueued = 0;
  229. oldfire = hooks.empty.fire;
  230. hooks.empty.fire = function() {
  231. if ( !hooks.unqueued ) {
  232. oldfire();
  233. }
  234. };
  235. }
  236. hooks.unqueued++;
  237. anim.always(function() {
  238. // doing this makes sure that the complete handler will be called
  239. // before this completes
  240. anim.always(function() {
  241. hooks.unqueued--;
  242. if ( !jQuery.queue( elem, "fx" ).length ) {
  243. hooks.empty.fire();
  244. }
  245. });
  246. });
  247. }
  248. // height/width overflow pass
  249. if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
  250. // Make sure that nothing sneaks out
  251. // Record all 3 overflow attributes because IE9-10 do not
  252. // change the overflow attribute when overflowX and
  253. // overflowY are set to the same value
  254. opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
  255. // Set display property to inline-block for height/width
  256. // animations on inline elements that are having width/height animated
  257. if ( jQuery.css( elem, "display" ) === "inline" &&
  258. jQuery.css( elem, "float" ) === "none" ) {
  259. style.display = "inline-block";
  260. }
  261. }
  262. if ( opts.overflow ) {
  263. style.overflow = "hidden";
  264. anim.always(function() {
  265. style.overflow = opts.overflow[ 0 ];
  266. style.overflowX = opts.overflow[ 1 ];
  267. style.overflowY = opts.overflow[ 2 ];
  268. });
  269. }
  270. // show/hide pass
  271. for ( prop in props ) {
  272. value = props[ prop ];
  273. if ( rfxtypes.exec( value ) ) {
  274. delete props[ prop ];
  275. toggle = toggle || value === "toggle";
  276. if ( value === ( hidden ? "hide" : "show" ) ) {
  277. // 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
  278. if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
  279. hidden = true;
  280. } else {
  281. continue;
  282. }
  283. }
  284. orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
  285. }
  286. }
  287. if ( !jQuery.isEmptyObject( orig ) ) {
  288. if ( dataShow ) {
  289. if ( "hidden" in dataShow ) {
  290. hidden = dataShow.hidden;
  291. }
  292. } else {
  293. dataShow = data_priv.access( elem, "fxshow", {} );
  294. }
  295. // store state if its toggle - enables .stop().toggle() to "reverse"
  296. if ( toggle ) {
  297. dataShow.hidden = !hidden;
  298. }
  299. if ( hidden ) {
  300. jQuery( elem ).show();
  301. } else {
  302. anim.done(function() {
  303. jQuery( elem ).hide();
  304. });
  305. }
  306. anim.done(function() {
  307. var prop;
  308. data_priv.remove( elem, "fxshow" );
  309. for ( prop in orig ) {
  310. jQuery.style( elem, prop, orig[ prop ] );
  311. }
  312. });
  313. for ( prop in orig ) {
  314. tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
  315. if ( !( prop in dataShow ) ) {
  316. dataShow[ prop ] = tween.start;
  317. if ( hidden ) {
  318. tween.end = tween.start;
  319. tween.start = prop === "width" || prop === "height" ? 1 : 0;
  320. }
  321. }
  322. }
  323. }
  324. }
  325. function Tween( elem, options, prop, end, easing ) {
  326. return new Tween.prototype.init( elem, options, prop, end, easing );
  327. }
  328. jQuery.Tween = Tween;
  329. Tween.prototype = {
  330. constructor: Tween,
  331. init: function( elem, options, prop, end, easing, unit ) {
  332. this.elem = elem;
  333. this.prop = prop;
  334. this.easing = easing || "swing";
  335. this.options = options;
  336. this.start = this.now = this.cur();
  337. this.end = end;
  338. this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
  339. },
  340. cur: function() {
  341. var hooks = Tween.propHooks[ this.prop ];
  342. return hooks && hooks.get ?
  343. hooks.get( this ) :
  344. Tween.propHooks._default.get( this );
  345. },
  346. run: function( percent ) {
  347. var eased,
  348. hooks = Tween.propHooks[ this.prop ];
  349. if ( this.options.duration ) {
  350. this.pos = eased = jQuery.easing[ this.easing ](
  351. percent, this.options.duration * percent, 0, 1, this.options.duration
  352. );
  353. } else {
  354. this.pos = eased = percent;
  355. }
  356. this.now = ( this.end - this.start ) * eased + this.start;
  357. if ( this.options.step ) {
  358. this.options.step.call( this.elem, this.now, this );
  359. }
  360. if ( hooks && hooks.set ) {
  361. hooks.set( this );
  362. } else {
  363. Tween.propHooks._default.set( this );
  364. }
  365. return this;
  366. }
  367. };
  368. Tween.prototype.init.prototype = Tween.prototype;
  369. Tween.propHooks = {
  370. _default: {
  371. get: function( tween ) {
  372. var result;
  373. if ( tween.elem[ tween.prop ] != null &&
  374. (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
  375. return tween.elem[ tween.prop ];
  376. }
  377. // passing an empty string as a 3rd parameter to .css will automatically
  378. // attempt a parseFloat and fallback to a string if the parse fails
  379. // so, simple values such as "10px" are parsed to Float.
  380. // complex values such as "rotate(1rad)" are returned as is.
  381. result = jQuery.css( tween.elem, tween.prop, "" );
  382. // Empty strings, null, undefined and "auto" are converted to 0.
  383. return !result || result === "auto" ? 0 : result;
  384. },
  385. set: function( tween ) {
  386. // use step hook for back compat - use cssHook if its there - use .style if its
  387. // available and use plain properties where available
  388. if ( jQuery.fx.step[ tween.prop ] ) {
  389. jQuery.fx.step[ tween.prop ]( tween );
  390. } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
  391. jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
  392. } else {
  393. tween.elem[ tween.prop ] = tween.now;
  394. }
  395. }
  396. }
  397. };
  398. // Support: IE9
  399. // Panic based approach to setting things on disconnected nodes
  400. Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
  401. set: function( tween ) {
  402. if ( tween.elem.nodeType && tween.elem.parentNode ) {
  403. tween.elem[ tween.prop ] = tween.now;
  404. }
  405. }
  406. };
  407. jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
  408. var cssFn = jQuery.fn[ name ];
  409. jQuery.fn[ name ] = function( speed, easing, callback ) {
  410. return speed == null || typeof speed === "boolean" ?
  411. cssFn.apply( this, arguments ) :
  412. this.animate( genFx( name, true ), speed, easing, callback );
  413. };
  414. });
  415. jQuery.fn.extend({
  416. fadeTo: function( speed, to, easing, callback ) {
  417. // show any hidden elements after setting opacity to 0
  418. return this.filter( isHidden ).css( "opacity", 0 ).show()
  419. // animate to the value specified
  420. .end().animate({ opacity: to }, speed, easing, callback );
  421. },
  422. animate: function( prop, speed, easing, callback ) {
  423. var empty = jQuery.isEmptyObject( prop ),
  424. optall = jQuery.speed( speed, easing, callback ),
  425. doAnimation = function() {
  426. // Operate on a copy of prop so per-property easing won't be lost
  427. var anim = Animation( this, jQuery.extend( {}, prop ), optall );
  428. // Empty animations, or finishing resolves immediately
  429. if ( empty || data_priv.get( this, "finish" ) ) {
  430. anim.stop( true );
  431. }
  432. };
  433. doAnimation.finish = doAnimation;
  434. return empty || optall.queue === false ?
  435. this.each( doAnimation ) :
  436. this.queue( optall.queue, doAnimation );
  437. },
  438. stop: function( type, clearQueue, gotoEnd ) {
  439. var stopQueue = function( hooks ) {
  440. var stop = hooks.stop;
  441. delete hooks.stop;
  442. stop( gotoEnd );
  443. };
  444. if ( typeof type !== "string" ) {
  445. gotoEnd = clearQueue;
  446. clearQueue = type;
  447. type = undefined;
  448. }
  449. if ( clearQueue && type !== false ) {
  450. this.queue( type || "fx", [] );
  451. }
  452. return this.each(function() {
  453. var dequeue = true,
  454. index = type != null && type + "queueHooks",
  455. timers = jQuery.timers,
  456. data = data_priv.get( this );
  457. if ( index ) {
  458. if ( data[ index ] && data[ index ].stop ) {
  459. stopQueue( data[ index ] );
  460. }
  461. } else {
  462. for ( index in data ) {
  463. if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
  464. stopQueue( data[ index ] );
  465. }
  466. }
  467. }
  468. for ( index = timers.length; index--; ) {
  469. if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
  470. timers[ index ].anim.stop( gotoEnd );
  471. dequeue = false;
  472. timers.splice( index, 1 );
  473. }
  474. }
  475. // start the next in the queue if the last step wasn't forced
  476. // timers currently will call their complete callbacks, which will dequeue
  477. // but only if they were gotoEnd
  478. if ( dequeue || !gotoEnd ) {
  479. jQuery.dequeue( this, type );
  480. }
  481. });
  482. },
  483. finish: function( type ) {
  484. if ( type !== false ) {
  485. type = type || "fx";
  486. }
  487. return this.each(function() {
  488. var index,
  489. data = data_priv.get( this ),
  490. queue = data[ type + "queue" ],
  491. hooks = data[ type + "queueHooks" ],
  492. timers = jQuery.timers,
  493. length = queue ? queue.length : 0;
  494. // enable finishing flag on private data
  495. data.finish = true;
  496. // empty the queue first
  497. jQuery.queue( this, type, [] );
  498. if ( hooks && hooks.stop ) {
  499. hooks.stop.call( this, true );
  500. }
  501. // look for any active animations, and finish them
  502. for ( index = timers.length; index--; ) {
  503. if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
  504. timers[ index ].anim.stop( true );
  505. timers.splice( index, 1 );
  506. }
  507. }
  508. // look for any animations in the old queue and finish them
  509. for ( index = 0; index < length; index++ ) {
  510. if ( queue[ index ] && queue[ index ].finish ) {
  511. queue[ index ].finish.call( this );
  512. }
  513. }
  514. // turn off finishing flag
  515. delete data.finish;
  516. });
  517. }
  518. });
  519. // Generate parameters to create a standard animation
  520. function genFx( type, includeWidth ) {
  521. var which,
  522. attrs = { height: type },
  523. i = 0;
  524. // if we include width, step value is 1 to do all cssExpand values,
  525. // if we don't include width, step value is 2 to skip over Left and Right
  526. includeWidth = includeWidth? 1 : 0;
  527. for( ; i < 4 ; i += 2 - includeWidth ) {
  528. which = cssExpand[ i ];
  529. attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
  530. }
  531. if ( includeWidth ) {
  532. attrs.opacity = attrs.width = type;
  533. }
  534. return attrs;
  535. }
  536. // Generate shortcuts for custom animations
  537. jQuery.each({
  538. slideDown: genFx("show"),
  539. slideUp: genFx("hide"),
  540. slideToggle: genFx("toggle"),
  541. fadeIn: { opacity: "show" },
  542. fadeOut: { opacity: "hide" },
  543. fadeToggle: { opacity: "toggle" }
  544. }, function( name, props ) {
  545. jQuery.fn[ name ] = function( speed, easing, callback ) {
  546. return this.animate( props, speed, easing, callback );
  547. };
  548. });
  549. jQuery.speed = function( speed, easing, fn ) {
  550. var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
  551. complete: fn || !fn && easing ||
  552. jQuery.isFunction( speed ) && speed,
  553. duration: speed,
  554. easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
  555. };
  556. opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
  557. opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
  558. // normalize opt.queue - true/undefined/null -> "fx"
  559. if ( opt.queue == null || opt.queue === true ) {
  560. opt.queue = "fx";
  561. }
  562. // Queueing
  563. opt.old = opt.complete;
  564. opt.complete = function() {
  565. if ( jQuery.isFunction( opt.old ) ) {
  566. opt.old.call( this );
  567. }
  568. if ( opt.queue ) {
  569. jQuery.dequeue( this, opt.queue );
  570. }
  571. };
  572. return opt;
  573. };
  574. jQuery.easing = {
  575. linear: function( p ) {
  576. return p;
  577. },
  578. swing: function( p ) {
  579. return 0.5 - Math.cos( p*Math.PI ) / 2;
  580. }
  581. };
  582. jQuery.timers = [];
  583. jQuery.fx = Tween.prototype.init;
  584. jQuery.fx.tick = function() {
  585. var timer,
  586. timers = jQuery.timers,
  587. i = 0;
  588. fxNow = jQuery.now();
  589. for ( ; i < timers.length; i++ ) {
  590. timer = timers[ i ];
  591. // Checks the timer has not already been removed
  592. if ( !timer() && timers[ i ] === timer ) {
  593. timers.splice( i--, 1 );
  594. }
  595. }
  596. if ( !timers.length ) {
  597. jQuery.fx.stop();
  598. }
  599. fxNow = undefined;
  600. };
  601. jQuery.fx.timer = function( timer ) {
  602. if ( timer() && jQuery.timers.push( timer ) ) {
  603. jQuery.fx.start();
  604. }
  605. };
  606. jQuery.fx.interval = 13;
  607. jQuery.fx.start = function() {
  608. if ( !timerId ) {
  609. timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
  610. }
  611. };
  612. jQuery.fx.stop = function() {
  613. clearInterval( timerId );
  614. timerId = null;
  615. };
  616. jQuery.fx.speeds = {
  617. slow: 600,
  618. fast: 200,
  619. // Default speed
  620. _default: 400
  621. };
  622. // Back Compat <1.8 extension point
  623. jQuery.fx.step = {};
  624. if ( jQuery.expr && jQuery.expr.filters ) {
  625. jQuery.expr.filters.animated = function( elem ) {
  626. return jQuery.grep(jQuery.timers, function( fn ) {
  627. return elem === fn.elem;
  628. }).length;
  629. };
  630. }