fx.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. /**
  2. * DevExtreme (animation/fx.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. function _typeof(obj) {
  11. "@babel/helpers - typeof";
  12. return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
  13. return typeof obj
  14. } : function(obj) {
  15. return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj
  16. }, _typeof(obj)
  17. }
  18. var $ = require("../core/renderer");
  19. var window = require("../core/utils/window").getWindow();
  20. var eventsEngine = require("../events/core/events_engine");
  21. var errors = require("../core/errors");
  22. var getPublicElement = require("../core/utils/dom").getPublicElement;
  23. var extend = require("../core/utils/extend").extend;
  24. var typeUtils = require("../core/utils/type");
  25. var iteratorUtils = require("../core/utils/iterator");
  26. var translator = require("./translator");
  27. var easing = require("./easing");
  28. var animationFrame = require("./frame");
  29. var support = require("../core/utils/support");
  30. var positionUtils = require("./position");
  31. var removeEvent = require("../core/remove_event");
  32. var eventUtils = require("../events/utils");
  33. var deferredUtils = require("../core/utils/deferred");
  34. var when = deferredUtils.when;
  35. var Deferred = deferredUtils.Deferred;
  36. var removeEventName = eventUtils.addNamespace(removeEvent, "dxFX");
  37. var isFunction = typeUtils.isFunction;
  38. var isPlainObject = typeUtils.isPlainObject;
  39. var noop = require("../core/utils/common").noop;
  40. var RELATIVE_VALUE_REGEX = /^([+-])=(.*)/i;
  41. var ANIM_DATA_KEY = "dxAnimData";
  42. var ANIM_QUEUE_KEY = "dxAnimQueue";
  43. var TRANSFORM_PROP = "transform";
  44. var TransitionAnimationStrategy = {
  45. initAnimation: function($element, config) {
  46. $element.css({
  47. transitionProperty: "none"
  48. });
  49. if ("string" === typeof config.from) {
  50. $element.addClass(config.from)
  51. } else {
  52. setProps($element, config.from)
  53. }
  54. var that = this;
  55. var deferred = new Deferred;
  56. var cleanupWhen = config.cleanupWhen;
  57. config.transitionAnimation = {
  58. deferred: deferred,
  59. finish: function() {
  60. that._finishTransition($element);
  61. if (cleanupWhen) {
  62. when(deferred, cleanupWhen).always(function() {
  63. that._cleanup($element, config)
  64. })
  65. } else {
  66. that._cleanup($element, config)
  67. }
  68. deferred.resolveWith($element, [config, $element])
  69. }
  70. };
  71. this._completeAnimationCallback($element, config).done(function() {
  72. config.transitionAnimation.finish()
  73. }).fail(function() {
  74. deferred.rejectWith($element, [config, $element])
  75. });
  76. if (!config.duration) {
  77. config.transitionAnimation.finish()
  78. }
  79. $element.css("transform")
  80. },
  81. animate: function($element, config) {
  82. this._startAnimation($element, config);
  83. return config.transitionAnimation.deferred.promise()
  84. },
  85. _completeAnimationCallback: function($element, config) {
  86. var that = this;
  87. var startTime = Date.now() + config.delay;
  88. var deferred = new Deferred;
  89. var transitionEndFired = new Deferred;
  90. var simulatedTransitionEndFired = new Deferred;
  91. var simulatedEndEventTimer;
  92. var transitionEndEventName = support.transitionEndEventName() + ".dxFX";
  93. config.transitionAnimation.cleanup = function() {
  94. clearTimeout(simulatedEndEventTimer);
  95. clearTimeout(waitForJSCompleteTimer);
  96. eventsEngine.off($element, transitionEndEventName);
  97. eventsEngine.off($element, removeEventName)
  98. };
  99. eventsEngine.one($element, transitionEndEventName, function() {
  100. if (Date.now() - startTime >= config.duration) {
  101. transitionEndFired.reject()
  102. }
  103. });
  104. eventsEngine.off($element, removeEventName);
  105. eventsEngine.on($element, removeEventName, function() {
  106. that.stop($element, config);
  107. deferred.reject()
  108. });
  109. var waitForJSCompleteTimer = setTimeout(function() {
  110. simulatedEndEventTimer = setTimeout(function() {
  111. simulatedTransitionEndFired.reject()
  112. }, config.duration + config.delay + fx._simulatedTransitionEndDelay);
  113. when(transitionEndFired, simulatedTransitionEndFired).fail(function() {
  114. deferred.resolve()
  115. }.bind(this))
  116. });
  117. return deferred.promise()
  118. },
  119. _startAnimation: function($element, config) {
  120. $element.css({
  121. transitionProperty: "all",
  122. transitionDelay: config.delay + "ms",
  123. transitionDuration: config.duration + "ms",
  124. transitionTimingFunction: config.easing
  125. });
  126. if ("string" === typeof config.to) {
  127. $element[0].className += " " + config.to
  128. } else {
  129. if (config.to) {
  130. setProps($element, config.to)
  131. }
  132. }
  133. },
  134. _finishTransition: function($element) {
  135. $element.css("transition", "none")
  136. },
  137. _cleanup: function($element, config) {
  138. config.transitionAnimation.cleanup();
  139. if ("string" === typeof config.from) {
  140. $element.removeClass(config.from);
  141. $element.removeClass(config.to)
  142. }
  143. },
  144. stop: function($element, config, jumpToEnd) {
  145. if (!config) {
  146. return
  147. }
  148. if (jumpToEnd) {
  149. config.transitionAnimation.finish()
  150. } else {
  151. if (isPlainObject(config.to)) {
  152. iteratorUtils.each(config.to, function(key) {
  153. $element.css(key, $element.css(key))
  154. })
  155. }
  156. this._finishTransition($element);
  157. this._cleanup($element, config)
  158. }
  159. }
  160. };
  161. var FrameAnimationStrategy = {
  162. initAnimation: function($element, config) {
  163. setProps($element, config.from)
  164. },
  165. animate: function($element, config) {
  166. var deferred = new Deferred;
  167. var that = this;
  168. if (!config) {
  169. return deferred.reject().promise()
  170. }
  171. iteratorUtils.each(config.to, function(prop) {
  172. if (void 0 === config.from[prop]) {
  173. config.from[prop] = that._normalizeValue($element.css(prop))
  174. }
  175. });
  176. if (config.to[TRANSFORM_PROP]) {
  177. config.from[TRANSFORM_PROP] = that._parseTransform(config.from[TRANSFORM_PROP]);
  178. config.to[TRANSFORM_PROP] = that._parseTransform(config.to[TRANSFORM_PROP])
  179. }
  180. config.frameAnimation = {
  181. to: config.to,
  182. from: config.from,
  183. currentValue: config.from,
  184. easing: easing.convertTransitionTimingFuncToEasing(config.easing),
  185. duration: config.duration,
  186. startTime: (new Date).valueOf(),
  187. finish: function() {
  188. this.currentValue = this.to;
  189. this.draw();
  190. animationFrame.cancelAnimationFrame(config.frameAnimation.animationFrameId);
  191. deferred.resolve()
  192. },
  193. draw: function() {
  194. if (config.draw) {
  195. config.draw(this.currentValue);
  196. return
  197. }
  198. var currentValue = extend({}, this.currentValue);
  199. if (currentValue[TRANSFORM_PROP]) {
  200. currentValue[TRANSFORM_PROP] = iteratorUtils.map(currentValue[TRANSFORM_PROP], function(value, prop) {
  201. if ("translate" === prop) {
  202. return translator.getTranslateCss(value)
  203. } else {
  204. if ("scale" === prop) {
  205. return "scale(" + value + ")"
  206. } else {
  207. if ("rotate" === prop.substr(0, prop.length - 1)) {
  208. return prop + "(" + value + "deg)"
  209. }
  210. }
  211. }
  212. }).join(" ")
  213. }
  214. $element.css(currentValue)
  215. }
  216. };
  217. if (config.delay) {
  218. config.frameAnimation.startTime += config.delay;
  219. config.frameAnimation.delayTimeout = setTimeout(function() {
  220. that._startAnimation($element, config)
  221. }, config.delay)
  222. } else {
  223. that._startAnimation($element, config)
  224. }
  225. return deferred.promise()
  226. },
  227. _startAnimation: function($element, config) {
  228. eventsEngine.off($element, removeEventName);
  229. eventsEngine.on($element, removeEventName, function() {
  230. if (config.frameAnimation) {
  231. animationFrame.cancelAnimationFrame(config.frameAnimation.animationFrameId)
  232. }
  233. });
  234. this._animationStep($element, config)
  235. },
  236. _parseTransform: function(transformString) {
  237. var result = {};
  238. iteratorUtils.each(transformString.match(/\w+\d*\w*\([^)]*\)\s*/g), function(i, part) {
  239. var translateData = translator.parseTranslate(part);
  240. var scaleData = part.match(/scale\((.+?)\)/);
  241. var rotateData = part.match(/(rotate.)\((.+)deg\)/);
  242. if (translateData) {
  243. result.translate = translateData
  244. }
  245. if (scaleData && scaleData[1]) {
  246. result.scale = parseFloat(scaleData[1])
  247. }
  248. if (rotateData && rotateData[1]) {
  249. result[rotateData[1]] = parseFloat(rotateData[2])
  250. }
  251. });
  252. return result
  253. },
  254. stop: function($element, config, jumpToEnd) {
  255. var frameAnimation = config && config.frameAnimation;
  256. if (!frameAnimation) {
  257. return
  258. }
  259. animationFrame.cancelAnimationFrame(frameAnimation.animationFrameId);
  260. clearTimeout(frameAnimation.delayTimeout);
  261. if (jumpToEnd) {
  262. frameAnimation.finish()
  263. }
  264. delete config.frameAnimation
  265. },
  266. _animationStep: function($element, config) {
  267. var frameAnimation = config && config.frameAnimation;
  268. if (!frameAnimation) {
  269. return
  270. }
  271. var now = (new Date).valueOf();
  272. if (now >= frameAnimation.startTime + frameAnimation.duration) {
  273. frameAnimation.finish();
  274. return
  275. }
  276. frameAnimation.currentValue = this._calcStepValue(frameAnimation, now - frameAnimation.startTime);
  277. frameAnimation.draw();
  278. var that = this;
  279. frameAnimation.animationFrameId = animationFrame.requestAnimationFrame(function() {
  280. that._animationStep($element, config)
  281. })
  282. },
  283. _calcStepValue: function(frameAnimation, currentDuration) {
  284. var calcValueRecursively = function calcValueRecursively(from, to) {
  285. var result = Array.isArray(to) ? [] : {};
  286. var calcEasedValue = function(propName) {
  287. var x = currentDuration / frameAnimation.duration;
  288. var t = currentDuration;
  289. var b = 1 * from[propName];
  290. var c = to[propName] - from[propName];
  291. var d = frameAnimation.duration;
  292. return easing.getEasing(frameAnimation.easing)(x, t, b, c, d)
  293. };
  294. iteratorUtils.each(to, function(propName, endPropValue) {
  295. if ("string" === typeof endPropValue && false === parseFloat(endPropValue, 10)) {
  296. return true
  297. }
  298. result[propName] = "object" === _typeof(endPropValue) ? calcValueRecursively(from[propName], endPropValue) : calcEasedValue(propName)
  299. });
  300. return result
  301. };
  302. return calcValueRecursively(frameAnimation.from, frameAnimation.to)
  303. },
  304. _normalizeValue: function(value) {
  305. var numericValue = parseFloat(value, 10);
  306. if (false === numericValue) {
  307. return value
  308. }
  309. return numericValue
  310. }
  311. };
  312. var FallbackToNoAnimationStrategy = {
  313. initAnimation: function() {},
  314. animate: function() {
  315. return (new Deferred).resolve().promise()
  316. },
  317. stop: noop,
  318. isSynchronous: true
  319. };
  320. var getAnimationStrategy = function(config) {
  321. config = config || {};
  322. var animationStrategies = {
  323. transition: support.transition() ? TransitionAnimationStrategy : FrameAnimationStrategy,
  324. frame: FrameAnimationStrategy,
  325. noAnimation: FallbackToNoAnimationStrategy
  326. };
  327. var strategy = config.strategy || "transition";
  328. if ("css" === config.type && !support.transition()) {
  329. strategy = "noAnimation"
  330. }
  331. return animationStrategies[strategy]
  332. };
  333. var baseConfigValidator = function(config, animationType, validate, typeMessage) {
  334. iteratorUtils.each(["from", "to"], function() {
  335. if (!validate(config[this])) {
  336. throw errors.Error("E0010", animationType, this, typeMessage)
  337. }
  338. })
  339. };
  340. var isObjectConfigValidator = function(config, animationType) {
  341. return baseConfigValidator(config, animationType, function(target) {
  342. return isPlainObject(target)
  343. }, "a plain object")
  344. };
  345. var isStringConfigValidator = function(config, animationType) {
  346. return baseConfigValidator(config, animationType, function(target) {
  347. return "string" === typeof target
  348. }, "a string")
  349. };
  350. var CustomAnimationConfigurator = {
  351. setup: function() {}
  352. };
  353. var CssAnimationConfigurator = {
  354. validateConfig: function(config) {
  355. isStringConfigValidator(config, "css")
  356. },
  357. setup: function() {}
  358. };
  359. var positionAliases = {
  360. top: {
  361. my: "bottom center",
  362. at: "top center"
  363. },
  364. bottom: {
  365. my: "top center",
  366. at: "bottom center"
  367. },
  368. right: {
  369. my: "left center",
  370. at: "right center"
  371. },
  372. left: {
  373. my: "right center",
  374. at: "left center"
  375. }
  376. };
  377. var SlideAnimationConfigurator = {
  378. validateConfig: function(config) {
  379. isObjectConfigValidator(config, "slide")
  380. },
  381. setup: function($element, config) {
  382. var location = translator.locate($element);
  383. if ("slide" !== config.type) {
  384. var positioningConfig = "slideIn" === config.type ? config.from : config.to;
  385. positioningConfig.position = extend({
  386. of: window
  387. }, positionAliases[config.direction]);
  388. setupPosition($element, positioningConfig)
  389. }
  390. this._setUpConfig(location, config.from);
  391. this._setUpConfig(location, config.to);
  392. translator.clearCache($element)
  393. },
  394. _setUpConfig: function(location, config) {
  395. config.left = "left" in config ? config.left : "+=0";
  396. config.top = "top" in config ? config.top : "+=0";
  397. this._initNewPosition(location, config)
  398. },
  399. _initNewPosition: function(location, config) {
  400. var position = {
  401. left: config.left,
  402. top: config.top
  403. };
  404. delete config.left;
  405. delete config.top;
  406. var relativeValue = this._getRelativeValue(position.left);
  407. if (void 0 !== relativeValue) {
  408. position.left = relativeValue + location.left
  409. } else {
  410. config.left = 0
  411. }
  412. relativeValue = this._getRelativeValue(position.top);
  413. if (void 0 !== relativeValue) {
  414. position.top = relativeValue + location.top
  415. } else {
  416. config.top = 0
  417. }
  418. config[TRANSFORM_PROP] = translator.getTranslateCss({
  419. x: position.left,
  420. y: position.top
  421. })
  422. },
  423. _getRelativeValue: function(value) {
  424. var relativeValue;
  425. if ("string" === typeof value && (relativeValue = RELATIVE_VALUE_REGEX.exec(value))) {
  426. return parseInt(relativeValue[1] + "1") * relativeValue[2]
  427. }
  428. }
  429. };
  430. var FadeAnimationConfigurator = {
  431. setup: function($element, config) {
  432. var from = config.from;
  433. var fromOpacity = isPlainObject(from) ? config.skipElementInitialStyles ? 0 : $element.css("opacity") : String(from);
  434. var toOpacity;
  435. switch (config.type) {
  436. case "fadeIn":
  437. toOpacity = 1;
  438. break;
  439. case "fadeOut":
  440. toOpacity = 0;
  441. break;
  442. default:
  443. toOpacity = String(config.to)
  444. }
  445. config.from = {
  446. visibility: "visible",
  447. opacity: fromOpacity
  448. };
  449. config.to = {
  450. opacity: toOpacity
  451. }
  452. }
  453. };
  454. var PopAnimationConfigurator = {
  455. validateConfig: function(config) {
  456. isObjectConfigValidator(config, "pop")
  457. },
  458. setup: function($element, config) {
  459. var from = config.from;
  460. var to = config.to;
  461. var fromOpacity = "opacity" in from ? from.opacity : $element.css("opacity");
  462. var toOpacity = "opacity" in to ? to.opacity : 1;
  463. var fromScale = "scale" in from ? from.scale : 0;
  464. var toScale = "scale" in to ? to.scale : 1;
  465. config.from = {
  466. opacity: fromOpacity
  467. };
  468. var translate = translator.getTranslate($element);
  469. config.from[TRANSFORM_PROP] = this._getCssTransform(translate, fromScale);
  470. config.to = {
  471. opacity: toOpacity
  472. };
  473. config.to[TRANSFORM_PROP] = this._getCssTransform(translate, toScale)
  474. },
  475. _getCssTransform: function(translate, scale) {
  476. return translator.getTranslateCss(translate) + "scale(" + scale + ")"
  477. }
  478. };
  479. var animationConfigurators = {
  480. custom: CustomAnimationConfigurator,
  481. slide: SlideAnimationConfigurator,
  482. slideIn: SlideAnimationConfigurator,
  483. slideOut: SlideAnimationConfigurator,
  484. fade: FadeAnimationConfigurator,
  485. fadeIn: FadeAnimationConfigurator,
  486. fadeOut: FadeAnimationConfigurator,
  487. pop: PopAnimationConfigurator,
  488. css: CssAnimationConfigurator
  489. };
  490. var getAnimationConfigurator = function(config) {
  491. var result = animationConfigurators[config.type];
  492. if (!result) {
  493. throw errors.Error("E0011", config.type)
  494. }
  495. return result
  496. };
  497. var defaultJSConfig = {
  498. type: "custom",
  499. from: {},
  500. to: {},
  501. duration: 400,
  502. start: noop,
  503. complete: noop,
  504. easing: "ease",
  505. delay: 0
  506. };
  507. var defaultCssConfig = {
  508. duration: 400,
  509. easing: "ease",
  510. delay: 0
  511. };
  512. var setupAnimationOnElement = function() {
  513. var animation = this;
  514. var $element = animation.element;
  515. var config = animation.config;
  516. setupPosition($element, config.from);
  517. setupPosition($element, config.to);
  518. animation.configurator.setup($element, config);
  519. $element.data(ANIM_DATA_KEY, animation);
  520. if (fx.off) {
  521. config.duration = 0;
  522. config.delay = 0
  523. }
  524. animation.strategy.initAnimation($element, config);
  525. if (config.start) {
  526. var element = getPublicElement($element);
  527. config.start.apply(this, [element, config])
  528. }
  529. };
  530. var onElementAnimationComplete = function(animation) {
  531. var $element = animation.element;
  532. var config = animation.config;
  533. $element.removeData(ANIM_DATA_KEY);
  534. if (config.complete) {
  535. var element = getPublicElement($element);
  536. config.complete.apply(this, [element, config])
  537. }
  538. animation.deferred.resolveWith(this, [$element, config])
  539. };
  540. var startAnimationOnElement = function() {
  541. var animation = this;
  542. var $element = animation.element;
  543. var config = animation.config;
  544. animation.isStarted = true;
  545. return animation.strategy.animate($element, config).done(function() {
  546. onElementAnimationComplete(animation)
  547. }).fail(function() {
  548. animation.deferred.rejectWith(this, [$element, config])
  549. })
  550. };
  551. var stopAnimationOnElement = function(jumpToEnd) {
  552. var animation = this;
  553. var $element = animation.element;
  554. var config = animation.config;
  555. clearTimeout(animation.startTimeout);
  556. if (!animation.isStarted) {
  557. animation.start()
  558. }
  559. animation.strategy.stop($element, config, jumpToEnd)
  560. };
  561. var scopedRemoveEvent = eventUtils.addNamespace(removeEvent, "dxFXStartAnimation");
  562. var subscribeToRemoveEvent = function(animation) {
  563. eventsEngine.off(animation.element, scopedRemoveEvent);
  564. eventsEngine.on(animation.element, scopedRemoveEvent, function() {
  565. fx.stop(animation.element)
  566. });
  567. animation.deferred.always(function() {
  568. eventsEngine.off(animation.element, scopedRemoveEvent)
  569. })
  570. };
  571. var createAnimation = function(element, initialConfig) {
  572. var defaultConfig = "css" === initialConfig.type ? defaultCssConfig : defaultJSConfig;
  573. var config = extend(true, {}, defaultConfig, initialConfig);
  574. var configurator = getAnimationConfigurator(config);
  575. var strategy = getAnimationStrategy(config);
  576. var animation = {
  577. element: $(element),
  578. config: config,
  579. configurator: configurator,
  580. strategy: strategy,
  581. isSynchronous: strategy.isSynchronous,
  582. setup: setupAnimationOnElement,
  583. start: startAnimationOnElement,
  584. stop: stopAnimationOnElement,
  585. deferred: new Deferred
  586. };
  587. if (isFunction(configurator.validateConfig)) {
  588. configurator.validateConfig(config)
  589. }
  590. subscribeToRemoveEvent(animation);
  591. return animation
  592. };
  593. var animate = function(element, config) {
  594. var $element = $(element);
  595. if (!$element.length) {
  596. return (new Deferred).resolve().promise()
  597. }
  598. var animation = createAnimation($element, config);
  599. pushInAnimationQueue($element, animation);
  600. return animation.deferred.promise()
  601. };
  602. var pushInAnimationQueue = function($element, animation) {
  603. var queueData = getAnimQueueData($element);
  604. writeAnimQueueData($element, queueData);
  605. queueData.push(animation);
  606. if (!isAnimating($element)) {
  607. shiftFromAnimationQueue($element, queueData)
  608. }
  609. };
  610. var getAnimQueueData = function($element) {
  611. return $element.data(ANIM_QUEUE_KEY) || []
  612. };
  613. var writeAnimQueueData = function($element, queueData) {
  614. $element.data(ANIM_QUEUE_KEY, queueData)
  615. };
  616. var destroyAnimQueueData = function($element) {
  617. $element.removeData(ANIM_QUEUE_KEY)
  618. };
  619. var isAnimating = function($element) {
  620. return !!$element.data(ANIM_DATA_KEY)
  621. };
  622. var shiftFromAnimationQueue = function shiftFromAnimationQueue($element, queueData) {
  623. queueData = getAnimQueueData($element);
  624. if (!queueData.length) {
  625. return
  626. }
  627. var animation = queueData.shift();
  628. if (0 === queueData.length) {
  629. destroyAnimQueueData($element)
  630. }
  631. executeAnimation(animation).done(function() {
  632. if (!isAnimating($element)) {
  633. shiftFromAnimationQueue($element)
  634. }
  635. })
  636. };
  637. var executeAnimation = function(animation) {
  638. animation.setup();
  639. if (fx.off || animation.isSynchronous) {
  640. animation.start()
  641. } else {
  642. animation.startTimeout = setTimeout(function() {
  643. animation.start()
  644. })
  645. }
  646. return animation.deferred.promise()
  647. };
  648. var setupPosition = function($element, config) {
  649. if (!config || !config.position) {
  650. return
  651. }
  652. var win = $(window);
  653. var left = 0;
  654. var top = 0;
  655. var position = positionUtils.calculate($element, config.position);
  656. var offset = $element.offset();
  657. var currentPosition = $element.position();
  658. if (currentPosition.top > offset.top) {
  659. top = win.scrollTop()
  660. }
  661. if (currentPosition.left > offset.left) {
  662. left = win.scrollLeft()
  663. }
  664. extend(config, {
  665. left: position.h.location - offset.left + currentPosition.left - left,
  666. top: position.v.location - offset.top + currentPosition.top - top
  667. });
  668. delete config.position
  669. };
  670. var setProps = function($element, props) {
  671. iteratorUtils.each(props, function(key, value) {
  672. try {
  673. $element.css(key, typeUtils.isFunction(value) ? value() : value)
  674. } catch (e) {}
  675. })
  676. };
  677. var stop = function(element, jumpToEnd) {
  678. var $element = $(element);
  679. var queueData = getAnimQueueData($element);
  680. iteratorUtils.each(queueData, function(_, animation) {
  681. animation.config.delay = 0;
  682. animation.config.duration = 0;
  683. animation.isSynchronous = true
  684. });
  685. if (!isAnimating($element)) {
  686. shiftFromAnimationQueue($element, queueData)
  687. }
  688. var animation = $element.data(ANIM_DATA_KEY);
  689. if (animation) {
  690. animation.stop(jumpToEnd)
  691. }
  692. $element.removeData(ANIM_DATA_KEY);
  693. destroyAnimQueueData($element)
  694. };
  695. var fx = {
  696. off: false,
  697. animationTypes: animationConfigurators,
  698. animate: animate,
  699. createAnimation: createAnimation,
  700. isAnimating: isAnimating,
  701. stop: stop,
  702. _simulatedTransitionEndDelay: 100
  703. };
  704. module.exports = fx;
  705. module.exports.default = module.exports;