76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass* Provides the transition method for Node.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass* Transition has no API of its own, but adds the transition method to Node.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass* @module transition
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass* @requires node-style
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * A class for constructing transition instances.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Adds the "transition" method to Node.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class Transition
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassTransition = function() {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass property = property.replace(/-([a-z])/gi, function(m0, m1) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) {
416ff6e8477a5950c56e04adea6abf838140a852Matt Sweeney var str = ((m1) ? '-' + m1.toLowerCase() : '') + m2;
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyY.Array.each(VENDORS, function(val) { // then vendor specific
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt Sweeney if (property in DOCUMENT[DOCUMENT_ELEMENT].style) {
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt Sweeney VENDOR_PREFIX = Transition._toHyphen(val) + '-';
416ff6e8477a5950c56e04adea6abf838140a852Matt SweeneyTRANSITION_CAMEL = CAMEL_VENDOR_PREFIX + TRANSITION_CAMEL;
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyTRANSITION_PROPERTY_CAMEL = CAMEL_VENDOR_PREFIX + 'TransitionProperty';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyTRANSITION_PROPERTY = VENDOR_PREFIX + 'transition-property';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyTRANSITION_DURATION = VENDOR_PREFIX + 'transition-duration';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyTRANSITION_TIMING_FUNCTION = VENDOR_PREFIX + 'transition-timing-function';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyTRANSITION_DELAY = VENDOR_PREFIX + 'transition-delay';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyON_TRANSITION_END = 'on' + CAMEL_VENDOR_PREFIX.toLowerCase() + 'transitionend';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyTRANSITION_END = VENDOR_TRANSITION_END[CAMEL_VENDOR_PREFIX] || TRANSITION_END;
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyTRANSFORM_CAMEL = CAMEL_VENDOR_PREFIX + 'Transform';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt SweeneyTransition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass config.duration: anim.constructor.DEFAULT_DURATION;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass anim._easing = config.easing || anim.constructor.DEFAULT_EASING;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass anim._count = 0; // track number of animated properties
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // might just be a value
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // take control if another transition owns this property
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass attr.transition._count--; // remapping attr to this transition
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // make 0 async and fire events
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass dur = ((typeof config.duration != 'undefined') ? config.duration :
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass delay: (typeof config.delay != 'undefined') ? config.delay :
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // native end event doesnt fire when setting to same value
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // supplementing with timer
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // val may be a string or number (height: 0, etc), but computedStyle is always string
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass compareVal = (typeof val === 'string') ? computed : parseFloat(computed);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass attrs = Transition._nodeAttrs[Y.stamp(anim._node)];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (config.transform && !config[TRANSFORM_CAMEL]) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // when size is auto or % webkit starts from zero instead of computed
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // (https://bugs.webkit.org/show_bug.cgi?id=16020)
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // TODO: selective set
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr));
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Starts or an animation.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method run
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @chainable
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //anim._node.fire('transition:start', data);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _start: function() {
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt Sweeney cssTransition = computed[Transition._toCamel(TRANSITION_PROPERTY)],
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // preserve existing transitions
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt Sweeney duration += computed[Transition._toCamel(TRANSITION_DURATION)] + ',';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt Sweeney easing += computed[Transition._toCamel(TRANSITION_TIMING_FUNCTION)] + ',';
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt Sweeney delay += computed[Transition._toCamel(TRANSITION_DELAY)] + ',';
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // run transitions mapped to this instance
416ff6e8477a5950c56e04adea6abf838140a852Matt Sweeney if ((attr = attrs[name]) && attr.transition === anim) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (name in node.style) { // only native styles allowed
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass transitionText = transitionText.replace(/,$/, ';');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // only one native end event per node
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //anim._detach = Y.on(TRANSITION_END, anim._onNativeEnd, node);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //node[ON_TRANSITION_END] = anim._onNativeEnd;
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt Sweeney node.addEventListener(TRANSITION_END, anim._onNativeEnd, '');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //setTimeout(function() { // allow updates to apply (size fix, onstart, etc)
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass style.cssText += transitionText + duration + easing + delay + cssText;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass setTimeout(function() { // IE: allow previous update to finish
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // nested to ensure proper fire order
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else if (callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass setTimeout(function() { // IE: allow previous update to finish
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //node.fire('transition:end', data);
2e49faa8717cc2acbd7ab2aac237061848568a6cMatt Sweeney value = node.ownerDocument.defaultView.getComputedStyle(node, '')[Transition._toCamel(TRANSITION_PROPERTY)];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ',');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _onNativeEnd: function(e) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //node.fire('transition:propertyEnd', data);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (anim._count <= 0) { // after propertyEnd fires
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass destroy: function() {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (anim._detach) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass anim._detach.detach();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //anim._node[ON_TRANSITION_END] = null;
416ff6e8477a5950c56e04adea6abf838140a852Matt Sweeney node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Animate one or more css properties to a given value. Requires the "transition" module.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <pre>example usage:
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Y.one('#demo').transition({
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * duration: 1, // in seconds, default is 0.5
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * easing: 'ease-out', // default is 'ease'
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * delay: '1', // delay start for 1 second, default is 0
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * height: '10px',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * width: '10px',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * opacity: { // per property
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * duration: 2,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * easing: 'ease-in'
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method transition
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Object} config An object containing one or more style properties, a duration and an easing.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Function} callback A function to run after the transition has completed.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @chainable
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.Node.prototype.transition = function(name, config, callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)],
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass anim = (transitionAttrs) ? transitionAttrs.transition || null : null,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof name === 'string') { // named effect, pull config from registry
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else { // name is a config, config is a callback or undefined
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.Node.prototype.show = function(name, config, callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass else if (name && !Y.Transition) { Y.log('unable to transition show; missing transition module', 'warn', 'node'); }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return function() {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.Node.prototype.hide = function(name, config, callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else if (name && !Y.Transition) { Y.log('unable to transition hide; missing transition module', 'warn', 'node'); // end if on nex
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Animate one or more css properties to a given value. Requires the "transition" module.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * <pre>example usage:
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Y.all('.demo').transition({
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * duration: 1, // in seconds, default is 0.5
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * easing: 'ease-out', // default is 'ease'
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * delay: '1', // delay start for 1 second, default is 0
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * height: '10px',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * width: '10px',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * opacity: { // per property
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * duration: 2,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * easing: 'ease-in'
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @for NodeList
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method transition
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Object} config An object containing one or more style properties, a duration and an easing.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Function} callback A function to run after the transition has completed. The callback fires
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * once per item in the NodeList.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @chainable
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.NodeList.prototype.transition = function(config, callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.Node.prototype.toggleView = function(name, on, callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof name == 'boolean') { // no transition, just toggle
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof on == 'undefined' && name in this._toggles) { // reverse current toggle
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass callback = _wrapCallBack(this, this._hide, callback);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.transition(Y.Transition.toggles[name][on], callback);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.NodeList.prototype.toggleView = function(name, on, callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass start: function() {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (overflow !== 'hidden') { // enable scrollHeight/Width
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass end: function() {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (this._transitionOverflow) { // revert overridden value
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.setStyle('overflow', this._transitionOverflow);