PageRenderTime 64ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/nicholas_moore/sencha-test/sdk/src/fx/runner/CssTransition.js

https://bitbucket.org/mtldigitalservicesgroup/developer-playground
JavaScript | 409 lines | 315 code | 90 blank | 4 comment | 59 complexity | 3917b42d00a192ecb1e6a7eda41021a3 MD5 | raw file
  1. /**
  2. * @author Jacky Nguyen <jacky@sencha.com>
  3. * @private
  4. */
  5. Ext.define('Ext.fx.runner.CssTransition', {
  6. extend: 'Ext.fx.runner.Css',
  7. listenersAttached: false,
  8. constructor: function() {
  9. this.runningAnimationsData = {};
  10. return this.callParent(arguments);
  11. },
  12. attachListeners: function() {
  13. this.listenersAttached = true;
  14. this.getEventDispatcher().addListener('element', '*', 'transitionend', 'onTransitionEnd', this);
  15. },
  16. onTransitionEnd: function(e) {
  17. var target = e.target,
  18. id = target.id;
  19. if (id && this.runningAnimationsData.hasOwnProperty(id)) {
  20. this.refreshRunningAnimationsData(Ext.get(target), [e.browserEvent.propertyName]);
  21. }
  22. },
  23. onAnimationEnd: function(element, data, animation, isInterrupted, isReplaced) {
  24. var id = element.getId(),
  25. runningData = this.runningAnimationsData[id],
  26. endRules = {},
  27. endData = {},
  28. runningNameMap, toPropertyNames, i, ln, name;
  29. animation.un('stop', 'onAnimationStop', this);
  30. if (runningData) {
  31. runningNameMap = runningData.nameMap;
  32. }
  33. endRules[id] = endData;
  34. if (data.onBeforeEnd) {
  35. data.onBeforeEnd.call(data.scope || this, element, isInterrupted);
  36. }
  37. animation.fireEvent('animationbeforeend', animation, element, isInterrupted);
  38. this.fireEvent('animationbeforeend', this, animation, element, isInterrupted);
  39. if (isReplaced || (!isInterrupted && !data.preserveEndState)) {
  40. toPropertyNames = data.toPropertyNames;
  41. for (i = 0,ln = toPropertyNames.length; i < ln; i++) {
  42. name = toPropertyNames[i];
  43. if (runningNameMap && !runningNameMap.hasOwnProperty(name)) {
  44. endData[name] = null;
  45. }
  46. }
  47. }
  48. if (data.after) {
  49. Ext.merge(endData, data.after);
  50. }
  51. this.applyStyles(endRules);
  52. if (data.onEnd) {
  53. data.onEnd.call(data.scope || this, element, isInterrupted);
  54. }
  55. animation.fireEvent('animationend', animation, element, isInterrupted);
  56. this.fireEvent('animationend', this, animation, element, isInterrupted);
  57. },
  58. onAllAnimationsEnd: function(element) {
  59. var id = element.getId(),
  60. endRules = {};
  61. delete this.runningAnimationsData[id];
  62. endRules[id] = {
  63. 'transition-property': null,
  64. 'transition-duration': null,
  65. 'transition-timing-function': null,
  66. 'transition-delay': null
  67. };
  68. this.applyStyles(endRules);
  69. this.fireEvent('animationallend', this, element);
  70. },
  71. hasRunningAnimations: function(element) {
  72. var id = element.getId(),
  73. runningAnimationsData = this.runningAnimationsData;
  74. return runningAnimationsData.hasOwnProperty(id) && runningAnimationsData[id].sessions.length > 0;
  75. },
  76. refreshRunningAnimationsData: function(element, propertyNames, interrupt, replace) {
  77. var id = element.getId(),
  78. runningAnimationsData = this.runningAnimationsData,
  79. runningData = runningAnimationsData[id];
  80. if (!runningData) {
  81. return;
  82. }
  83. var nameMap = runningData.nameMap,
  84. nameList = runningData.nameList,
  85. sessions = runningData.sessions,
  86. ln, j, subLn, name,
  87. i, session, map, list,
  88. hasCompletedSession = false;
  89. interrupt = Boolean(interrupt);
  90. replace = Boolean(replace);
  91. if (!sessions) {
  92. return this;
  93. }
  94. ln = sessions.length;
  95. if (ln === 0) {
  96. return this;
  97. }
  98. if (replace) {
  99. runningData.nameMap = {};
  100. nameList.length = 0;
  101. for (i = 0; i < ln; i++) {
  102. session = sessions[i];
  103. this.onAnimationEnd(element, session.data, session.animation, interrupt, replace);
  104. }
  105. sessions.length = 0;
  106. }
  107. else {
  108. for (i = 0; i < ln; i++) {
  109. session = sessions[i];
  110. map = session.map;
  111. list = session.list;
  112. for (j = 0,subLn = propertyNames.length; j < subLn; j++) {
  113. name = propertyNames[j];
  114. if (map[name]) {
  115. delete map[name];
  116. Ext.Array.remove(list, name);
  117. session.length--;
  118. if (--nameMap[name] == 0) {
  119. delete nameMap[name];
  120. Ext.Array.remove(nameList, name);
  121. }
  122. }
  123. }
  124. if (session.length == 0) {
  125. sessions.splice(i, 1);
  126. i--;
  127. ln--;
  128. hasCompletedSession = true;
  129. this.onAnimationEnd(element, session.data, session.animation, interrupt);
  130. }
  131. }
  132. }
  133. if (!replace && !interrupt && sessions.length == 0 && hasCompletedSession) {
  134. this.onAllAnimationsEnd(element);
  135. }
  136. },
  137. getRunningData: function(id) {
  138. var runningAnimationsData = this.runningAnimationsData;
  139. if (!runningAnimationsData.hasOwnProperty(id)) {
  140. runningAnimationsData[id] = {
  141. nameMap: {},
  142. nameList: [],
  143. sessions: []
  144. };
  145. }
  146. return runningAnimationsData[id];
  147. },
  148. getTestElement: function() {
  149. var testElement = this.testElement,
  150. iframe, iframeDocument, iframeStyle;
  151. if (!testElement) {
  152. iframe = document.createElement('iframe');
  153. iframeStyle = iframe.style;
  154. iframeStyle.setProperty('visibility', 'hidden', 'important');
  155. iframeStyle.setProperty('width', '0px', 'important');
  156. iframeStyle.setProperty('height', '0px', 'important');
  157. iframeStyle.setProperty('position', 'absolute', 'important');
  158. iframeStyle.setProperty('border', '0px', 'important');
  159. iframeStyle.setProperty('zIndex', '-1000', 'important');
  160. document.body.appendChild(iframe);
  161. iframeDocument = iframe.contentDocument;
  162. iframeDocument.open();
  163. iframeDocument.writeln('</body>');
  164. iframeDocument.close();
  165. this.testElement = testElement = iframeDocument.createElement('div');
  166. testElement.style.setProperty('position', 'absolute', '!important');
  167. iframeDocument.body.appendChild(testElement);
  168. this.testElementComputedStyle = window.getComputedStyle(testElement);
  169. }
  170. return testElement;
  171. },
  172. getCssStyleValue: function(name, value) {
  173. var testElement = this.getTestElement(),
  174. computedStyle = this.testElementComputedStyle,
  175. style = testElement.style;
  176. style.setProperty(name, value);
  177. value = computedStyle.getPropertyValue(name);
  178. style.removeProperty(name);
  179. return value;
  180. },
  181. run: function(animations) {
  182. var me = this,
  183. isLengthPropertyMap = this.lengthProperties,
  184. fromData = {},
  185. toData = {},
  186. data = {},
  187. element, elementId, from, to, before,
  188. fromPropertyNames, toPropertyNames,
  189. doApplyTo, message,
  190. runningData,
  191. i, j, ln, animation, propertiesLength, sessionNameMap,
  192. computedStyle, formattedName, name, toFormattedValue,
  193. computedValue, fromFormattedValue, isLengthProperty,
  194. runningNameMap, runningNameList, runningSessions, runningSession;
  195. if (!this.listenersAttached) {
  196. this.attachListeners();
  197. }
  198. animations = Ext.Array.from(animations);
  199. for (i = 0,ln = animations.length; i < ln; i++) {
  200. animation = animations[i];
  201. animation = Ext.factory(animation, Ext.fx.Animation);
  202. element = animation.getElement();
  203. computedStyle = window.getComputedStyle(element.dom);
  204. elementId = element.getId();
  205. data = Ext.merge({}, animation.getData());
  206. if (animation.onBeforeStart) {
  207. animation.onBeforeStart.call(animation.scope || this, element);
  208. }
  209. animation.fireEvent('animationstart', animation);
  210. this.fireEvent('animationstart', this, animation);
  211. data[elementId] = data;
  212. before = data.before;
  213. from = data.from;
  214. to = data.to;
  215. data.fromPropertyNames = fromPropertyNames = [];
  216. data.toPropertyNames = toPropertyNames = [];
  217. for (name in to) {
  218. if (to.hasOwnProperty(name)) {
  219. to[name] = toFormattedValue = this.formatValue(to[name], name);
  220. formattedName = this.formatName(name);
  221. isLengthProperty = isLengthPropertyMap.hasOwnProperty(name);
  222. if (!isLengthProperty) {
  223. toFormattedValue = this.getCssStyleValue(formattedName, toFormattedValue);
  224. }
  225. if (from.hasOwnProperty(name)) {
  226. from[name] = fromFormattedValue = this.formatValue(from[name], name);
  227. if (!isLengthProperty) {
  228. fromFormattedValue = this.getCssStyleValue(formattedName, fromFormattedValue);
  229. }
  230. if (toFormattedValue !== fromFormattedValue) {
  231. fromPropertyNames.push(formattedName);
  232. toPropertyNames.push(formattedName);
  233. }
  234. }
  235. else {
  236. computedValue = computedStyle.getPropertyValue(formattedName);
  237. if (toFormattedValue !== computedValue) {
  238. toPropertyNames.push(formattedName);
  239. }
  240. }
  241. }
  242. }
  243. propertiesLength = toPropertyNames.length;
  244. if (propertiesLength === 0) {
  245. this.onAnimationEnd(element, data, animation);
  246. continue;
  247. }
  248. runningData = this.getRunningData(elementId);
  249. runningSessions = runningData.sessions;
  250. if (runningSessions.length > 0) {
  251. this.refreshRunningAnimationsData(
  252. element, Ext.Array.merge(fromPropertyNames, toPropertyNames), true, data.replacePrevious
  253. );
  254. }
  255. runningNameMap = runningData.nameMap;
  256. runningNameList = runningData.nameList;
  257. sessionNameMap = {};
  258. for (j = 0; j < propertiesLength; j++) {
  259. name = toPropertyNames[j];
  260. sessionNameMap[name] = true;
  261. if (!runningNameMap.hasOwnProperty(name)) {
  262. runningNameMap[name] = 1;
  263. runningNameList.push(name);
  264. }
  265. else {
  266. runningNameMap[name]++;
  267. }
  268. }
  269. runningSession = {
  270. element: element,
  271. map: sessionNameMap,
  272. list: toPropertyNames.slice(),
  273. length: propertiesLength,
  274. data: data,
  275. animation: animation
  276. };
  277. runningSessions.push(runningSession);
  278. animation.on('stop', 'onAnimationStop', this);
  279. fromData[elementId] = from = Ext.apply(Ext.Object.chain(before), from);
  280. if (runningNameList.length > 0) {
  281. fromPropertyNames = Ext.Array.difference(runningNameList, fromPropertyNames);
  282. toPropertyNames = Ext.Array.merge(fromPropertyNames, toPropertyNames);
  283. from['transition-property'] = fromPropertyNames;
  284. }
  285. toData[elementId] = to = Ext.Object.chain(to);
  286. to['transition-property'] = toPropertyNames;
  287. to['transition-duration'] = data.duration;
  288. to['transition-timing-function'] = data.easing;
  289. to['transition-delay'] = data.delay;
  290. animation.startTime = Date.now();
  291. }
  292. message = this.$className;
  293. this.applyStyles(fromData);
  294. doApplyTo = function(e) {
  295. if (e.data === message && e.source === window) {
  296. window.removeEventListener('message', doApplyTo, false);
  297. me.applyStyles(toData);
  298. }
  299. };
  300. window.addEventListener('message', doApplyTo, false);
  301. window.postMessage(message, '*');
  302. },
  303. onAnimationStop: function(animation) {
  304. var runningAnimationsData = this.runningAnimationsData,
  305. id, runningData, sessions, i, ln, session;
  306. for (id in runningAnimationsData) {
  307. if (runningAnimationsData.hasOwnProperty(id)) {
  308. runningData = runningAnimationsData[id];
  309. sessions = runningData.sessions;
  310. for (i = 0,ln = sessions.length; i < ln; i++) {
  311. session = sessions[i];
  312. if (session.animation === animation) {
  313. this.refreshRunningAnimationsData(session.element, session.list.slice(), true);
  314. }
  315. }
  316. }
  317. }
  318. }
  319. });