transition-native-debug.js revision 4527b08ced97d1bf5f88cf786302fd66eb80a35b
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan HuntYUI.add('transition-native', function(Y) {
010a51c427bfb6ab658fc0056955a1a5b69810beTinderbox User
bef75d63d74f58abc0f834ed271526672777ba29Automatic Updater/**
c6fb85f9500350e5ce58c9a24f5d264c8a8bd6f4Automatic Updater* Provides the transition method for Node.
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt* Transition has no API of its own, but adds the transition method to Node.
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt*
bef75d63d74f58abc0f834ed271526672777ba29Automatic Updater* @module transition
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt* @see Node
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt*/
bef75d63d74f58abc0f834ed271526672777ba29Automatic Updater
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt/*
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt * A class for constructing transition instances.
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt * Adds the "transition" method to Node.
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt * @class Transition
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt * @constructor
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt */
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Huntvar TRANSITION = '-webkit-transition',
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt TRANSITION_PROPERTY_CAMEL = 'WebkitTransition',
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User TRANSITION_PROPERTY = '-webkit-transition-property',
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt TRANSITION_DURATION = '-webkit-transition-duration',
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User TRANSITION_TIMING_FUNCTION = '-webkit-transition-timing-function',
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt TRANSITION_DELAY = '-webkit-transition-delay',
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User TRANSITION_END = 'webkitTransitionEnd',
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt TRANSFORM_CAMEL = 'WebkitTransform',
dec590a3deb8e87380a8bd3a77d535dba3729bf6Tinderbox User
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt EMPTY_OBJ = {},
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan HuntTransition = function() {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User this.init.apply(this, arguments);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User};
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox UserTransition._toCamel = function(property) {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User property = property.replace(/-([a-z])/gi, function(m0, m1) {
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt return m1.toUpperCase();
fd0b768f4c23d22c89f8a156a632831583b7fb68Automatic Updater });
fd0b768f4c23d22c89f8a156a632831583b7fb68Automatic Updater
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt return property;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User};
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox UserTransition._toHyphen = function(property) {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) {
0ae35ecf053a29f61ad6b3659ac2445cf2c3f663Automatic Updater var str = '';
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User if (m1) {
0ae35ecf053a29f61ad6b3659ac2445cf2c3f663Automatic Updater str += '-' + m1.toLowerCase();
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User }
0a7ed88633a680bb881868b75ded4d09a7bbbc50Automatic Updater str += m2;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt if (m3) {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User str += '-' + m3.toLowerCase();
0ae35ecf053a29f61ad6b3659ac2445cf2c3f663Automatic Updater }
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
0ae35ecf053a29f61ad6b3659ac2445cf2c3f663Automatic Updater return str;
0ae35ecf053a29f61ad6b3659ac2445cf2c3f663Automatic Updater });
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt return property;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User};
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
6f1205897504b8f50b1785975482c995888dd630Tinderbox UserTransition._reKeywords = /^(?:node|duration|iterations|easing|delay)$/;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
6f1205897504b8f50b1785975482c995888dd630Tinderbox UserTransition.useNative = false;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
8ec3c085233cedb22b05da36e2773c8f357a7e45Automatic Updaterif (TRANSITION in Y.config.doc.documentElement.style) {
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox User Transition.useNative = true;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User Transition.supported = true; // TODO: remove
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox User}
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox User
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox UserY.Node.DOM_EVENTS[TRANSITION_END] = 1;
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox User
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox UserTransition.NAME = 'transition';
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox User
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox UserTransition.DEFAULT_EASING = 'ease';
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox UserTransition.DEFAULT_DURATION = 0.5;
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox UserTransition.DEFAULT_DELAY = 0;
6ea2385360e9e2167e65f9286447da9eea189457Tinderbox User
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox UserTransition._nodeAttrs = {};
0ae35ecf053a29f61ad6b3659ac2445cf2c3f663Automatic Updater
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox UserTransition.prototype = {
2eeb74d1cf5355dd98f6d507a10086e16bb08c4bTinderbox User constructor: Transition,
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt init: function(node, config) {
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt var anim = this;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User if (!anim._running) {
12bfbed87cfffa65ac300b72c5665ab38a355c2fAutomatic Updater anim._node = node;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User anim._config = config;
12bfbed87cfffa65ac300b72c5665ab38a355c2fAutomatic Updater node._transition = anim; // cache for reuse
12bfbed87cfffa65ac300b72c5665ab38a355c2fAutomatic Updater
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User anim._duration = ('duration' in config) ?
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt config.duration: anim.constructor.DEFAULT_DURATION;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User anim._delay = ('delay' in config) ?
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User config.delay: anim.constructor.DEFAULT_DELAY;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt anim._easing = config.easing || anim.constructor.DEFAULT_EASING;
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt anim._count = 0; // track number of animated properties
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt anim._running = false;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt anim.initAttrs(config);
cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88Evan Hunt
}
return anim;
},
addProperty: function(prop, config) {
var anim = this,
node = this._node,
uid = Y.stamp(node),
attrs = Transition._nodeAttrs[uid],
attr,
val;
if (!attrs) {
attrs = Transition._nodeAttrs[uid] = {};
}
attr = attrs[prop];
// might just be a value
if (config && config.value !== undefined) {
val = config.value;
} else if (config !== undefined) {
val = config;
config = EMPTY_OBJ;
}
if (typeof val === 'function') {
val = val.call(node, node);
}
// take control if another transition owns this property
if (attr && attr.transition && attr.transition !== anim) {
attr.transition._count--; // remapping attr to this transition
}
anim._count++; // properties per transition
attrs[prop] = {
value: val,
duration: ((typeof config.duration !== 'undefined') ? config.duration :
anim._duration) || 0.0001, // make 0 async and fire events
delay: (typeof config.delay !== 'undefined') ? config.delay :
anim._delay,
easing: config.easing || anim._easing,
transition: anim
};
},
removeProperty: function(prop) {
var anim = this,
attrs = Transition._nodeAttrs[Y.stamp(anim._node)];
if (attrs && attrs[prop]) {
delete attrs[prop];
anim._count--;
}
},
initAttrs: function(config) {
var attr;
if (config.transform && !config[TRANSFORM_CAMEL]) {
config[TRANSFORM_CAMEL] = config.transform;
delete config.transform; // TODO: copy
}
for (attr in config) {
if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) {
this.addProperty(attr, config[attr]);
}
}
},
/*
* Starts or an animation.
* @method run
* @chainable
*/
run: function(callback) {
var anim = this;
if (!anim._running) {
anim._running = true;
anim._node.fire('transition:start', {
type: 'transition:start',
config: anim._config
});
anim._start();
anim._callback = callback;
}
return anim;
},
_start: function() {
this._runNative();
},
_prepDur: function(dur) {
dur = parseFloat(dur);
return dur + 's';
},
_runNative: function(time) {
var anim = this,
node = anim._node,
uid = Y.stamp(node),
domNode = node._node,
style = domNode.style,
computed = getComputedStyle(domNode),
attrs = Transition._nodeAttrs[uid],
cssText = '',
cssTransition = computed[TRANSITION_PROPERTY],
transitionText = TRANSITION_PROPERTY + ': ',
duration = TRANSITION_DURATION + ': ',
easing = TRANSITION_TIMING_FUNCTION + ': ',
delay = TRANSITION_DELAY + ': ',
hyphy,
attr,
name;
// preserve existing transitions
if (cssTransition !== 'all') {
transitionText += cssTransition + ',';
duration += computed[TRANSITION_DURATION] + ',';
easing += computed[TRANSITION_TIMING_FUNCTION] + ',';
delay += computed[TRANSITION_DELAY] + ',';
}
// run transitions mapped to this instance
for (name in attrs) {
hyphy = Transition._toHyphen(name);
attr = attrs[name];
if (attrs.hasOwnProperty(name) && attr.transition === anim) {
if (name in domNode.style) { // only native styles allowed
duration += anim._prepDur(attr.duration) + ',';
delay += anim._prepDur(attr.delay) + ',';
easing += (attr.easing) + ',';
transitionText += hyphy + ',';
cssText += hyphy + ': ' + attr.value + '; ';
} else {
this.removeProperty(name);
}
}
}
transitionText = transitionText.replace(/,$/, ';');
duration = duration.replace(/,$/, ';');
easing = easing.replace(/,$/, ';');
delay = delay.replace(/,$/, ';');
// only one native end event per node
if (!node._hasTransitionEnd) {
anim._detach = node.on(TRANSITION_END, anim._onNativeEnd);
node._hasTransitionEnd = true;
}
style.cssText += transitionText + duration + easing + delay + cssText;
},
_end: function(elapsed) {
var anim = this,
node = anim._node,
callback = anim._callback,
data = {
type: 'transition:end',
config: anim._config,
elapsedTime: elapsed
};
anim._running = false;
if (callback) {
anim._callback = null;
setTimeout(function() { // IE: allow previous update to finish
callback.call(node, data);
}, 1);
}
node.fire('transition:end', data);
},
_endNative: function(name) {
var node = this._node,
value = node.getComputedStyle(TRANSITION_PROPERTY);
if (typeof value === 'string') {
value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ',');
value = value.replace(/^,|,$/, '');
node.setStyle(TRANSITION_PROPERTY_CAMEL, value);
}
},
_onNativeEnd: function(e) {
var node = this,
uid = Y.stamp(node),
event = e._event,
name = Transition._toCamel(event.propertyName),
elapsed = event.elapsedTime,
attrs = Transition._nodeAttrs[uid],
attr = attrs[name],
anim = (attr) ? attr.transition : null;
if (anim) {
anim.removeProperty(name);
anim._endNative(name);
node.fire('transition:propertyEnd', {
type: 'propertyEnd',
propertyName: name,
elapsedTime: elapsed
});
if (anim._count <= 0) { // after propertEnd fires
anim._end(elapsed);
}
}
},
destroy: function() {
var anim = this;
if (anim._detach) {
anim._detach.detach();
}
anim._node = null;
}
};
Y.Transition = Transition;
Y.TransitionNative = Transition; // TODO: remove
/**
* Animate one or more css properties to a given value. Requires the "transition" module.
* <pre>example usage:
* Y.one('#demo').transition({
* duration: 1, // in seconds, default is 0.5
* easing: 'ease-out', // default is 'ease'
* height: '10px',
* width: '10px',
* delay: '1', // delay start for 1 second, default is 0
* opacity: { // per property
* value: 0,
* duration: 2,
* delay: 2,
* easing: 'ease-in'
* }
* });
* </pre>
* @for Node
* @method transition
* @param {Object} config An object containing one or more style properties, a duration and an easing.
* @param {Function} callback A function to run after the transition has completed.
* @chainable
*/
Y.Node.prototype.transition = function(config, callback) {
var anim = this._transition;
if (anim && !anim._running) {
anim.init(this, config);
} else {
anim = new Transition(this, config);
}
anim.run(callback);
return this;
};
/**
* Animate one or more css properties to a given value. Requires the "transition" module.
* <pre>example usage:
* Y.all('.demo').transition({
* duration: 1, // in seconds, default is 0.5
* easing: 'ease-out', // default is 'ease'
* height: '10px',
* width: '10px',
* delay: '1', // delay start for 1 second, default is 0
* opacity: { // per property
* value: 0,
* duration: 2,
* delay: 2,
* easing: 'ease-in'
* }
* });
* </pre>
* @for NodeList
* @method transition
* @param {Object} config An object containing one or more style properties, a duration and an easing.
* @param {Function} callback A function to run after the transition has completed. The callback fires
* once per item in the NodeList.
* @chainable
*/
Y.NodeList.prototype.transition = function(config, callback) {
this.each(function(node) {
node.transition(config, callback);
});
return this;
};
}, '@VERSION@' ,{requires:['node-base']});