polardbxengine/storage/ndb/mcc/frontend/dojo/dojox/css3/transition.js.uncompressed.js

407 lines
11 KiB
JavaScript

define("dojox/css3/transition", ["dojo/_base/lang",
"dojo/_base/array",
"dojo/_base/Deferred",
"dojo/DeferredList",
"dojo/on",
"dojo/_base/sniff"],
function(lang, array, Deferred, DeferredList, on, has){
// module:
// dojox/css3/transition
//create cross platform animation/transition effects
//TODO enable opera mobile when it is hardware accelerated
//TODO enable IE when CSS3 transition is supported in IE 10
var transitionEndEventName = "transitionend";
var transitionPrefix = "t"; //by default use "t" prefix and "ransition" to make word "transition"
var translateMethodStart = "translate3d(";//Android 2.x does not support translateX in CSS Transition, we need to use translate3d in webkit browsers
var translateMethodEnd = ",0,0)";
if(has("webkit")){
transitionPrefix = "WebkitT";
transitionEndEventName = "webkitTransitionEnd";
}else if(has("mozilla")){
transitionPrefix = "MozT";
translateMethodStart = "translateX(";
translateMethodEnd = ")";
}
//TODO find a way to lock the animation and prevent animation conflict
//Use the simple object inheritance
var transition = function(/*Object?*/args){
// summary:
// This module defines the transition utilities which can be used
// to perform transition effects based on the CSS Transition standard.
// args:
// The arguments which will be mixed into this transition object.
//default config should be in animation object itself instead of its prototype
//otherwise, it might be easy for making mistake of modifying prototype
var defaultConfig = {
startState: {},
endState: {},
node: null,
duration: 250,
"in": true,
direction: 1,
autoClear: true
};
lang.mixin(this, defaultConfig);
lang.mixin(this, args);
//create the deferred object which will resolve after the animation is finished.
//We can rely on "onAfterEnd" function to notify the end of a single animation,
//but using a deferred object is easier to wait for multiple animations end.
if(!this.deferred){
this.deferred = new Deferred();
}
};
lang.extend(transition, {
play: function(){
// summary:
// Plays the transition effect defined by this transition object.
transition.groupedPlay([this]);
},
//method to apply the state of the transition
_applyState: function(state){
var style = this.node.style;
for(var property in state){
if(state.hasOwnProperty(property)){
style[property] = state[property];
}
}
},
initState: function(){
// summary:
// Method to initialize the state for a transition.
//apply the immediate style change for initial state.
this.node.style[transitionPrefix + "ransitionProperty"] = "none";
this.node.style[transitionPrefix + "ransitionDuration"] = "0ms";
this._applyState(this.startState);
},
_beforeStart: function(){
if (this.node.style.display === "none"){
this.node.style.display = "";
}
this.beforeStart();
},
_beforeClear: function(){
this.node.style[transitionPrefix + "ransitionProperty"] = null;
this.node.style[transitionPrefix + "ransitionDuration"] = null;
if(this["in"] !== true){
this.node.style.display = "none";
}
this.beforeClear();
},
_onAfterEnd: function(){
this.deferred.resolve(this.node);
if(this.node.id && transition.playing[this.node.id]===this.deferred){
delete transition.playing[this.node.id];
}
this.onAfterEnd();
},
beforeStart: function(){
// summary:
// The callback which will be called right before the start
// of the transition effect.
},
beforeClear: function(){
// summary:
// The callback which will be called right after the end
// of the transition effect and before the final state is
// cleared.
},
onAfterEnd: function(){
// summary:
// The callback which will be called right after the end
// of the transition effect and after the final state is
// cleared.
},
start: function(){
// summary:
// Method to start the transition.
this._beforeStart();
this._startTime = new Date().getTime(); // set transition start timestamp
this._cleared = false; // set clear flag to false
var self = this;
//change the transition duration
self.node.style[transitionPrefix + "ransitionProperty"] = "all";
self.node.style[transitionPrefix + "ransitionDuration"] = self.duration + "ms";
//connect to clear the transition state after the transition end.
//Since the transition is conducted asynchronously, we need to
//connect to transition end event to clear the state
on.once(self.node, transitionEndEventName, function(){
self.clear();
});
this._applyState(this.endState);
},
clear: function(){
// summary:
// Method to clear the state after a transition.
if(this._cleared) {
return;
}
this._cleared = true; // set clear flag to true
this._beforeClear();
this._removeState(this.endState);
// console.log(this.node.id + " clear.");
this._onAfterEnd();
},
//create removeState method
_removeState: function(state){
var style = this.node.style;
for(var property in state){
if(state.hasOwnProperty(property)){
style[property] = null;
}
}
}
});
//TODO add the lock mechanism for all of the transition effects
// consider using only one object for one type of transition.
transition.slide = function(node, config){
// summary:
// Method which is used to create the transition object of a slide effect.
// node:
// The node that the slide transition effect will be applied on.
// config:
// The cofig arguments which will be mixed into this transition object.
//create the return object and set the startState, endState of the return
var ret = new transition(config);
ret.node = node;
var startX = "0";
var endX = "0";
if(ret["in"]){
if(ret.direction === 1){
startX = "100%";
}else{
startX = "-100%";
}
}else{
if(ret.direction === 1){
endX = "-100%";
}else{
endX = "100%";
}
}
ret.startState[transitionPrefix + "ransform"]=translateMethodStart+startX+translateMethodEnd;
ret.endState[transitionPrefix + "ransform"]=translateMethodStart+endX+translateMethodEnd;
return ret;
};
transition.fade = function(node, config){
// summary:
// Method which is used to create the transition object of fade effect.
// node:
// The node that the fade transition effect will be applied on.
// config:
// The cofig arguments which will be mixed into this transition object.
var ret = new transition(config);
ret.node = node;
var startOpacity = "0";
var endOpacity = "0";
if(ret["in"]){
endOpacity = "1";
}else{
startOpacity = "1";
}
lang.mixin(ret, {
startState:{
"opacity": startOpacity
},
endState:{
"opacity": endOpacity
}
});
return ret;
};
transition.flip = function(node, config){
// summary:
// Method which is used to create the transition object of flip effect.
// node:
// The node that the flip transition effect will be applied on.
// config:
// The cofig arguments which will be mixed into this transition object.
var ret = new transition(config);
ret.node = node;
if(ret["in"]){
//Need to set opacity here because Android 2.2 has bug that
//scale(...) in transform does not persist status
lang.mixin(ret,{
startState:{
"opacity": "0"
},
endState:{
"opacity": "1"
}
});
ret.startState[transitionPrefix + "ransform"]="scale(0,0.8) skew(0,-30deg)";
ret.endState[transitionPrefix + "ransform"]="scale(1,1) skew(0,0)";
}else{
lang.mixin(ret,{
startState:{
"opacity": "1"
},
endState:{
"opacity": "0"
}
});
ret.startState[transitionPrefix + "ransform"]="scale(1,1) skew(0,0)";
ret.endState[transitionPrefix + "ransform"]="scale(0,0.8) skew(0,30deg)";
}
return ret;
};
var getWaitingList = function(/*Array*/ nodes){
var defs = [];
array.forEach(nodes, function(node){
//check whether the node is under other animation
if(node.id && transition.playing[node.id]){
//hook on deferred object in transition.playing
defs.push(transition.playing[node.id]);
}
});
return new DeferredList(defs);
};
transition.getWaitingList = getWaitingList;
transition.groupedPlay = function(/*Array*/args){
// summary:
// The method which groups multiple transitions and plays
// them together.
// args:
// The array of transition objects which will be played together.
var animNodes = array.filter(args, function(item){
return item.node;
});
var waitingList = getWaitingList(animNodes);
//update registry with deferred objects in animations of args.
array.forEach(args, function(item){
if(item.node.id){
transition.playing[item.node.id] = item.deferred;
}
});
//wait for all deferred object in deferred list to resolve
Deferred.when(waitingList, function(){
array.forEach(args, function(item){
//set the start state
item.initState();
});
//Assume the fps of the animation should be higher than 30 fps and
//allow the browser to use one frame's time to redraw so that
//the transition can be started
setTimeout(function(){
array.forEach(args, function(item){
item.start();
});
// check and clear node if the node not cleared.
// 1. on Android2.2/2.3, the "fade out" transitionEnd event will be lost if the soft keyboard popup, so we need to check nodes' clear status.
// 2. The "fade in" transitionEnd event will before or after "fade out" transitionEnd event and it always occurs.
// We can check fade out node status in the last "fade in" node transitionEnd event callback, if node transition timeout, we clear it.
// NOTE: the last "fade in" transitionEnd event will always fired, so we bind on this event and check other nodes.
on.once(args[args.length-1].node, transitionEndEventName, function(){
var timeout;
for(var i=0; i<args.length-1; i++){
if(args[i].deferred.fired !== 0){
timeout = new Date().getTime() - args[i]._startTime;
if(timeout >= args[i].duration){
args[i].clear();
}
}
}
});
}, 33);
});
};
transition.chainedPlay = function(/*Array*/args){
// summary:
// The method which plays multiple transitions one by one.
// args:
// The array of transition objects which will be played in a chain.
var animNodes = array.filter(args, function(item){
return item.node;
});
var waitingList = getWaitingList(animNodes);
//update registry with deferred objects in animations of args.
array.forEach(args, function(item){
if(item.node.id){
transition.playing[item.node.id] = item.deferred;
}
});
Deferred.when(waitingList, function(){
array.forEach(args, function(item){
//set the start state
item.initState();
});
//chain animations together
for (var i=1, len=args.length; i < len; i++){
args[i-1].deferred.then(lang.hitch(args[i], function(){
this.start();
}));
}
//Assume the fps of the animation should be higher than 30 fps and
//allow the browser to use one frame's time to redraw so that
//the transition can be started
setTimeout(function(){
args[0].start();
}, 33);
});
};
//TODO complete the registry mechanism for animation handling and prevent animation conflicts
transition.playing = {};
return transition;
});