Version 3.17.2

APIs

  • Begin typing in the search box above to see results.
Show:

File: transition/js/transition-native.js

/**
* Provides the transition method for Node.
* Transition has no API of its own, but adds the transition method to Node.
*
* @module transition
* @requires node-style
*/
var CAMEL_VENDOR_PREFIX = '',
 VENDOR_PREFIX = '',
 DOCUMENT = Y.config.doc,
 DOCUMENT_ELEMENT = 'documentElement',
 DOCUMENT_STYLE = DOCUMENT[DOCUMENT_ELEMENT].style,
 TRANSITION_CAMEL = 'transition',
 TRANSITION_PROPERTY_CAMEL = 'transitionProperty',
 TRANSITION_PROPERTY,
 TRANSITION_DURATION,
 TRANSITION_TIMING_FUNCTION,
 TRANSITION_DELAY,
 TRANSITION_END,
 ON_TRANSITION_END,
 EMPTY_OBJ = {},
 VENDORS = [
 'Webkit',
 'Moz'
 ],
 VENDOR_TRANSITION_END = {
 Webkit: 'webkitTransitionEnd'
 },
/**
 * A class for constructing transition instances.
 * Adds the "transition" method to Node.
 * @class Transition
 * @constructor
 */
Transition = function() {
 this.init.apply(this, arguments);
};
// One off handling of transform-prefixing.
Transition._TRANSFORM = 'transform';
Transition._toCamel = function(property) {
 property = property.replace(/-([a-z])/gi, function(m0, m1) {
 return m1.toUpperCase();
 });
 return property;
};
Transition._toHyphen = function(property) {
 property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) {
 var str = ((m1) ? '-' + m1.toLowerCase() : '') + m2;
 if (m3) {
 str += '-' + m3.toLowerCase();
 }
 return str;
 });
 return property;
};
Transition.SHOW_TRANSITION = 'fadeIn';
Transition.HIDE_TRANSITION = 'fadeOut';
Transition.useNative = false;
// Map transition properties to vendor-specific versions.
if ('transition' in DOCUMENT_STYLE
 && 'transitionProperty' in DOCUMENT_STYLE
 && 'transitionDuration' in DOCUMENT_STYLE
 && 'transitionTimingFunction' in DOCUMENT_STYLE
 && 'transitionDelay' in DOCUMENT_STYLE) {
 Transition.useNative = true;
 Transition.supported = true; // TODO: remove
} else {
 Y.Array.each(VENDORS, function(val) { // then vendor specific
 var property = val + 'Transition';
 if (property in DOCUMENT[DOCUMENT_ELEMENT].style) {
 CAMEL_VENDOR_PREFIX = val;
 VENDOR_PREFIX = Transition._toHyphen(val) + '-';
 Transition.useNative = true;
 Transition.supported = true; // TODO: remove
 Transition._VENDOR_PREFIX = val;
 }
 });
}
// Map transform property to vendor-specific versions.
// One-off required for cssText injection.
if (typeof DOCUMENT_STYLE.transform === 'undefined') {
 Y.Array.each(VENDORS, function(val) { // then vendor specific
 var property = val + 'Transform';
 if (typeof DOCUMENT_STYLE[property] !== 'undefined') {
 Transition._TRANSFORM = property;
 }
 });
}
if (CAMEL_VENDOR_PREFIX) {
 TRANSITION_CAMEL = CAMEL_VENDOR_PREFIX + 'Transition';
 TRANSITION_PROPERTY_CAMEL = CAMEL_VENDOR_PREFIX + 'TransitionProperty';
}
TRANSITION_PROPERTY = VENDOR_PREFIX + 'transition-property';
TRANSITION_DURATION = VENDOR_PREFIX + 'transition-duration';
TRANSITION_TIMING_FUNCTION = VENDOR_PREFIX + 'transition-timing-function';
TRANSITION_DELAY = VENDOR_PREFIX + 'transition-delay';
TRANSITION_END = 'transitionend';
ON_TRANSITION_END = 'on' + CAMEL_VENDOR_PREFIX.toLowerCase() + 'transitionend';
TRANSITION_END = VENDOR_TRANSITION_END[CAMEL_VENDOR_PREFIX] || TRANSITION_END;
Transition.fx = {};
Transition.toggles = {};
Transition._hasEnd = {};
Transition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i;
Y.Node.DOM_EVENTS[TRANSITION_END] = 1;
Transition.NAME = 'transition';
Transition.DEFAULT_EASING = 'ease';
Transition.DEFAULT_DURATION = 0.5;
Transition.DEFAULT_DELAY = 0;
Transition._nodeAttrs = {};
Transition.prototype = {
 constructor: Transition,
 init: function(node, config) {
 var anim = this;
 anim._node = node;
 if (!anim._running && config) {
 anim._config = config;
 node._transition = anim; // cache for reuse
 anim._duration = ('duration' in config) ?
 config.duration: anim.constructor.DEFAULT_DURATION;
 anim._delay = ('delay' in config) ?
 config.delay: anim.constructor.DEFAULT_DELAY;
 anim._easing = config.easing || anim.constructor.DEFAULT_EASING;
 anim._count = 0; // track number of animated properties
 anim._running = false;
 }
 return anim;
 },
 addProperty: function(prop, config) {
 var anim = this,
 node = this._node,
 uid = Y.stamp(node),
 nodeInstance = Y.one(node),
 attrs = Transition._nodeAttrs[uid],
 computed,
 compareVal,
 dur,
 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(nodeInstance, nodeInstance);
 }
 if (attr && attr.transition) {
 // take control if another transition owns this property
 if (attr.transition !== anim) {
 attr.transition._count--; // remapping attr to this transition
 }
 }
 anim._count++; // properties per transition
 // make 0 async and fire events
 dur = ((typeof config.duration !== 'undefined') ? config.duration :
 anim._duration) || 0.0001;
 attrs[prop] = {
 value: val,
 duration: dur,
 delay: (typeof config.delay !== 'undefined') ? config.delay :
 anim._delay,
 easing: config.easing || anim._easing,
 transition: anim
 };
 // native end event doesnt fire when setting to same value
 // supplementing with timer
 // val may be a string or number (height: 0, etc), but computedStyle is always string
 computed = Y.DOM.getComputedStyle(node, prop);
 compareVal = (typeof val === 'string') ? computed : parseFloat(computed);
 if (Transition.useNative && compareVal === val) {
 setTimeout(function() {
 anim._onNativeEnd.call(node, {
 propertyName: prop,
 elapsedTime: dur
 });
 }, dur * 1000);
 }
 },
 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,
 node = this._node;
 if (config.transform && !config[Transition._TRANSFORM]) {
 config[Transition._TRANSFORM] = config.transform;
 delete config.transform; // TODO: copy
 }
 for (attr in config) {
 if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) {
 this.addProperty(attr, config[attr]);
 // when size is auto or % webkit starts from zero instead of computed
 // (https://bugs.webkit.org/show_bug.cgi?id=16020)
 // TODO: selective set
 if (node.style[attr] === '') {
 Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr));
 }
 }
 }
 },
 /**
 * Starts or an animation.
 * @method run
 * @chainable
 * @private
 */
 run: function(callback) {
 var anim = this,
 node = anim._node,
 config = anim._config,
 data = {
 type: 'transition:start',
 config: config
 };
 if (!anim._running) {
 anim._running = true;
 if (config.on && config.on.start) {
 config.on.start.call(Y.one(node), data);
 }
 anim.initAttrs(anim._config);
 anim._callback = callback;
 anim._start();
 }
 return anim;
 },
 _start: function() {
 this._runNative();
 },
 _prepDur: function(dur) {
 dur = parseFloat(dur) * 1000;
 return dur + 'ms';
 },
 _runNative: function() {
 var anim = this,
 node = anim._node,
 uid = Y.stamp(node),
 style = node.style,
 computed = node.ownerDocument.defaultView.getComputedStyle(node),
 attrs = Transition._nodeAttrs[uid],
 cssText = '',
 cssTransition = computed[Transition._toCamel(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._toCamel(TRANSITION_DURATION)] + ',';
 easing += computed[Transition._toCamel(TRANSITION_TIMING_FUNCTION)] + ',';
 delay += computed[Transition._toCamel(TRANSITION_DELAY)] + ',';
 }
 // run transitions mapped to this instance
 for (name in attrs) {
 hyphy = Transition._toHyphen(name);
 attr = attrs[name];
 if ((attr = attrs[name]) && attr.transition === anim) {
 if (name in node.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 (!Transition._hasEnd[uid]) {
 node.addEventListener(TRANSITION_END, anim._onNativeEnd, '');
 Transition._hasEnd[uid] = true;
 }
 style.cssText += transitionText + duration + easing + delay + cssText;
 },
 _end: function(elapsed) {
 var anim = this,
 node = anim._node,
 callback = anim._callback,
 config = anim._config,
 data = {
 type: 'transition:end',
 config: config,
 elapsedTime: elapsed
 },
 nodeInstance = Y.one(node);
 anim._running = false;
 anim._callback = null;
 if (node) {
 if (config.on && config.on.end) {
 setTimeout(function() { // IE: allow previous update to finish
 config.on.end.call(nodeInstance, data);
 // nested to ensure proper fire order
 if (callback) {
 callback.call(nodeInstance, data);
 }
 }, 1);
 } else if (callback) {
 setTimeout(function() { // IE: allow previous update to finish
 callback.call(nodeInstance, data);
 }, 1);
 }
 }
 },
 _endNative: function(name) {
 var node = this._node,
 value = node.ownerDocument.defaultView.getComputedStyle(node, '')[Transition._toCamel(TRANSITION_PROPERTY)];
 name = Transition._toHyphen(name);
 if (typeof value === 'string') {
 value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ',');
 value = value.replace(/^,|,$/, '');
 node.style[TRANSITION_CAMEL] = value;
 }
 },
 _onNativeEnd: function(e) {
 var node = this,
 uid = Y.stamp(node),
 event = e,//e._event,
 name = Transition._toCamel(event.propertyName),
 elapsed = event.elapsedTime,
 attrs = Transition._nodeAttrs[uid],
 attr = attrs[name],
 anim = (attr) ? attr.transition : null,
 data,
 config;
 if (anim) {
 anim.removeProperty(name);
 anim._endNative(name);
 config = anim._config[name];
 data = {
 type: 'propertyEnd',
 propertyName: name,
 elapsedTime: elapsed,
 config: config
 };
 if (config && config.on && config.on.end) {
 config.on.end.call(Y.one(node), data);
 }
 if (anim._count <= 0) { // after propertyEnd fires
 anim._end(elapsed);
 node.style[TRANSITION_PROPERTY_CAMEL] = ''; // clean up style
 }
 }
 },
 destroy: function() {
 var anim = this,
 node = anim._node;
 if (node) {
 node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false);
 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'
 * delay: '1', // delay start for 1 second, default is 0
 *
 * height: '10px',
 * width: '10px',
 *
 * 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(name, config, callback) {
 var
 transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)],
 anim = (transitionAttrs) ? transitionAttrs.transition || null : null,
 fxConfig,
 prop;
 if (typeof name === 'string') { // named effect, pull config from registry
 if (typeof config === 'function') {
 callback = config;
 config = null;
 }
 fxConfig = Transition.fx[name];
 if (config && typeof config === 'object') {
 config = Y.clone(config);
 for (prop in fxConfig) {
 if (fxConfig.hasOwnProperty(prop)) {
 if (! (prop in config)) {
 config[prop] = fxConfig[prop];
 }
 }
 }
 } else {
 config = fxConfig;
 }
 } else { // name is a config, config is a callback or undefined
 callback = config;
 config = name;
 }
 if (anim && !anim._running) {
 anim.init(this, config);
 } else {
 anim = new Transition(this._node, config);
 }
 anim.run(callback);
 return this;
};
Y.Node.prototype.show = function(name, config, callback) {
 this._show(); // show prior to transition
 if (name && Y.Transition) {
 if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
 if (typeof config === 'function') {
 callback = config;
 config = name;
 }
 name = Transition.SHOW_TRANSITION;
 }
 this.transition(name, config, callback);
 }
 else if (name && !Y.Transition) { Y.log('unable to transition show; missing transition module', 'warn', 'node'); }
 return this;
};
Y.NodeList.prototype.show = function(name, config, callback) {
 var nodes = this._nodes,
 i = 0,
 node;
 while ((node = nodes[i++])) {
 Y.one(node).show(name, config, callback);
 }
 return this;
};
var _wrapCallBack = function(anim, fn, callback) {
 return function() {
 if (fn) {
 fn.call(anim);
 }
 if (callback && typeof callback === 'function') {
 callback.apply(anim._node, arguments);
 }
 };
};
Y.Node.prototype.hide = function(name, config, callback) {
 if (name && Y.Transition) {
 if (typeof config === 'function') {
 callback = config;
 config = null;
 }
 callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback
 if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
 if (typeof config === 'function') {
 callback = config;
 config = name;
 }
 name = Transition.HIDE_TRANSITION;
 }
 this.transition(name, config, callback);
 } else if (name && !Y.Transition) { Y.log('unable to transition hide; missing transition module', 'warn', 'node');
 } else {
 this._hide();
 }
 return this;
};
Y.NodeList.prototype.hide = function(name, config, callback) {
 var nodes = this._nodes,
 i = 0,
 node;
 while ((node = nodes[i++])) {
 Y.one(node).hide(name, config, 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'
 * delay: '1', // delay start for 1 second, default is 0
 *
 * height: '10px',
 * width: '10px',
 *
 * 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.
 * @param {Boolean} callbackOnce If true, the callback will be called only after the
 * last transition has completed
 * @chainable
*/
Y.NodeList.prototype.transition = function(config, callback, callbackOnce) {
 var nodes = this._nodes,
 size = this.size(),
 i = 0,
 callbackOnce = callbackOnce === true,
 node;
 while ((node = nodes[i++])) {
 if (i < size && callbackOnce){
 Y.one(node).transition(config);
 } else {
 Y.one(node).transition(config, callback);
 }
 }
 return this;
};
Y.Node.prototype.toggleView = function(name, on, callback) {
 this._toggles = this._toggles || [];
 callback = arguments[arguments.length - 1];
 if (typeof name !== 'string') { // no transition, just toggle
 on = name;
 this._toggleView(on, callback); // call original _toggleView in Y.Node
 return;
 }
 if (typeof on === 'function') { // Ignore "on" if used for callback argument.
 on = undefined;
 }
 if (typeof on === 'undefined' && name in this._toggles) { // reverse current toggle
 on = ! this._toggles[name];
 }
 on = (on) ? 1 : 0;
 if (on) {
 this._show();
 } else {
 callback = _wrapCallBack(this, this._hide, callback);
 }
 this._toggles[name] = on;
 this.transition(Y.Transition.toggles[name][on], callback);
 return this;
};
Y.NodeList.prototype.toggleView = function(name, on, callback) {
 var nodes = this._nodes,
 i = 0,
 node;
 while ((node = nodes[i++])) {
 node = Y.one(node);
 node.toggleView.apply(node, arguments);
 }
 return this;
};
Y.mix(Transition.fx, {
 fadeOut: {
 opacity: 0,
 duration: 0.5,
 easing: 'ease-out'
 },
 fadeIn: {
 opacity: 1,
 duration: 0.5,
 easing: 'ease-in'
 },
 sizeOut: {
 height: 0,
 width: 0,
 duration: 0.75,
 easing: 'ease-out'
 },
 sizeIn: {
 height: function(node) {
 return node.get('scrollHeight') + 'px';
 },
 width: function(node) {
 return node.get('scrollWidth') + 'px';
 },
 duration: 0.5,
 easing: 'ease-in',
 on: {
 start: function() {
 var overflow = this.getStyle('overflow');
 if (overflow !== 'hidden') { // enable scrollHeight/Width
 this.setStyle('overflow', 'hidden');
 this._transitionOverflow = overflow;
 }
 },
 end: function() {
 if (this._transitionOverflow) { // revert overridden value
 this.setStyle('overflow', this._transitionOverflow);
 delete this._transitionOverflow;
 }
 }
 }
 }
});
Y.mix(Transition.toggles, {
 size: ['sizeOut', 'sizeIn'],
 fade: ['fadeOut', 'fadeIn']
});
 

AltStyle によって変換されたページ (->オリジナル) /