/** * @author Jacky Nguyen <jacky@sencha.com> * @private */ Ext.define('Ext.fx.runner.CssAnimation', { extend: 'Ext.fx.runner.Css', constructor: function() { this.runningAnimationsMap = {}; this.elementEndStates = {}; this.animationElementMap = {}; this.keyframesRulesCache = {}; this.uniqueId = 0; return this.callParent(arguments); }, attachListeners: function() { var eventDispatcher = this.getEventDispatcher(); this.listenersAttached = true; eventDispatcher.addListener('element', '*', 'animationstart', 'onAnimationStart', this); eventDispatcher.addListener('element', '*', 'animationend', 'onAnimationEnd', this); }, onAnimationStart: function(e) { var name = e.browserEvent.animationName, elementId = this.animationElementMap[name], animation = this.runningAnimationsMap[elementId][name], elementEndStates = this.elementEndStates, elementEndState = elementEndStates[elementId], data = {}; console.log("START============= " + name); if (elementEndState) { delete elementEndStates[elementId]; data[elementId] = elementEndState; this.applyStyles(data); } if (animation.before) { data[elementId] = animation.before; this.applyStyles(data); } }, onAnimationEnd: function(e) { var element = e.target, name = e.browserEvent.animationName, animationElementMap = this.animationElementMap, elementId = animationElementMap[name], runningAnimationsMap = this.runningAnimationsMap, runningAnimations = runningAnimationsMap[elementId], animation = runningAnimations[name]; console.log("END============= " + name); if (animation.onBeforeEnd) { animation.onBeforeEnd.call(animation.scope || this, element); } if (animation.onEnd) { animation.onEnd.call(animation.scope || this, element); } delete animationElementMap[name]; delete runningAnimations[name]; this.removeKeyframesRule(name); }, generateAnimationId: function() { return 'animation-' + (++this.uniqueId); }, run: function(animations) { var data = {}, elementEndStates = this.elementEndStates, animationElementMap = this.animationElementMap, runningAnimationsMap = this.runningAnimationsMap, runningAnimations, states, elementId, animationId, i, ln, animation, name, runningAnimation, names, durations, easings, delays, directions, iterations; if (!this.listenersAttached) { this.attachListeners(); } animations = Ext.Array.from(animations); for (i = 0,ln = animations.length; i < ln; i++) { animation = animations[i]; animation = Ext.factory(animation, Ext.fx.Animation); elementId = animation.getElement().getId(); animationId = animation.getName() || this.generateAnimationId(); animationElementMap[animationId] = elementId; animation = animation.getData(); states = animation.states; this.addKeyframesRule(animationId, states); runningAnimations = runningAnimationsMap[elementId]; if (!runningAnimations) { runningAnimations = runningAnimationsMap[elementId] = {}; } runningAnimations[animationId] = animation; names = []; durations = []; easings = []; delays = []; directions = []; iterations = []; for (name in runningAnimations) { if (runningAnimations.hasOwnProperty(name)) { runningAnimation = runningAnimations[name]; names.push(name); durations.push(runningAnimation.duration); easings.push(runningAnimation.easing); delays.push(runningAnimation.delay); directions.push(runningAnimation.direction); iterations.push(runningAnimation.iteration); } } data[elementId] = { 'animation-name' : names, 'animation-duration' : durations, 'animation-timing-function' : easings, 'animation-delay' : delays, 'animation-direction' : directions, 'animation-iteration-count' : iterations }; // Ext.apply(data[elementId], animation.origin); if (animation.preserveEndState) { elementEndStates[elementId] = states['100%']; } } this.applyStyles(data); }, addKeyframesRule: function(name, keyframes) { var percentage, properties, keyframesRule, styleSheet, rules, styles, rulesLength, key, value; styleSheet = this.getStyleSheet(); rules = styleSheet.cssRules; rulesLength = rules.length; styleSheet.insertRule('@' + this.vendorPrefix + 'keyframes ' + name + '{}', rulesLength); keyframesRule = rules[rulesLength]; for (percentage in keyframes) { properties = keyframes[percentage]; rules = keyframesRule.cssRules; rulesLength = rules.length; styles = []; for (key in properties) { value = this.formatValue(properties[key], key); key = this.formatName(key); styles.push(key + ':' + value); } keyframesRule.insertRule(percentage + '{' + styles.join(';') + '}', rulesLength); } return this; }, removeKeyframesRule: function(name) { var styleSheet = this.getStyleSheet(), rules = styleSheet.cssRules, i, ln, rule; for (i = 0,ln = rules.length; i < ln; i++) { rule = rules[i]; if (rule.name === name) { styleSheet.removeRule(i); break; } } return this; } });