/**
* @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;
}
});