Front end of the Slack clone application.

animation.js 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. import { isDefined } from '../util/util';
  2. /**
  3. * @hidden
  4. */
  5. var Animation = (function () {
  6. function Animation(plt, ele, opts) {
  7. this._dur = null;
  8. this._es = null;
  9. this._rvEs = null;
  10. this.hasChildren = false;
  11. this.isPlaying = false;
  12. this.hasCompleted = false;
  13. this.plt = plt;
  14. this.element(ele);
  15. this.opts = opts;
  16. }
  17. Animation.prototype.element = function (ele) {
  18. if (ele) {
  19. if (typeof ele === 'string') {
  20. ele = this.plt.doc().querySelectorAll(ele);
  21. for (var i = 0; i < ele.length; i++) {
  22. this._addEle(ele[i]);
  23. }
  24. }
  25. else if (ele.length) {
  26. for (var i = 0; i < ele.length; i++) {
  27. this._addEle(ele[i]);
  28. }
  29. }
  30. else {
  31. this._addEle(ele);
  32. }
  33. }
  34. return this;
  35. };
  36. /**
  37. * NO DOM
  38. */
  39. Animation.prototype._addEle = function (ele) {
  40. if (ele.nativeElement) {
  41. ele = ele.nativeElement;
  42. }
  43. if (ele.nodeType === 1) {
  44. this._eL = (this._e = this._e || []).push(ele);
  45. }
  46. };
  47. /**
  48. * Add a child animation to this animation.
  49. */
  50. Animation.prototype.add = function (childAnimation) {
  51. childAnimation.parent = this;
  52. this.hasChildren = true;
  53. this._cL = (this._c = this._c || []).push(childAnimation);
  54. return this;
  55. };
  56. /**
  57. * Get the duration of this animation. If this animation does
  58. * not have a duration, then it'll get the duration from its parent.
  59. */
  60. Animation.prototype.getDuration = function (opts) {
  61. if (opts && isDefined(opts.duration)) {
  62. return opts.duration;
  63. }
  64. else if (this._dur !== null) {
  65. return this._dur;
  66. }
  67. else if (this.parent) {
  68. return this.parent.getDuration();
  69. }
  70. return 0;
  71. };
  72. /**
  73. * Returns if the animation is a root one.
  74. */
  75. Animation.prototype.isRoot = function () {
  76. return !this.parent;
  77. };
  78. /**
  79. * Set the duration for this animation.
  80. */
  81. Animation.prototype.duration = function (milliseconds) {
  82. this._dur = milliseconds;
  83. return this;
  84. };
  85. /**
  86. * Get the easing of this animation. If this animation does
  87. * not have an easing, then it'll get the easing from its parent.
  88. */
  89. Animation.prototype.getEasing = function () {
  90. if (this._rv && this._rvEs) {
  91. return this._rvEs;
  92. }
  93. return this._es !== null ? this._es : (this.parent && this.parent.getEasing()) || null;
  94. };
  95. /**
  96. * Set the easing for this animation.
  97. */
  98. Animation.prototype.easing = function (name) {
  99. this._es = name;
  100. return this;
  101. };
  102. /**
  103. * Set the easing for this reversed animation.
  104. */
  105. Animation.prototype.easingReverse = function (name) {
  106. this._rvEs = name;
  107. return this;
  108. };
  109. /**
  110. * Add the "from" value for a specific property.
  111. */
  112. Animation.prototype.from = function (prop, val) {
  113. this._addProp('from', prop, val);
  114. return this;
  115. };
  116. /**
  117. * Add the "to" value for a specific property.
  118. */
  119. Animation.prototype.to = function (prop, val, clearProperyAfterTransition) {
  120. var fx = this._addProp('to', prop, val);
  121. if (clearProperyAfterTransition) {
  122. // if this effect is a transform then clear the transform effect
  123. // otherwise just clear the actual property
  124. this.afterClearStyles([fx.trans ? this.plt.Css.transform : prop]);
  125. }
  126. return this;
  127. };
  128. /**
  129. * Shortcut to add both the "from" and "to" for the same property.
  130. */
  131. Animation.prototype.fromTo = function (prop, fromVal, toVal, clearProperyAfterTransition) {
  132. return this.from(prop, fromVal).to(prop, toVal, clearProperyAfterTransition);
  133. };
  134. /**
  135. * @hidden
  136. * NO DOM
  137. */
  138. Animation.prototype._getProp = function (name) {
  139. if (this._fx) {
  140. return this._fx.find(function (prop) { return prop.name === name; });
  141. }
  142. else {
  143. this._fx = [];
  144. }
  145. return null;
  146. };
  147. Animation.prototype._addProp = function (state, prop, val) {
  148. var fxProp = this._getProp(prop);
  149. if (!fxProp) {
  150. // first time we've see this EffectProperty
  151. var shouldTrans = (ANIMATION_TRANSFORMS[prop] === 1);
  152. fxProp = {
  153. name: prop,
  154. trans: shouldTrans,
  155. // add the will-change property for transforms or opacity
  156. wc: (shouldTrans ? this.plt.Css.transform : prop)
  157. };
  158. this._fx.push(fxProp);
  159. }
  160. // add from/to EffectState to the EffectProperty
  161. var fxState = {
  162. val: val,
  163. num: null,
  164. unit: '',
  165. };
  166. fxProp[state] = fxState;
  167. if (typeof val === 'string' && val.indexOf(' ') < 0) {
  168. var r = val.match(ANIMATION_CSS_VALUE_REGEX);
  169. var num = parseFloat(r[1]);
  170. if (!isNaN(num)) {
  171. fxState.num = num;
  172. }
  173. fxState.unit = (r[0] !== r[2] ? r[2] : '');
  174. }
  175. else if (typeof val === 'number') {
  176. fxState.num = val;
  177. }
  178. return fxProp;
  179. };
  180. /**
  181. * Add CSS class to this animation's elements
  182. * before the animation begins.
  183. */
  184. Animation.prototype.beforeAddClass = function (className) {
  185. (this._bfAdd = this._bfAdd || []).push(className);
  186. return this;
  187. };
  188. /**
  189. * Remove CSS class from this animation's elements
  190. * before the animation begins.
  191. */
  192. Animation.prototype.beforeRemoveClass = function (className) {
  193. (this._bfRm = this._bfRm || []).push(className);
  194. return this;
  195. };
  196. /**
  197. * Set CSS inline styles to this animation's elements
  198. * before the animation begins.
  199. */
  200. Animation.prototype.beforeStyles = function (styles) {
  201. this._bfSty = styles;
  202. return this;
  203. };
  204. /**
  205. * Clear CSS inline styles from this animation's elements
  206. * before the animation begins.
  207. */
  208. Animation.prototype.beforeClearStyles = function (propertyNames) {
  209. this._bfSty = this._bfSty || {};
  210. for (var i = 0; i < propertyNames.length; i++) {
  211. this._bfSty[propertyNames[i]] = '';
  212. }
  213. return this;
  214. };
  215. /**
  216. * Add a function which contains DOM reads, which will run
  217. * before the animation begins.
  218. */
  219. Animation.prototype.beforeAddRead = function (domReadFn) {
  220. (this._rdFn = this._rdFn || []).push(domReadFn);
  221. return this;
  222. };
  223. /**
  224. * Add a function which contains DOM writes, which will run
  225. * before the animation begins.
  226. */
  227. Animation.prototype.beforeAddWrite = function (domWriteFn) {
  228. (this._wrFn = this._wrFn || []).push(domWriteFn);
  229. return this;
  230. };
  231. /**
  232. * Add CSS class to this animation's elements
  233. * after the animation finishes.
  234. */
  235. Animation.prototype.afterAddClass = function (className) {
  236. (this._afAdd = this._afAdd || []).push(className);
  237. return this;
  238. };
  239. /**
  240. * Remove CSS class from this animation's elements
  241. * after the animation finishes.
  242. */
  243. Animation.prototype.afterRemoveClass = function (className) {
  244. (this._afRm = this._afRm || []).push(className);
  245. return this;
  246. };
  247. /**
  248. * Set CSS inline styles to this animation's elements
  249. * after the animation finishes.
  250. */
  251. Animation.prototype.afterStyles = function (styles) {
  252. this._afSty = styles;
  253. return this;
  254. };
  255. /**
  256. * Clear CSS inline styles from this animation's elements
  257. * after the animation finishes.
  258. */
  259. Animation.prototype.afterClearStyles = function (propertyNames) {
  260. this._afSty = this._afSty || {};
  261. for (var i = 0; i < propertyNames.length; i++) {
  262. this._afSty[propertyNames[i]] = '';
  263. }
  264. return this;
  265. };
  266. /**
  267. * Play the animation.
  268. */
  269. Animation.prototype.play = function (opts) {
  270. var _this = this;
  271. // If the animation was already invalidated (it did finish), do nothing
  272. if (!this.plt) {
  273. return;
  274. }
  275. // this is the top level animation and is in full control
  276. // of when the async play() should actually kick off
  277. // if there is no duration then it'll set the TO property immediately
  278. // if there is a duration, then it'll stage all animations at the
  279. // FROM property and transition duration, wait a few frames, then
  280. // kick off the animation by setting the TO property for each animation
  281. this._isAsync = this._hasDuration(opts);
  282. // ensure all past transition end events have been cleared
  283. this._clearAsync();
  284. // recursively kicks off the correct progress step for each child animation
  285. // ******** DOM WRITE ****************
  286. this._playInit(opts);
  287. // doubling up RAFs since this animation was probably triggered
  288. // from an input event, and just having one RAF would have this code
  289. // run within the same frame as the triggering input event, and the
  290. // input event probably already did way too much work for one frame
  291. this.plt.raf(function () {
  292. _this.plt.raf(_this._playDomInspect.bind(_this, opts));
  293. });
  294. };
  295. Animation.prototype.syncPlay = function () {
  296. // If the animation was already invalidated (it did finish), do nothing
  297. if (!this.plt) {
  298. return;
  299. }
  300. var opts = { duration: 0 };
  301. this._isAsync = false;
  302. this._clearAsync();
  303. this._playInit(opts);
  304. this._playDomInspect(opts);
  305. };
  306. /**
  307. * @hidden
  308. * DOM WRITE
  309. * RECURSION
  310. */
  311. Animation.prototype._playInit = function (opts) {
  312. // always default that an animation does not tween
  313. // a tween requires that an Animation class has an element
  314. // and that it has at least one FROM/TO effect
  315. // and that the FROM/TO effect can tween numeric values
  316. this._twn = false;
  317. this.isPlaying = true;
  318. this.hasCompleted = false;
  319. this._hasDur = (this.getDuration(opts) > ANIMATION_DURATION_MIN);
  320. var children = this._c;
  321. for (var i = 0; i < this._cL; i++) {
  322. // ******** DOM WRITE ****************
  323. children[i]._playInit(opts);
  324. }
  325. if (this._hasDur) {
  326. // if there is a duration then we want to start at step 0
  327. // ******** DOM WRITE ****************
  328. this._progress(0);
  329. // add the will-change properties
  330. // ******** DOM WRITE ****************
  331. this._willChg(true);
  332. }
  333. };
  334. /**
  335. * @hidden
  336. * DOM WRITE
  337. * NO RECURSION
  338. * ROOT ANIMATION
  339. */
  340. Animation.prototype._playDomInspect = function (opts) {
  341. // fire off all the "before" function that have DOM READS in them
  342. // elements will be in the DOM, however visibily hidden
  343. // so we can read their dimensions if need be
  344. // ******** DOM READ ****************
  345. // ******** DOM WRITE ****************
  346. this._beforeAnimation();
  347. // for the root animation only
  348. // set the async TRANSITION END event
  349. // and run onFinishes when the transition ends
  350. var dur = this.getDuration(opts);
  351. if (this._isAsync) {
  352. this._asyncEnd(dur, true);
  353. }
  354. // ******** DOM WRITE ****************
  355. this._playProgress(opts);
  356. if (this._isAsync && this.plt) {
  357. // this animation has a duration so we need another RAF
  358. // for the CSS TRANSITION properties to kick in
  359. this.plt.raf(this._playToStep.bind(this, 1));
  360. }
  361. };
  362. /**
  363. * @hidden
  364. * DOM WRITE
  365. * RECURSION
  366. */
  367. Animation.prototype._playProgress = function (opts) {
  368. var children = this._c;
  369. for (var i = 0; i < this._cL; i++) {
  370. // ******** DOM WRITE ****************
  371. children[i]._playProgress(opts);
  372. }
  373. if (this._hasDur) {
  374. // set the CSS TRANSITION duration/easing
  375. // ******** DOM WRITE ****************
  376. this._setTrans(this.getDuration(opts), false);
  377. }
  378. else {
  379. // this animation does not have a duration, so it should not animate
  380. // just go straight to the TO properties and call it done
  381. // ******** DOM WRITE ****************
  382. this._progress(1);
  383. // since there was no animation, immediately run the after
  384. // ******** DOM WRITE ****************
  385. this._setAfterStyles();
  386. // this animation has no duration, so it has finished
  387. // other animations could still be running
  388. this._didFinish(true);
  389. }
  390. };
  391. /**
  392. * @hidden
  393. * DOM WRITE
  394. * RECURSION
  395. */
  396. Animation.prototype._playToStep = function (stepValue) {
  397. var children = this._c;
  398. for (var i = 0; i < this._cL; i++) {
  399. // ******** DOM WRITE ****************
  400. children[i]._playToStep(stepValue);
  401. }
  402. if (this._hasDur) {
  403. // browser had some time to render everything in place
  404. // and the transition duration/easing is set
  405. // now set the TO properties which will trigger the transition to begin
  406. // ******** DOM WRITE ****************
  407. this._progress(stepValue);
  408. }
  409. };
  410. /**
  411. * @hidden
  412. * DOM WRITE
  413. * NO RECURSION
  414. * ROOT ANIMATION
  415. */
  416. Animation.prototype._asyncEnd = function (dur, shouldComplete) {
  417. (void 0) /* assert */;
  418. (void 0) /* assert */;
  419. (void 0) /* assert */;
  420. var self = this;
  421. function onTransitionEnd() {
  422. // congrats! a successful transition completed!
  423. // ensure transition end events and timeouts have been cleared
  424. self._clearAsync();
  425. // ******** DOM WRITE ****************
  426. self._playEnd();
  427. // transition finished
  428. self._didFinishAll(shouldComplete, true, false);
  429. }
  430. function onTransitionFallback() {
  431. (void 0) /* console.debug */;
  432. // oh noz! the transition end event didn't fire in time!
  433. // instead the fallback timer when first
  434. // if all goes well this fallback should never fire
  435. // clear the other async end events from firing
  436. self._tm = undefined;
  437. self._clearAsync();
  438. // set the after styles
  439. // ******** DOM WRITE ****************
  440. self._playEnd(shouldComplete ? 1 : 0);
  441. // transition finished
  442. self._didFinishAll(shouldComplete, true, false);
  443. }
  444. // set the TRANSITION END event on one of the transition elements
  445. self._unrgTrns = this.plt.transitionEnd(self._transEl(), onTransitionEnd, false);
  446. // set a fallback timeout if the transition end event never fires, or is too slow
  447. // transition end fallback: (animation duration + XXms)
  448. self._tm = self.plt.timeout(onTransitionFallback, (dur + ANIMATION_TRANSITION_END_FALLBACK_PADDING_MS));
  449. };
  450. /**
  451. * @hidden
  452. * DOM WRITE
  453. * RECURSION
  454. */
  455. Animation.prototype._playEnd = function (stepValue) {
  456. var children = this._c;
  457. for (var i = 0; i < this._cL; i++) {
  458. // ******** DOM WRITE ****************
  459. children[i]._playEnd(stepValue);
  460. }
  461. if (this._hasDur) {
  462. if (isDefined(stepValue)) {
  463. // too late to have a smooth animation, just finish it
  464. // ******** DOM WRITE ****************
  465. this._setTrans(0, true);
  466. // ensure the ending progress step gets rendered
  467. // ******** DOM WRITE ****************
  468. this._progress(stepValue);
  469. }
  470. // set the after styles
  471. // ******** DOM WRITE ****************
  472. this._setAfterStyles();
  473. // remove the will-change properties
  474. // ******** DOM WRITE ****************
  475. this._willChg(false);
  476. }
  477. };
  478. /**
  479. * @hidden
  480. * NO DOM
  481. * RECURSION
  482. */
  483. Animation.prototype._hasDuration = function (opts) {
  484. if (this.getDuration(opts) > ANIMATION_DURATION_MIN) {
  485. return true;
  486. }
  487. var children = this._c;
  488. for (var i = 0; i < this._cL; i++) {
  489. if (children[i]._hasDuration(opts)) {
  490. return true;
  491. }
  492. }
  493. return false;
  494. };
  495. /**
  496. * @hidden
  497. * NO DOM
  498. * RECURSION
  499. */
  500. Animation.prototype._hasDomReads = function () {
  501. if (this._rdFn && this._rdFn.length) {
  502. return true;
  503. }
  504. var children = this._c;
  505. for (var i = 0; i < this._cL; i++) {
  506. if (children[i]._hasDomReads()) {
  507. return true;
  508. }
  509. }
  510. return false;
  511. };
  512. /**
  513. * Immediately stop at the end of the animation.
  514. */
  515. Animation.prototype.stop = function (stepValue) {
  516. if (stepValue === void 0) { stepValue = 1; }
  517. // ensure all past transition end events have been cleared
  518. this._clearAsync();
  519. this._hasDur = true;
  520. this._playEnd(stepValue);
  521. };
  522. /**
  523. * @hidden
  524. * NO DOM
  525. * NO RECURSION
  526. */
  527. Animation.prototype._clearAsync = function () {
  528. this._unrgTrns && this._unrgTrns();
  529. this._tm && clearTimeout(this._tm);
  530. this._tm = this._unrgTrns = undefined;
  531. };
  532. /**
  533. * @hidden
  534. * DOM WRITE
  535. * NO RECURSION
  536. */
  537. Animation.prototype._progress = function (stepValue) {
  538. // bread 'n butter
  539. var val;
  540. var effects = this._fx;
  541. var nuElements = this._eL;
  542. if (!effects || !nuElements) {
  543. return;
  544. }
  545. // flip the number if we're going in reverse
  546. if (this._rv) {
  547. stepValue = ((stepValue * -1) + 1);
  548. }
  549. var i, j;
  550. var finalTransform = '';
  551. var elements = this._e;
  552. for (i = 0; i < effects.length; i++) {
  553. var fx = effects[i];
  554. if (fx.from && fx.to) {
  555. var fromNum = fx.from.num;
  556. var toNum = fx.to.num;
  557. var tweenEffect = (fromNum !== toNum);
  558. (void 0) /* assert */;
  559. if (tweenEffect) {
  560. this._twn = true;
  561. }
  562. if (stepValue === 0) {
  563. // FROM
  564. val = fx.from.val;
  565. }
  566. else if (stepValue === 1) {
  567. // TO
  568. val = fx.to.val;
  569. }
  570. else if (tweenEffect) {
  571. // EVERYTHING IN BETWEEN
  572. var valNum = (((toNum - fromNum) * stepValue) + fromNum);
  573. var unit = fx.to.unit;
  574. if (unit === 'px') {
  575. valNum = Math.round(valNum);
  576. }
  577. val = valNum + unit;
  578. }
  579. if (val !== null) {
  580. var prop = fx.name;
  581. if (fx.trans) {
  582. finalTransform += prop + '(' + val + ') ';
  583. }
  584. else {
  585. for (j = 0; j < nuElements; j++) {
  586. // ******** DOM WRITE ****************
  587. elements[j].style[prop] = val;
  588. }
  589. }
  590. }
  591. }
  592. }
  593. // place all transforms on the same property
  594. if (finalTransform.length) {
  595. if (!this._rv && stepValue !== 1 || this._rv && stepValue !== 0) {
  596. finalTransform += 'translateZ(0px)';
  597. }
  598. var cssTransform = this.plt.Css.transform;
  599. for (i = 0; i < elements.length; i++) {
  600. // ******** DOM WRITE ****************
  601. elements[i].style[cssTransform] = finalTransform;
  602. }
  603. }
  604. };
  605. /**
  606. * @hidden
  607. * DOM WRITE
  608. * NO RECURSION
  609. */
  610. Animation.prototype._setTrans = function (dur, forcedLinearEasing) {
  611. // Transition is not enabled if there are not effects
  612. if (!this._fx) {
  613. return;
  614. }
  615. // set the TRANSITION properties inline on the element
  616. var elements = this._e;
  617. var easing = (forcedLinearEasing ? 'linear' : this.getEasing());
  618. var durString = dur + 'ms';
  619. var Css = this.plt.Css;
  620. var cssTransform = Css.transition;
  621. var cssTransitionDuration = Css.transitionDuration;
  622. var cssTransitionTimingFn = Css.transitionTimingFn;
  623. var eleStyle;
  624. for (var i = 0; i < this._eL; i++) {
  625. eleStyle = elements[i].style;
  626. if (dur > 0) {
  627. // ******** DOM WRITE ****************
  628. eleStyle[cssTransform] = '';
  629. eleStyle[cssTransitionDuration] = durString;
  630. // each animation can have a different easing
  631. if (easing) {
  632. // ******** DOM WRITE ****************
  633. eleStyle[cssTransitionTimingFn] = easing;
  634. }
  635. }
  636. else {
  637. eleStyle[cssTransform] = 'none';
  638. }
  639. }
  640. };
  641. /**
  642. * @hidden
  643. * DOM READ
  644. * DOM WRITE
  645. * RECURSION
  646. */
  647. Animation.prototype._beforeAnimation = function () {
  648. // fire off all the "before" function that have DOM READS in them
  649. // elements will be in the DOM, however visibily hidden
  650. // so we can read their dimensions if need be
  651. // ******** DOM READ ****************
  652. this._fireBeforeReadFunc();
  653. // ******** DOM READS ABOVE / DOM WRITES BELOW ****************
  654. // fire off all the "before" function that have DOM WRITES in them
  655. // ******** DOM WRITE ****************
  656. this._fireBeforeWriteFunc();
  657. // stage all of the before css classes and inline styles
  658. // ******** DOM WRITE ****************
  659. this._setBeforeStyles();
  660. };
  661. /**
  662. * @hidden
  663. * DOM WRITE
  664. * RECURSION
  665. */
  666. Animation.prototype._setBeforeStyles = function () {
  667. var i, j;
  668. var children = this._c;
  669. for (i = 0; i < this._cL; i++) {
  670. children[i]._setBeforeStyles();
  671. }
  672. // before the animations have started
  673. // only set before styles if animation is not reversed
  674. if (this._rv) {
  675. return;
  676. }
  677. var addClasses = this._bfAdd;
  678. var removeClasses = this._bfRm;
  679. var ele;
  680. var eleClassList;
  681. var prop;
  682. for (i = 0; i < this._eL; i++) {
  683. ele = this._e[i];
  684. eleClassList = ele.classList;
  685. // css classes to add before the animation
  686. if (addClasses) {
  687. for (j = 0; j < addClasses.length; j++) {
  688. // ******** DOM WRITE ****************
  689. eleClassList.add(addClasses[j]);
  690. }
  691. }
  692. // css classes to remove before the animation
  693. if (removeClasses) {
  694. for (j = 0; j < removeClasses.length; j++) {
  695. // ******** DOM WRITE ****************
  696. eleClassList.remove(removeClasses[j]);
  697. }
  698. }
  699. // inline styles to add before the animation
  700. if (this._bfSty) {
  701. for (prop in this._bfSty) {
  702. // ******** DOM WRITE ****************
  703. ele.style[prop] = this._bfSty[prop];
  704. }
  705. }
  706. }
  707. };
  708. /**
  709. * @hidden
  710. * DOM READ
  711. * RECURSION
  712. */
  713. Animation.prototype._fireBeforeReadFunc = function () {
  714. var children = this._c;
  715. for (var i = 0; i < this._cL; i++) {
  716. // ******** DOM READ ****************
  717. children[i]._fireBeforeReadFunc();
  718. }
  719. var readFunctions = this._rdFn;
  720. if (readFunctions) {
  721. for (var i = 0; i < readFunctions.length; i++) {
  722. // ******** DOM READ ****************
  723. readFunctions[i]();
  724. }
  725. }
  726. };
  727. /**
  728. * @hidden
  729. * DOM WRITE
  730. * RECURSION
  731. */
  732. Animation.prototype._fireBeforeWriteFunc = function () {
  733. var children = this._c;
  734. for (var i = 0; i < this._cL; i++) {
  735. // ******** DOM WRITE ****************
  736. children[i]._fireBeforeWriteFunc();
  737. }
  738. var writeFunctions = this._wrFn;
  739. if (this._wrFn) {
  740. for (var i = 0; i < writeFunctions.length; i++) {
  741. // ******** DOM WRITE ****************
  742. writeFunctions[i]();
  743. }
  744. }
  745. };
  746. /**
  747. * @hidden
  748. * DOM WRITE
  749. */
  750. Animation.prototype._setAfterStyles = function () {
  751. var i, j;
  752. var ele;
  753. var eleClassList;
  754. var elements = this._e;
  755. for (i = 0; i < this._eL; i++) {
  756. ele = elements[i];
  757. eleClassList = ele.classList;
  758. // remove the transition duration/easing
  759. // ******** DOM WRITE ****************
  760. ele.style[this.plt.Css.transitionDuration] = ele.style[this.plt.Css.transitionTimingFn] = '';
  761. if (this._rv) {
  762. // finished in reverse direction
  763. // css classes that were added before the animation should be removed
  764. if (this._bfAdd) {
  765. for (j = 0; j < this._bfAdd.length; j++) {
  766. // ******** DOM WRITE ****************
  767. eleClassList.remove(this._bfAdd[j]);
  768. }
  769. }
  770. // css classes that were removed before the animation should be added
  771. if (this._bfRm) {
  772. for (j = 0; j < this._bfRm.length; j++) {
  773. // ******** DOM WRITE ****************
  774. eleClassList.add(this._bfRm[j]);
  775. }
  776. }
  777. // inline styles that were added before the animation should be removed
  778. if (this._bfSty) {
  779. for (var prop in this._bfSty) {
  780. // ******** DOM WRITE ****************
  781. ele.style[prop] = '';
  782. }
  783. }
  784. }
  785. else {
  786. // finished in forward direction
  787. // css classes to add after the animation
  788. if (this._afAdd) {
  789. for (j = 0; j < this._afAdd.length; j++) {
  790. // ******** DOM WRITE ****************
  791. eleClassList.add(this._afAdd[j]);
  792. }
  793. }
  794. // css classes to remove after the animation
  795. if (this._afRm) {
  796. for (j = 0; j < this._afRm.length; j++) {
  797. // ******** DOM WRITE ****************
  798. eleClassList.remove(this._afRm[j]);
  799. }
  800. }
  801. // inline styles to add after the animation
  802. if (this._afSty) {
  803. for (var prop in this._afSty) {
  804. // ******** DOM WRITE ****************
  805. ele.style[prop] = this._afSty[prop];
  806. }
  807. }
  808. }
  809. }
  810. };
  811. /**
  812. * @hidden
  813. * DOM WRITE
  814. * NO RECURSION
  815. */
  816. Animation.prototype._willChg = function (addWillChange) {
  817. var wc;
  818. var effects = this._fx;
  819. var willChange;
  820. if (addWillChange && effects) {
  821. wc = [];
  822. for (var i = 0; i < effects.length; i++) {
  823. var propWC = effects[i].wc;
  824. if (propWC === 'webkitTransform') {
  825. wc.push('transform', '-webkit-transform');
  826. }
  827. else {
  828. wc.push(propWC);
  829. }
  830. }
  831. willChange = wc.join(',');
  832. }
  833. else {
  834. willChange = '';
  835. }
  836. for (var i = 0; i < this._eL; i++) {
  837. // ******** DOM WRITE ****************
  838. this._e[i].style.willChange = willChange;
  839. }
  840. };
  841. /**
  842. * Start the animation with a user controlled progress.
  843. */
  844. Animation.prototype.progressStart = function () {
  845. // ensure all past transition end events have been cleared
  846. this._clearAsync();
  847. // ******** DOM READ/WRITE ****************
  848. this._beforeAnimation();
  849. // ******** DOM WRITE ****************
  850. this._progressStart();
  851. };
  852. /**
  853. * @hidden
  854. * DOM WRITE
  855. * RECURSION
  856. */
  857. Animation.prototype._progressStart = function () {
  858. var children = this._c;
  859. for (var i = 0; i < this._cL; i++) {
  860. // ******** DOM WRITE ****************
  861. children[i]._progressStart();
  862. }
  863. // force no duration, linear easing
  864. // ******** DOM WRITE ****************
  865. this._setTrans(0, true);
  866. // ******** DOM WRITE ****************
  867. this._willChg(true);
  868. };
  869. /**
  870. * Set the progress step for this animation.
  871. * progressStep() is not debounced, so it should not be called faster than 60FPS.
  872. */
  873. Animation.prototype.progressStep = function (stepValue) {
  874. // only update if the last update was more than 16ms ago
  875. stepValue = Math.min(1, Math.max(0, stepValue));
  876. var children = this._c;
  877. for (var i = 0; i < this._cL; i++) {
  878. // ******** DOM WRITE ****************
  879. children[i].progressStep(stepValue);
  880. }
  881. if (this._rv) {
  882. // if the animation is going in reverse then
  883. // flip the step value: 0 becomes 1, 1 becomes 0
  884. stepValue = ((stepValue * -1) + 1);
  885. }
  886. // ******** DOM WRITE ****************
  887. this._progress(stepValue);
  888. };
  889. /**
  890. * End the progress animation.
  891. */
  892. Animation.prototype.progressEnd = function (shouldComplete, currentStepValue, dur) {
  893. if (dur === void 0) { dur = -1; }
  894. (void 0) /* console.debug */;
  895. if (this._rv) {
  896. // if the animation is going in reverse then
  897. // flip the step value: 0 becomes 1, 1 becomes 0
  898. currentStepValue = ((currentStepValue * -1) + 1);
  899. }
  900. var stepValue = shouldComplete ? 1 : 0;
  901. var diff = Math.abs(currentStepValue - stepValue);
  902. if (diff < 0.05) {
  903. dur = 0;
  904. }
  905. else if (dur < 0) {
  906. dur = this._dur;
  907. }
  908. this._isAsync = (dur > 30);
  909. this._progressEnd(shouldComplete, stepValue, dur, this._isAsync);
  910. if (this._isAsync) {
  911. // for the root animation only
  912. // set the async TRANSITION END event
  913. // and run onFinishes when the transition ends
  914. // ******** DOM WRITE ****************
  915. this._asyncEnd(dur, shouldComplete);
  916. // this animation has a duration so we need another RAF
  917. // for the CSS TRANSITION properties to kick in
  918. this.plt && this.plt.raf(this._playToStep.bind(this, stepValue));
  919. }
  920. };
  921. /**
  922. * @hidden
  923. * DOM WRITE
  924. * RECURSION
  925. */
  926. Animation.prototype._progressEnd = function (shouldComplete, stepValue, dur, isAsync) {
  927. var children = this._c;
  928. for (var i = 0; i < this._cL; i++) {
  929. // ******** DOM WRITE ****************
  930. children[i]._progressEnd(shouldComplete, stepValue, dur, isAsync);
  931. }
  932. if (!isAsync) {
  933. // stop immediately
  934. // set all the animations to their final position
  935. // ******** DOM WRITE ****************
  936. this._progress(stepValue);
  937. this._willChg(false);
  938. this._setAfterStyles();
  939. this._didFinish(shouldComplete);
  940. }
  941. else {
  942. // animate it back to it's ending position
  943. this.isPlaying = true;
  944. this.hasCompleted = false;
  945. this._hasDur = true;
  946. // ******** DOM WRITE ****************
  947. this._willChg(true);
  948. this._setTrans(dur, false);
  949. }
  950. };
  951. /**
  952. * Add a callback to fire when the animation has finished.
  953. */
  954. Animation.prototype.onFinish = function (callback, onceTimeCallback, clearOnFinishCallacks) {
  955. if (onceTimeCallback === void 0) { onceTimeCallback = false; }
  956. if (clearOnFinishCallacks === void 0) { clearOnFinishCallacks = false; }
  957. if (clearOnFinishCallacks) {
  958. this._fFn = this._fOneFn = undefined;
  959. }
  960. if (onceTimeCallback) {
  961. this._fOneFn = this._fOneFn || [];
  962. this._fOneFn.push(callback);
  963. }
  964. else {
  965. this._fFn = this._fFn || [];
  966. this._fFn.push(callback);
  967. }
  968. return this;
  969. };
  970. /**
  971. * @hidden
  972. * NO DOM
  973. * RECURSION
  974. */
  975. Animation.prototype._didFinishAll = function (hasCompleted, finishAsyncAnimations, finishNoDurationAnimations) {
  976. var children = this._c;
  977. for (var i = 0; i < this._cL; i++) {
  978. children[i]._didFinishAll(hasCompleted, finishAsyncAnimations, finishNoDurationAnimations);
  979. }
  980. if (finishAsyncAnimations && this._isAsync || finishNoDurationAnimations && !this._isAsync) {
  981. this._didFinish(hasCompleted);
  982. }
  983. };
  984. /**
  985. * @hidden
  986. * NO RECURSION
  987. */
  988. Animation.prototype._didFinish = function (hasCompleted) {
  989. this.isPlaying = false;
  990. this.hasCompleted = hasCompleted;
  991. if (this._fFn) {
  992. // run all finish callbacks
  993. for (var i = 0; i < this._fFn.length; i++) {
  994. this._fFn[i](this);
  995. }
  996. }
  997. if (this._fOneFn) {
  998. // run all "onetime" finish callbacks
  999. for (var i = 0; i < this._fOneFn.length; i++) {
  1000. this._fOneFn[i](this);
  1001. }
  1002. this._fOneFn.length = 0;
  1003. }
  1004. };
  1005. /**
  1006. * Reverse the animation.
  1007. */
  1008. Animation.prototype.reverse = function (shouldReverse) {
  1009. if (shouldReverse === void 0) { shouldReverse = true; }
  1010. var children = this._c;
  1011. for (var i = 0; i < this._cL; i++) {
  1012. children[i].reverse(shouldReverse);
  1013. }
  1014. this._rv = shouldReverse;
  1015. return this;
  1016. };
  1017. /**
  1018. * Recursively destroy this animation and all child animations.
  1019. */
  1020. Animation.prototype.destroy = function () {
  1021. var children = this._c;
  1022. for (var i = 0; i < this._cL; i++) {
  1023. children[i].destroy();
  1024. }
  1025. this._clearAsync();
  1026. this.parent = this.plt = this._e = this._rdFn = this._wrFn = null;
  1027. if (this._c) {
  1028. this._c.length = this._cL = 0;
  1029. }
  1030. if (this._fFn) {
  1031. this._fFn.length = 0;
  1032. }
  1033. if (this._fOneFn) {
  1034. this._fOneFn.length = 0;
  1035. }
  1036. };
  1037. /**
  1038. * @hidden
  1039. * NO DOM
  1040. */
  1041. Animation.prototype._transEl = function () {
  1042. // get the lowest level element that has an Animation
  1043. var targetEl;
  1044. for (var i = 0; i < this._cL; i++) {
  1045. targetEl = this._c[i]._transEl();
  1046. if (targetEl) {
  1047. return targetEl;
  1048. }
  1049. }
  1050. return (this._twn && this._hasDur && this._eL ? this._e[0] : null);
  1051. };
  1052. return Animation;
  1053. }());
  1054. export { Animation };
  1055. var ANIMATION_TRANSFORMS = {
  1056. 'translateX': 1,
  1057. 'translateY': 1,
  1058. 'translateZ': 1,
  1059. 'scale': 1,
  1060. 'scaleX': 1,
  1061. 'scaleY': 1,
  1062. 'scaleZ': 1,
  1063. 'rotate': 1,
  1064. 'rotateX': 1,
  1065. 'rotateY': 1,
  1066. 'rotateZ': 1,
  1067. 'skewX': 1,
  1068. 'skewY': 1,
  1069. 'perspective': 1
  1070. };
  1071. var ANIMATION_CSS_VALUE_REGEX = /(^-?\d*\.?\d*)(.*)/;
  1072. var ANIMATION_DURATION_MIN = 32;
  1073. var ANIMATION_TRANSITION_END_FALLBACK_PADDING_MS = 400;
  1074. //# sourceMappingURL=animation.js.map