From 5b2235e0c926d089dce683dd28093150bf204b75 Mon Sep 17 00:00:00 2001 From: Julien Bouquillon Date: Tue, 11 Nov 2014 14:30:29 +0100 Subject: [PATCH] fix(shifty): upgrade to latest version --- bower.json | 2 +- dist/angular-carousel.js | 2513 +++++++++++++++++---------------- dist/angular-carousel.min.js | 4 +- package.json | 2 +- src/directives/rn-carousel.js | 2 +- src/directives/shifty.js | 2511 ++++++++++++++++---------------- 6 files changed, 2556 insertions(+), 2478 deletions(-) diff --git a/bower.json b/bower.json index dd01b6a..3cd6d32 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "angular-carousel", "description": "Angular Carousel - Mobile friendly touch carousel for AngularJS", - "version": "0.3.6", + "version": "0.3.7", "homepage": "http://revolunet.github.com/angular-carousel", "author": "Julien Bouquillon ", "repository": { diff --git a/dist/angular-carousel.js b/dist/angular-carousel.js index 35fa6be..905d0f5 100644 --- a/dist/angular-carousel.js +++ b/dist/angular-carousel.js @@ -1,6 +1,6 @@ /** * Angular Carousel - Mobile friendly touch carousel for AngularJS - * @version v0.3.5 - 2014-11-06 + * @version v0.3.7 - 2014-11-11 * @link http://revolunet.github.com/angular-carousel * @author Julien Bouquillon * @license MIT License, http://www.opensource.org/licenses/MIT @@ -238,7 +238,7 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach return true; }); return result; - }; + } return { restrict: 'A', @@ -657,1381 +657,1420 @@ angular.module('angular-carousel.shifty', []) .factory('Tweenable', function() { - (function (root, window) { - /*! - * Shifty Core - * By Jeremy Kahn - jeremyckahn@gmail.com - */ + /*! shifty - v1.3.4 - 2014-10-29 - http://jeremyckahn.github.io/shifty */ + ;(function (root) { + + /*! + * Shifty Core + * By Jeremy Kahn - jeremyckahn@gmail.com + */ + + var Tweenable = (function () { + + 'use strict'; + + // Aliases that get defined later in this function + var formula; + + // CONSTANTS + var DEFAULT_SCHEDULE_FUNCTION; + var DEFAULT_EASING = 'linear'; + var DEFAULT_DURATION = 500; + var UPDATE_TIME = 1000 / 60; + + var _now = Date.now + ? Date.now + : function () {return +new Date();}; + + var now = typeof SHIFTY_DEBUG_NOW !== 'undefined' ? SHIFTY_DEBUG_NOW : _now; + + if (typeof window !== 'undefined') { + // requestAnimationFrame() shim by Paul Irish (modified for Shifty) + // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + DEFAULT_SCHEDULE_FUNCTION = window.requestAnimationFrame + || window.webkitRequestAnimationFrame + || window.oRequestAnimationFrame + || window.msRequestAnimationFrame + || (window.mozCancelRequestAnimationFrame + && window.mozRequestAnimationFrame) + || setTimeout; + } else { + DEFAULT_SCHEDULE_FUNCTION = setTimeout; + } - // UglifyJS define hack. Used for unit testing. Contents of this if are - // compiled away. - if (typeof SHIFTY_DEBUG_NOW === 'undefined') { - SHIFTY_DEBUG_NOW = function () { - return +new Date(); - }; + function noop () { + // NOOP! } - var Tweenable = (function () { - - 'use strict'; - - // Aliases that get defined later in this function - var formula; - - // CONSTANTS - var DEFAULT_SCHEDULE_FUNCTION; - var DEFAULT_EASING = 'linear'; - var DEFAULT_DURATION = 500; - var UPDATE_TIME = 1000 / 60; - - var _now = Date.now - ? Date.now - : function () {return +new Date();}; - - var now = SHIFTY_DEBUG_NOW - ? SHIFTY_DEBUG_NOW - : _now; - - if (typeof window !== 'undefined') { - // requestAnimationFrame() shim by Paul Irish (modified for Shifty) - // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - DEFAULT_SCHEDULE_FUNCTION = window.requestAnimationFrame - || window.webkitRequestAnimationFrame - || window.oRequestAnimationFrame - || window.msRequestAnimationFrame - || (window.mozCancelRequestAnimationFrame - && window.mozRequestAnimationFrame) - || setTimeout; - } else { - DEFAULT_SCHEDULE_FUNCTION = setTimeout; + /*! + * Handy shortcut for doing a for-in loop. This is not a "normal" each + * function, it is optimized for Shifty. The iterator function only receives + * the property name, not the value. + * @param {Object} obj + * @param {Function(string)} fn + */ + function each (obj, fn) { + var key; + for (key in obj) { + if (Object.hasOwnProperty.call(obj, key)) { + fn(key); + } } + } - function noop () { - // NOOP! - } + /*! + * Perform a shallow copy of Object properties. + * @param {Object} targetObject The object to copy into + * @param {Object} srcObject The object to copy from + * @return {Object} A reference to the augmented `targetObj` Object + */ + function shallowCopy (targetObj, srcObj) { + each(srcObj, function (prop) { + targetObj[prop] = srcObj[prop]; + }); - /*! - * Handy shortcut for doing a for-in loop. This is not a "normal" each - * function, it is optimized for Shifty. The iterator function only receives - * the property name, not the value. - * @param {Object} obj - * @param {Function(string)} fn - */ - function each (obj, fn) { - var key; - for (key in obj) { - if (Object.hasOwnProperty.call(obj, key)) { - fn(key); - } + return targetObj; + } + + /*! + * Copies each property from src onto target, but only if the property to + * copy to target is undefined. + * @param {Object} target Missing properties in this Object are filled in + * @param {Object} src + */ + function defaults (target, src) { + each(src, function (prop) { + if (typeof target[prop] === 'undefined') { + target[prop] = src[prop]; + } + }); + } + + /*! + * Calculates the interpolated tween values of an Object for a given + * timestamp. + * @param {Number} forPosition The position to compute the state for. + * @param {Object} currentState Current state properties. + * @param {Object} originalState: The original state properties the Object is + * tweening from. + * @param {Object} targetState: The destination state properties the Object + * is tweening to. + * @param {number} duration: The length of the tween in milliseconds. + * @param {number} timestamp: The UNIX epoch time at which the tween began. + * @param {Object} easing: This Object's keys must correspond to the keys in + * targetState. + */ + function tweenProps (forPosition, currentState, originalState, targetState, + duration, timestamp, easing) { + var normalizedPosition = (forPosition - timestamp) / duration; + + var prop; + for (prop in currentState) { + if (currentState.hasOwnProperty(prop)) { + currentState[prop] = tweenProp(originalState[prop], + targetState[prop], formula[easing[prop]], normalizedPosition); } } - /*! - * Perform a shallow copy of Object properties. - * @param {Object} targetObject The object to copy into - * @param {Object} srcObject The object to copy from - * @return {Object} A reference to the augmented `targetObj` Object - */ - function shallowCopy (targetObj, srcObj) { - each(srcObj, function (prop) { - targetObj[prop] = srcObj[prop]; - }); + return currentState; + } - return targetObj; - } + /*! + * Tweens a single property. + * @param {number} start The value that the tween started from. + * @param {number} end The value that the tween should end at. + * @param {Function} easingFunc The easing curve to apply to the tween. + * @param {number} position The normalized position (between 0.0 and 1.0) to + * calculate the midpoint of 'start' and 'end' against. + * @return {number} The tweened value. + */ + function tweenProp (start, end, easingFunc, position) { + return start + (end - start) * easingFunc(position); + } - /*! - * Copies each property from src onto target, but only if the property to - * copy to target is undefined. - * @param {Object} target Missing properties in this Object are filled in - * @param {Object} src - */ - function defaults (target, src) { - each(src, function (prop) { - if (typeof target[prop] === 'undefined') { - target[prop] = src[prop]; - } - }); - } + /*! + * Applies a filter to Tweenable instance. + * @param {Tweenable} tweenable The `Tweenable` instance to call the filter + * upon. + * @param {String} filterName The name of the filter to apply. + */ + function applyFilter (tweenable, filterName) { + var filters = Tweenable.prototype.filter; + var args = tweenable._filterArgs; - /*! - * Calculates the interpolated tween values of an Object for a given - * timestamp. - * @param {Number} forPosition The position to compute the state for. - * @param {Object} currentState Current state properties. - * @param {Object} originalState: The original state properties the Object is - * tweening from. - * @param {Object} targetState: The destination state properties the Object - * is tweening to. - * @param {number} duration: The length of the tween in milliseconds. - * @param {number} timestamp: The UNIX epoch time at which the tween began. - * @param {Object} easing: This Object's keys must correspond to the keys in - * targetState. - */ - function tweenProps (forPosition, currentState, originalState, targetState, - duration, timestamp, easing) { - var normalizedPosition = (forPosition - timestamp) / duration; - - var prop; - for (prop in currentState) { - if (currentState.hasOwnProperty(prop)) { - currentState[prop] = tweenProp(originalState[prop], - targetState[prop], formula[easing[prop]], normalizedPosition); - } + each(filters, function (name) { + if (typeof filters[name][filterName] !== 'undefined') { + filters[name][filterName].apply(tweenable, args); } + }); + } - return currentState; + var timeoutHandler_endTime; + var timeoutHandler_currentTime; + var timeoutHandler_isEnded; + var timeoutHandler_offset; + /*! + * Handles the update logic for one step of a tween. + * @param {Tweenable} tweenable + * @param {number} timestamp + * @param {number} duration + * @param {Object} currentState + * @param {Object} originalState + * @param {Object} targetState + * @param {Object} easing + * @param {Function(Object, *, number)} step + * @param {Function(Function,number)}} schedule + */ + function timeoutHandler (tweenable, timestamp, duration, currentState, + originalState, targetState, easing, step, schedule) { + timeoutHandler_endTime = timestamp + duration; + timeoutHandler_currentTime = Math.min(now(), timeoutHandler_endTime); + timeoutHandler_isEnded = + timeoutHandler_currentTime >= timeoutHandler_endTime; + + timeoutHandler_offset = duration - ( + timeoutHandler_endTime - timeoutHandler_currentTime); + + if (tweenable.isPlaying() && !timeoutHandler_isEnded) { + tweenable._scheduleId = schedule(tweenable._timeoutHandler, UPDATE_TIME); + + applyFilter(tweenable, 'beforeTween'); + tweenProps(timeoutHandler_currentTime, currentState, originalState, + targetState, duration, timestamp, easing); + applyFilter(tweenable, 'afterTween'); + + step(currentState, tweenable._attachment, timeoutHandler_offset); + } else if (timeoutHandler_isEnded) { + step(targetState, tweenable._attachment, timeoutHandler_offset); + tweenable.stop(true); } + } - /*! - * Tweens a single property. - * @param {number} start The value that the tween started from. - * @param {number} end The value that the tween should end at. - * @param {Function} easingFunc The easing curve to apply to the tween. - * @param {number} position The normalized position (between 0.0 and 1.0) to - * calculate the midpoint of 'start' and 'end' against. - * @return {number} The tweened value. - */ - function tweenProp (start, end, easingFunc, position) { - return start + (end - start) * easingFunc(position); - } - /*! - * Applies a filter to Tweenable instance. - * @param {Tweenable} tweenable The `Tweenable` instance to call the filter - * upon. - * @param {String} filterName The name of the filter to apply. - */ - function applyFilter (tweenable, filterName) { - var filters = Tweenable.prototype.filter; - var args = tweenable._filterArgs; - - each(filters, function (name) { - if (typeof filters[name][filterName] !== 'undefined') { - filters[name][filterName].apply(tweenable, args); + /*! + * Creates a usable easing Object from either a string or another easing + * Object. If `easing` is an Object, then this function clones it and fills + * in the missing properties with "linear". + * @param {Object} fromTweenParams + * @param {Object|string} easing + */ + function composeEasingObject (fromTweenParams, easing) { + var composedEasing = {}; + + if (typeof easing === 'string') { + each(fromTweenParams, function (prop) { + composedEasing[prop] = easing; + }); + } else { + each(fromTweenParams, function (prop) { + if (!composedEasing[prop]) { + composedEasing[prop] = easing[prop] || DEFAULT_EASING; } }); } - var timeoutHandler_endTime; - var timeoutHandler_currentTime; - var timeoutHandler_isEnded; - /*! - * Handles the update logic for one step of a tween. - * @param {Tweenable} tweenable - * @param {number} timestamp - * @param {number} duration - * @param {Object} currentState - * @param {Object} originalState - * @param {Object} targetState - * @param {Object} easing - * @param {Function} step - * @param {Function(Function,number)}} schedule - */ - function timeoutHandler (tweenable, timestamp, duration, currentState, - originalState, targetState, easing, step, schedule) { - timeoutHandler_endTime = timestamp + duration; - timeoutHandler_currentTime = Math.min(now(), timeoutHandler_endTime); - timeoutHandler_isEnded = timeoutHandler_currentTime >= timeoutHandler_endTime; - - if (tweenable.isPlaying() && !timeoutHandler_isEnded) { - schedule(tweenable._timeoutHandler, UPDATE_TIME); - - applyFilter(tweenable, 'beforeTween'); - tweenProps(timeoutHandler_currentTime, currentState, originalState, - targetState, duration, timestamp, easing); - applyFilter(tweenable, 'afterTween'); - - step(currentState); - } else if (timeoutHandler_isEnded) { - step(targetState); - tweenable.stop(true); - } - } - - - /*! - * Creates a usable easing Object from either a string or another easing - * Object. If `easing` is an Object, then this function clones it and fills - * in the missing properties with "linear". - * @param {Object} fromTweenParams - * @param {Object|string} easing - */ - function composeEasingObject (fromTweenParams, easing) { - var composedEasing = {}; - - if (typeof easing === 'string') { - each(fromTweenParams, function (prop) { - composedEasing[prop] = easing; - }); - } else { - each(fromTweenParams, function (prop) { - if (!composedEasing[prop]) { - composedEasing[prop] = easing[prop] || DEFAULT_EASING; - } - }); - } + return composedEasing; + } - return composedEasing; + /** + * Tweenable constructor. + * @param {Object=} opt_initialState The values that the initial tween should start at if a "from" object is not provided to Tweenable#tween. + * @param {Object=} opt_config See Tweenable.prototype.setConfig() + * @constructor + */ + function Tweenable (opt_initialState, opt_config) { + this._currentState = opt_initialState || {}; + this._configured = false; + this._scheduleFunction = DEFAULT_SCHEDULE_FUNCTION; + + // To prevent unnecessary calls to setConfig do not set default configuration here. + // Only set default configuration immediately before tweening if none has been set. + if (typeof opt_config !== 'undefined') { + this.setConfig(opt_config); } + } - /** - * Tweenable constructor. - * @param {Object=} opt_initialState The values that the initial tween should start at if a "from" object is not provided to Tweenable#tween. - * @param {Object=} opt_config See Tweenable.prototype.setConfig() - * @constructor - */ - function Tweenable (opt_initialState, opt_config) { - this._currentState = opt_initialState || {}; - this._configured = false; - this._scheduleFunction = DEFAULT_SCHEDULE_FUNCTION; - - // To prevent unnecessary calls to setConfig do not set default configuration here. - // Only set default configuration immediately before tweening if none has been set. - if (typeof opt_config !== 'undefined') { - this.setConfig(opt_config); - } + /** + * Configure and start a tween. + * @param {Object=} opt_config See Tweenable.prototype.setConfig() + * @return {Tweenable} + */ + Tweenable.prototype.tween = function (opt_config) { + if (this._isTweening) { + return this; } - /** - * Configure and start a tween. - * @param {Object=} opt_config See Tweenable.prototype.setConfig() - * @return {Tweenable} - */ - Tweenable.prototype.tween = function (opt_config) { - if (this._isTweening) { - return this; - } + // Only set default config if no configuration has been set previously and none is provided now. + if (opt_config !== undefined || !this._configured) { + this.setConfig(opt_config); + } - // Only set default config if no configuration has been set previously and none is provided now. - if (opt_config !== undefined || !this._configured) { - this.setConfig(opt_config); - } + this._timestamp = now(); + this._start(this.get(), this._attachment); + return this.resume(); + }; - this._start(this.get()); - return this.resume(); - }; + /** + * Sets the tween configuration. `config` may have the following options: + * + * - __from__ (_Object=_): Starting position. If omitted, the current state is used. + * - __to__ (_Object=_): Ending position. + * - __duration__ (_number=_): How many milliseconds to animate for. + * - __start__ (_Function(Object)_): Function to execute when the tween begins. Receives the state of the tween as the first parameter. Attachment is the second parameter. + * - __step__ (_Function(Object, *, number)_): Function to execute on every tick. Receives the state of the tween as the first parameter. Attachment is the second parameter, and the time elapsed since the start of the tween is the third parameter. This function is not called on the final step of the animation, but `finish` is. + * - __finish__ (_Function(Object, *)_): Function to execute upon tween completion. Receives the state of the tween as the first parameter. Attachment is the second parameter. + * - __easing__ (_Object|string=_): Easing curve name(s) to use for the tween. + * - __attachment__ (_Object|string|any=_): Value that is attached to this instance and passed on to the step/start/finish methods. + * @param {Object} config + * @return {Tweenable} + */ + Tweenable.prototype.setConfig = function (config) { + config = config || {}; + this._configured = true; - /** - * Sets the tween configuration. `config` may have the following options: - * - * - __from__ (_Object=_): Starting position. If omitted, the current state is used. - * - __to__ (_Object=_): Ending position. - * - __duration__ (_number=_): How many milliseconds to animate for. - * - __start__ (_Function(Object)=_): Function to execute when the tween begins. Receives the state of the tween as the only parameter. - * - __step__ (_Function(Object)=_): Function to execute on every tick. Receives the state of the tween as the only parameter. This function is not called on the final step of the animation, but `finish` is. - * - __finish__ (_Function(Object)=_): Function to execute upon tween completion. Receives the state of the tween as the only parameter. - * - __easing__ (_Object|string=_): Easing curve name(s) to use for the tween. - * @param {Object} config - * @return {Tweenable} - */ - Tweenable.prototype.setConfig = function (config) { - config = config || {}; - this._configured = true; - - // Init the internal state - this._pausedAtTime = null; - this._start = config.start || noop; - this._step = config.step || noop; - this._finish = config.finish || noop; - this._duration = config.duration || DEFAULT_DURATION; - this._currentState = config.from || this.get(); - this._originalState = this.get(); - this._targetState = config.to || this.get(); - this._timestamp = now(); - - // Aliases used below - var currentState = this._currentState; - var targetState = this._targetState; - - // Ensure that there is always something to tween to. - defaults(targetState, currentState); - - this._easing = composeEasingObject( - currentState, config.easing || DEFAULT_EASING); - - this._filterArgs = - [currentState, this._originalState, targetState, this._easing]; - - applyFilter(this, 'tweenCreated'); - return this; - }; + // Attach something to this Tweenable instance (e.g.: a DOM element, an object, a string, etc.); + this._attachment = config.attachment; - /** - * Gets the current state. - * @return {Object} - */ - Tweenable.prototype.get = function () { - return shallowCopy({}, this._currentState); - }; + // Init the internal state + this._pausedAtTime = null; + this._scheduleId = null; + this._start = config.start || noop; + this._step = config.step || noop; + this._finish = config.finish || noop; + this._duration = config.duration || DEFAULT_DURATION; + this._currentState = config.from || this.get(); + this._originalState = this.get(); + this._targetState = config.to || this.get(); - /** - * Sets the current state. - * @param {Object} state - */ - Tweenable.prototype.set = function (state) { - this._currentState = state; - }; + // Aliases used below + var currentState = this._currentState; + var targetState = this._targetState; - /** - * Pauses a tween. Paused tweens can be resumed from the point at which they were paused. This is different than [`stop()`](#stop), as that method causes a tween to start over when it is resumed. - * @return {Tweenable} - */ - Tweenable.prototype.pause = function () { - this._pausedAtTime = now(); - this._isPaused = true; - return this; - }; + // Ensure that there is always something to tween to. + defaults(targetState, currentState); - /** - * Resumes a paused tween. - * @return {Tweenable} - */ - Tweenable.prototype.resume = function () { - if (this._isPaused) { - this._timestamp += now() - this._pausedAtTime; - } + this._easing = composeEasingObject( + currentState, config.easing || DEFAULT_EASING); - this._isPaused = false; - this._isTweening = true; + this._filterArgs = + [currentState, this._originalState, targetState, this._easing]; - var self = this; - this._timeoutHandler = function () { - timeoutHandler(self, self._timestamp, self._duration, self._currentState, - self._originalState, self._targetState, self._easing, self._step, - self._scheduleFunction); - }; + applyFilter(this, 'tweenCreated'); + return this; + }; - this._timeoutHandler(); + /** + * Gets the current state. + * @return {Object} + */ + Tweenable.prototype.get = function () { + return shallowCopy({}, this._currentState); + }; - return this; - }; + /** + * Sets the current state. + * @param {Object} state + */ + Tweenable.prototype.set = function (state) { + this._currentState = state; + }; - /** - * Stops and cancels a tween. - * @param {boolean=} gotoEnd If false or omitted, the tween just stops at its current state, and the "finish" handler is not invoked. If true, the tweened object's values are instantly set to the target values, and "finish" is invoked. - * @return {Tweenable} - */ - Tweenable.prototype.stop = function (gotoEnd) { - this._isTweening = false; - this._isPaused = false; - this._timeoutHandler = noop; + /** + * Pauses a tween. Paused tweens can be resumed from the point at which they were paused. This is different than [`stop()`](#stop), as that method causes a tween to start over when it is resumed. + * @return {Tweenable} + */ + Tweenable.prototype.pause = function () { + this._pausedAtTime = now(); + this._isPaused = true; + return this; + }; - if (gotoEnd) { - shallowCopy(this._currentState, this._targetState); - applyFilter(this, 'afterTweenEnd'); - this._finish.call(this, this._currentState); - } + /** + * Resumes a paused tween. + * @return {Tweenable} + */ + Tweenable.prototype.resume = function () { + if (this._isPaused) { + this._timestamp += now() - this._pausedAtTime; + } - return this; - }; + this._isPaused = false; + this._isTweening = true; - /** - * Returns whether or not a tween is running. - * @return {boolean} - */ - Tweenable.prototype.isPlaying = function () { - return this._isTweening && !this._isPaused; + var self = this; + this._timeoutHandler = function () { + timeoutHandler(self, self._timestamp, self._duration, self._currentState, + self._originalState, self._targetState, self._easing, self._step, + self._scheduleFunction); }; - /** - * Sets a custom schedule function. - * - * If a custom function is not set the default one is used [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame) if available, otherwise [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout)). - * - * @param {Function(Function,number)} scheduleFunction The function to be called to schedule the next frame to be rendered - */ - Tweenable.prototype.setScheduleFunction = function (scheduleFunction) { - this._scheduleFunction = scheduleFunction; - }; + this._timeoutHandler(); - /** - * `delete`s all "own" properties. Call this when the `Tweenable` instance is no longer needed to free memory. - */ - Tweenable.prototype.dispose = function () { - var prop; - for (prop in this) { - if (this.hasOwnProperty(prop)) { - delete this[prop]; - } - } - }; + return this; + }; - /*! - * Filters are used for transforming the properties of a tween at various - * points in a Tweenable's life cycle. See the README for more info on this. - */ - Tweenable.prototype.filter = {}; - - /*! - * This object contains all of the tweens available to Shifty. It is extendible - simply attach properties to the Tweenable.prototype.formula Object following the same format at linear. - * - * `pos` should be a normalized `number` (between 0 and 1). - */ - Tweenable.prototype.formula = { - linear: function (pos) { - return pos; - } - }; + /** + * Move the state of the animation to a specific point in the tween's timeline. + * If the animation is not running, this will cause the `step` handlers to be + * called. + * @param {millisecond} millisecond The millisecond of the animation to seek to. + * @return {Tweenable} + */ + Tweenable.prototype.seek = function (millisecond) { + this._timestamp = now() - millisecond; - formula = Tweenable.prototype.formula; - - shallowCopy(Tweenable, { - 'now': now - ,'each': each - ,'tweenProps': tweenProps - ,'tweenProp': tweenProp - ,'applyFilter': applyFilter - ,'shallowCopy': shallowCopy - ,'defaults': defaults - ,'composeEasingObject': composeEasingObject - }); + if (!this.isPlaying()) { + this._isTweening = true; + this._isPaused = false; - // `root` is provided in the intro/outro files. + // If the animation is not running, call timeoutHandler to make sure that + // any step handlers are run. + timeoutHandler(this, this._timestamp, this._duration, this._currentState, + this._originalState, this._targetState, this._easing, this._step, + this._scheduleFunction); - // A hook used for unit testing. - if (typeof SHIFTY_DEBUG_NOW === 'function') { - root.timeoutHandler = timeoutHandler; + this._timeoutHandler(); + this.pause(); } - // Bootstrap Tweenable appropriately for the environment. - if (typeof exports === 'object') { - // CommonJS - module.exports = Tweenable; - } else if (typeof define === 'function' && define.amd) { - // AMD - define(function () {return Tweenable;}); - } else if (typeof root.Tweenable === 'undefined') { - // Browser: Make `Tweenable` globally accessible. - root.Tweenable = Tweenable; + return this; + }; + + /** + * Stops and cancels a tween. + * @param {boolean=} gotoEnd If false or omitted, the tween just stops at its current state, and the "finish" handler is not invoked. If true, the tweened object's values are instantly set to the target values, and "finish" is invoked. + * @return {Tweenable} + */ + Tweenable.prototype.stop = function (gotoEnd) { + this._isTweening = false; + this._isPaused = false; + this._timeoutHandler = noop; + + (root.cancelAnimationFrame || + root.webkitCancelAnimationFrame || + root.oCancelAnimationFrame || + root.msCancelAnimationFrame || + root.mozCancelRequestAnimationFrame || + root.clearTimeout)(this._scheduleId); + + if (gotoEnd) { + shallowCopy(this._currentState, this._targetState); + applyFilter(this, 'afterTweenEnd'); + this._finish.call(this, this._currentState, this._attachment); } - return Tweenable; + return this; + }; - } ()); - - window.Tweenable = Tweenable; - /*! - * All equations are adapted from Thomas Fuchs' [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/penner.js). + /** + * Returns whether or not a tween is running. + * @return {boolean} + */ + Tweenable.prototype.isPlaying = function () { + return this._isTweening && !this._isPaused; + }; + + /** + * Sets a custom schedule function. * - * Based on Easing Equations (c) 2003 [Robert Penner](http://www.robertpenner.com/), all rights reserved. This work is [subject to terms](http://www.robertpenner.com/easing_terms_of_use.html). + * If a custom function is not set the default one is used [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame) if available, otherwise [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout)). + * + * @param {Function(Function,number)} scheduleFunction The function to be called to schedule the next frame to be rendered */ + Tweenable.prototype.setScheduleFunction = function (scheduleFunction) { + this._scheduleFunction = scheduleFunction; + }; + + /** + * `delete`s all "own" properties. Call this when the `Tweenable` instance is no longer needed to free memory. + */ + Tweenable.prototype.dispose = function () { + var prop; + for (prop in this) { + if (this.hasOwnProperty(prop)) { + delete this[prop]; + } + } + }; /*! - * TERMS OF USE - EASING EQUATIONS - * Open source under the BSD License. - * Easing Equations (c) 2003 Robert Penner, all rights reserved. + * Filters are used for transforming the properties of a tween at various + * points in a Tweenable's life cycle. See the README for more info on this. */ + Tweenable.prototype.filter = {}; - ;(function () { - - Tweenable.shallowCopy(Tweenable.prototype.formula, { - easeInQuad: function (pos) { - return Math.pow(pos, 2); - }, - - easeOutQuad: function (pos) { - return -(Math.pow((pos - 1), 2) - 1); - }, - - easeInOutQuad: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,2);} - return -0.5 * ((pos -= 2) * pos - 2); - }, - - easeInCubic: function (pos) { - return Math.pow(pos, 3); - }, - - easeOutCubic: function (pos) { - return (Math.pow((pos - 1), 3) + 1); - }, - - easeInOutCubic: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,3);} - return 0.5 * (Math.pow((pos - 2),3) + 2); - }, - - easeInQuart: function (pos) { - return Math.pow(pos, 4); - }, - - easeOutQuart: function (pos) { - return -(Math.pow((pos - 1), 4) - 1); - }, - - easeInOutQuart: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);} - return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2); - }, - - easeInQuint: function (pos) { - return Math.pow(pos, 5); - }, - - easeOutQuint: function (pos) { - return (Math.pow((pos - 1), 5) + 1); - }, - - easeInOutQuint: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,5);} - return 0.5 * (Math.pow((pos - 2),5) + 2); - }, - - easeInSine: function (pos) { - return -Math.cos(pos * (Math.PI / 2)) + 1; - }, - - easeOutSine: function (pos) { - return Math.sin(pos * (Math.PI / 2)); - }, - - easeInOutSine: function (pos) { - return (-0.5 * (Math.cos(Math.PI * pos) - 1)); - }, - - easeInExpo: function (pos) { - return (pos === 0) ? 0 : Math.pow(2, 10 * (pos - 1)); - }, - - easeOutExpo: function (pos) { - return (pos === 1) ? 1 : -Math.pow(2, -10 * pos) + 1; - }, - - easeInOutExpo: function (pos) { - if (pos === 0) {return 0;} - if (pos === 1) {return 1;} - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(2,10 * (pos - 1));} - return 0.5 * (-Math.pow(2, -10 * --pos) + 2); - }, - - easeInCirc: function (pos) { - return -(Math.sqrt(1 - (pos * pos)) - 1); - }, - - easeOutCirc: function (pos) { - return Math.sqrt(1 - Math.pow((pos - 1), 2)); - }, - - easeInOutCirc: function (pos) { - if ((pos /= 0.5) < 1) {return -0.5 * (Math.sqrt(1 - pos * pos) - 1);} - return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1); - }, - - easeOutBounce: function (pos) { - if ((pos) < (1 / 2.75)) { - return (7.5625 * pos * pos); - } else if (pos < (2 / 2.75)) { - return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); - } else if (pos < (2.5 / 2.75)) { - return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); - } else { - return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); - } - }, - - easeInBack: function (pos) { - var s = 1.70158; - return (pos) * pos * ((s + 1) * pos - s); - }, - - easeOutBack: function (pos) { - var s = 1.70158; - return (pos = pos - 1) * pos * ((s + 1) * pos + s) + 1; - }, - - easeInOutBack: function (pos) { - var s = 1.70158; - if ((pos /= 0.5) < 1) {return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));} - return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2); - }, - - elastic: function (pos) { - return -1 * Math.pow(4,-8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1; - }, - - swingFromTo: function (pos) { - var s = 1.70158; - return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) : - 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2); - }, - - swingFrom: function (pos) { - var s = 1.70158; - return pos * pos * ((s + 1) * pos - s); - }, - - swingTo: function (pos) { - var s = 1.70158; - return (pos -= 1) * pos * ((s + 1) * pos + s) + 1; - }, - - bounce: function (pos) { - if (pos < (1 / 2.75)) { - return (7.5625 * pos * pos); - } else if (pos < (2 / 2.75)) { - return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); - } else if (pos < (2.5 / 2.75)) { - return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); - } else { - return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); - } - }, - - bouncePast: function (pos) { - if (pos < (1 / 2.75)) { - return (7.5625 * pos * pos); - } else if (pos < (2 / 2.75)) { - return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); - } else if (pos < (2.5 / 2.75)) { - return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); - } else { - return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); - } - }, + /*! + * This object contains all of the tweens available to Shifty. It is extendible - simply attach properties to the Tweenable.prototype.formula Object following the same format at linear. + * + * `pos` should be a normalized `number` (between 0 and 1). + */ + Tweenable.prototype.formula = { + linear: function (pos) { + return pos; + } + }; + + formula = Tweenable.prototype.formula; + + shallowCopy(Tweenable, { + 'now': now + ,'each': each + ,'tweenProps': tweenProps + ,'tweenProp': tweenProp + ,'applyFilter': applyFilter + ,'shallowCopy': shallowCopy + ,'defaults': defaults + ,'composeEasingObject': composeEasingObject + }); + + // `root` is provided in the intro/outro files. - easeFromTo: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);} - return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2); - }, + // A hook used for unit testing. + if (typeof SHIFTY_DEBUG_NOW === 'function') { + root.timeoutHandler = timeoutHandler; + } + + // Bootstrap Tweenable appropriately for the environment. + if (typeof exports === 'object') { + // CommonJS + module.exports = Tweenable; + } else if (typeof define === 'function' && define.amd) { + // AMD + define(function () {return Tweenable;}); + } else if (typeof root.Tweenable === 'undefined') { + // Browser: Make `Tweenable` globally accessible. + root.Tweenable = Tweenable; + } - easeFrom: function (pos) { - return Math.pow(pos,4); - }, + return Tweenable; - easeTo: function (pos) { - return Math.pow(pos,0.25); + } ()); + + /*! + * All equations are adapted from Thomas Fuchs' [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/penner.js). + * + * Based on Easing Equations (c) 2003 [Robert Penner](http://www.robertpenner.com/), all rights reserved. This work is [subject to terms](http://www.robertpenner.com/easing_terms_of_use.html). + */ + + /*! + * TERMS OF USE - EASING EQUATIONS + * Open source under the BSD License. + * Easing Equations (c) 2003 Robert Penner, all rights reserved. + */ + + ;(function () { + + Tweenable.shallowCopy(Tweenable.prototype.formula, { + easeInQuad: function (pos) { + return Math.pow(pos, 2); + }, + + easeOutQuad: function (pos) { + return -(Math.pow((pos - 1), 2) - 1); + }, + + easeInOutQuad: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,2);} + return -0.5 * ((pos -= 2) * pos - 2); + }, + + easeInCubic: function (pos) { + return Math.pow(pos, 3); + }, + + easeOutCubic: function (pos) { + return (Math.pow((pos - 1), 3) + 1); + }, + + easeInOutCubic: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,3);} + return 0.5 * (Math.pow((pos - 2),3) + 2); + }, + + easeInQuart: function (pos) { + return Math.pow(pos, 4); + }, + + easeOutQuart: function (pos) { + return -(Math.pow((pos - 1), 4) - 1); + }, + + easeInOutQuart: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);} + return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2); + }, + + easeInQuint: function (pos) { + return Math.pow(pos, 5); + }, + + easeOutQuint: function (pos) { + return (Math.pow((pos - 1), 5) + 1); + }, + + easeInOutQuint: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,5);} + return 0.5 * (Math.pow((pos - 2),5) + 2); + }, + + easeInSine: function (pos) { + return -Math.cos(pos * (Math.PI / 2)) + 1; + }, + + easeOutSine: function (pos) { + return Math.sin(pos * (Math.PI / 2)); + }, + + easeInOutSine: function (pos) { + return (-0.5 * (Math.cos(Math.PI * pos) - 1)); + }, + + easeInExpo: function (pos) { + return (pos === 0) ? 0 : Math.pow(2, 10 * (pos - 1)); + }, + + easeOutExpo: function (pos) { + return (pos === 1) ? 1 : -Math.pow(2, -10 * pos) + 1; + }, + + easeInOutExpo: function (pos) { + if (pos === 0) {return 0;} + if (pos === 1) {return 1;} + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(2,10 * (pos - 1));} + return 0.5 * (-Math.pow(2, -10 * --pos) + 2); + }, + + easeInCirc: function (pos) { + return -(Math.sqrt(1 - (pos * pos)) - 1); + }, + + easeOutCirc: function (pos) { + return Math.sqrt(1 - Math.pow((pos - 1), 2)); + }, + + easeInOutCirc: function (pos) { + if ((pos /= 0.5) < 1) {return -0.5 * (Math.sqrt(1 - pos * pos) - 1);} + return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1); + }, + + easeOutBounce: function (pos) { + if ((pos) < (1 / 2.75)) { + return (7.5625 * pos * pos); + } else if (pos < (2 / 2.75)) { + return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); + } else if (pos < (2.5 / 2.75)) { + return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); + } else { + return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); } - }); + }, + + easeInBack: function (pos) { + var s = 1.70158; + return (pos) * pos * ((s + 1) * pos - s); + }, + + easeOutBack: function (pos) { + var s = 1.70158; + return (pos = pos - 1) * pos * ((s + 1) * pos + s) + 1; + }, + + easeInOutBack: function (pos) { + var s = 1.70158; + if ((pos /= 0.5) < 1) {return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));} + return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2); + }, + + elastic: function (pos) { + return -1 * Math.pow(4,-8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1; + }, + + swingFromTo: function (pos) { + var s = 1.70158; + return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) : + 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2); + }, + + swingFrom: function (pos) { + var s = 1.70158; + return pos * pos * ((s + 1) * pos - s); + }, + + swingTo: function (pos) { + var s = 1.70158; + return (pos -= 1) * pos * ((s + 1) * pos + s) + 1; + }, + + bounce: function (pos) { + if (pos < (1 / 2.75)) { + return (7.5625 * pos * pos); + } else if (pos < (2 / 2.75)) { + return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); + } else if (pos < (2.5 / 2.75)) { + return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); + } else { + return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); + } + }, + + bouncePast: function (pos) { + if (pos < (1 / 2.75)) { + return (7.5625 * pos * pos); + } else if (pos < (2 / 2.75)) { + return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); + } else if (pos < (2.5 / 2.75)) { + return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); + } else { + return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); + } + }, - }()); + easeFromTo: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);} + return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2); + }, - /*! - * The Bezier magic in this file is adapted/copied almost wholesale from - * [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/cubic-bezier.js), - * which was adapted from Apple code (which probably came from - * [here](http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h)). - * Special thanks to Apple and Thomas Fuchs for much of this code. - */ + easeFrom: function (pos) { + return Math.pow(pos,4); + }, + easeTo: function (pos) { + return Math.pow(pos,0.25); + } + }); + + }()); + + /*! + * The Bezier magic in this file is adapted/copied almost wholesale from + * [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/cubic-bezier.js), + * which was adapted from Apple code (which probably came from + * [here](http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h)). + * Special thanks to Apple and Thomas Fuchs for much of this code. + */ + + /*! + * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder(s) nor the names of any + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ;(function () { + // port of webkit cubic bezier handling by http://www.netzgesta.de/dev/ + function cubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration) { + var ax = 0,bx = 0,cx = 0,ay = 0,by = 0,cy = 0; + function sampleCurveX(t) {return ((ax * t + bx) * t + cx) * t;} + function sampleCurveY(t) {return ((ay * t + by) * t + cy) * t;} + function sampleCurveDerivativeX(t) {return (3.0 * ax * t + 2.0 * bx) * t + cx;} + function solveEpsilon(duration) {return 1.0 / (200.0 * duration);} + function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));} + function fabs(n) {if (n >= 0) {return n;}else {return 0 - n;}} + function solveCurveX(x,epsilon) { + var t0,t1,t2,x2,d2,i; + for (t2 = x, i = 0; i < 8; i++) {x2 = sampleCurveX(t2) - x; if (fabs(x2) < epsilon) {return t2;} d2 = sampleCurveDerivativeX(t2); if (fabs(d2) < 1e-6) {break;} t2 = t2 - x2 / d2;} + t0 = 0.0; t1 = 1.0; t2 = x; if (t2 < t0) {return t0;} if (t2 > t1) {return t1;} + while (t0 < t1) {x2 = sampleCurveX(t2); if (fabs(x2 - x) < epsilon) {return t2;} if (x > x2) {t0 = t2;}else {t1 = t2;} t2 = (t1 - t0) * 0.5 + t0;} + return t2; // Failure. + } + cx = 3.0 * p1x; bx = 3.0 * (p2x - p1x) - cx; ax = 1.0 - cx - bx; cy = 3.0 * p1y; by = 3.0 * (p2y - p1y) - cy; ay = 1.0 - cy - by; + return solve(t, solveEpsilon(duration)); + } /*! - * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * getCubicBezierTransition(x1, y1, x2, y2) -> Function * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * Generates a transition easing function that is compatible + * with WebKit's CSS transitions `-webkit-transition-timing-function` + * CSS property. * - * 3. Neither the name of the copyright holder(s) nor the names of any - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * The W3C has more information about + * + * CSS3 transition timing functions. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @return {function} */ - ;(function () { - // port of webkit cubic bezier handling by http://www.netzgesta.de/dev/ - function cubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration) { - var ax = 0,bx = 0,cx = 0,ay = 0,by = 0,cy = 0; - function sampleCurveX(t) {return ((ax * t + bx) * t + cx) * t;} - function sampleCurveY(t) {return ((ay * t + by) * t + cy) * t;} - function sampleCurveDerivativeX(t) {return (3.0 * ax * t + 2.0 * bx) * t + cx;} - function solveEpsilon(duration) {return 1.0 / (200.0 * duration);} - function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));} - function fabs(n) {if (n >= 0) {return n;}else {return 0 - n;}} - function solveCurveX(x,epsilon) { - var t0,t1,t2,x2,d2,i; - for (t2 = x, i = 0; i < 8; i++) {x2 = sampleCurveX(t2) - x; if (fabs(x2) < epsilon) {return t2;} d2 = sampleCurveDerivativeX(t2); if (fabs(d2) < 1e-6) {break;} t2 = t2 - x2 / d2;} - t0 = 0.0; t1 = 1.0; t2 = x; if (t2 < t0) {return t0;} if (t2 > t1) {return t1;} - while (t0 < t1) {x2 = sampleCurveX(t2); if (fabs(x2 - x) < epsilon) {return t2;} if (x > x2) {t0 = t2;}else {t1 = t2;} t2 = (t1 - t0) * 0.5 + t0;} - return t2; // Failure. - } - cx = 3.0 * p1x; bx = 3.0 * (p2x - p1x) - cx; ax = 1.0 - cx - bx; cy = 3.0 * p1y; by = 3.0 * (p2y - p1y) - cy; ay = 1.0 - cy - by; - return solve(t, solveEpsilon(duration)); - } - /*! - * getCubicBezierTransition(x1, y1, x2, y2) -> Function - * - * Generates a transition easing function that is compatible - * with WebKit's CSS transitions `-webkit-transition-timing-function` - * CSS property. - * - * The W3C has more information about - * - * CSS3 transition timing functions. - * - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @return {function} - */ - function getCubicBezierTransition (x1, y1, x2, y2) { - return function (pos) { - return cubicBezierAtTime(pos,x1,y1,x2,y2,1); - }; - } - // End ported code - - /** - * Creates a Bezier easing function and attaches it to `Tweenable.prototype.formula`. This function gives you total control over the easing curve. Matthew Lein's [Ceaser](http://matthewlein.com/ceaser/) is a useful tool for visualizing the curves you can make with this function. - * - * @param {string} name The name of the easing curve. Overwrites the old easing function on Tweenable.prototype.formula if it exists. - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @return {function} The easing function that was attached to Tweenable.prototype.formula. - */ - Tweenable.setBezierFunction = function (name, x1, y1, x2, y2) { - var cubicBezierTransition = getCubicBezierTransition(x1, y1, x2, y2); - cubicBezierTransition.x1 = x1; - cubicBezierTransition.y1 = y1; - cubicBezierTransition.x2 = x2; - cubicBezierTransition.y2 = y2; - - return Tweenable.prototype.formula[name] = cubicBezierTransition; + function getCubicBezierTransition (x1, y1, x2, y2) { + return function (pos) { + return cubicBezierAtTime(pos,x1,y1,x2,y2,1); }; + } + // End ported code + /** + * Creates a Bezier easing function and attaches it to `Tweenable.prototype.formula`. This function gives you total control over the easing curve. Matthew Lein's [Ceaser](http://matthewlein.com/ceaser/) is a useful tool for visualizing the curves you can make with this function. + * + * @param {string} name The name of the easing curve. Overwrites the old easing function on Tweenable.prototype.formula if it exists. + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @return {function} The easing function that was attached to Tweenable.prototype.formula. + */ + Tweenable.setBezierFunction = function (name, x1, y1, x2, y2) { + var cubicBezierTransition = getCubicBezierTransition(x1, y1, x2, y2); + cubicBezierTransition.x1 = x1; + cubicBezierTransition.y1 = y1; + cubicBezierTransition.x2 = x2; + cubicBezierTransition.y2 = y2; - /** - * `delete`s an easing function from `Tweenable.prototype.formula`. Be careful with this method, as it `delete`s whatever easing formula matches `name` (which means you can delete default Shifty easing functions). - * - * @param {string} name The name of the easing function to delete. - * @return {function} - */ - Tweenable.unsetBezierFunction = function (name) { - delete Tweenable.prototype.formula[name]; - }; + return Tweenable.prototype.formula[name] = cubicBezierTransition; + }; - })(); - ;(function () { + /** + * `delete`s an easing function from `Tweenable.prototype.formula`. Be careful with this method, as it `delete`s whatever easing formula matches `name` (which means you can delete default Shifty easing functions). + * + * @param {string} name The name of the easing function to delete. + * @return {function} + */ + Tweenable.unsetBezierFunction = function (name) { + delete Tweenable.prototype.formula[name]; + }; - function getInterpolatedValues ( - from, current, targetState, position, easing) { - return Tweenable.tweenProps( - position, current, from, targetState, 1, 0, easing); - } + })(); - // Fake a Tweenable and patch some internals. This approach allows us to - // skip uneccessary processing and object recreation, cutting down on garbage - // collection pauses. - var mockTweenable = new Tweenable(); - mockTweenable._filterArgs = []; - - /** - * Compute the midpoint of two Objects. This method effectively calculates a specific frame of animation that [Tweenable#tween](shifty.core.js.html#tween) does many times over the course of a tween. - * - * Example: - * - * ``` - * var interpolatedValues = Tweenable.interpolate({ - * width: '100px', - * opacity: 0, - * color: '#fff' - * }, { - * width: '200px', - * opacity: 1, - * color: '#000' - * }, 0.5); - * - * console.log(interpolatedValues); - * // {opacity: 0.5, width: "150px", color: "rgb(127,127,127)"} - * ``` - * - * @param {Object} from The starting values to tween from. - * @param {Object} targetState The ending values to tween to. - * @param {number} position The normalized position value (between 0.0 and 1.0) to interpolate the values between `from` and `to` for. `from` represents 0 and `to` represents `1`. - * @param {string|Object} easing The easing curve(s) to calculate the midpoint against. You can reference any easing function attached to `Tweenable.prototype.formula`. If omitted, this defaults to "linear". - * @return {Object} - */ - Tweenable.interpolate = function (from, targetState, position, easing) { - var current = Tweenable.shallowCopy({}, from); - var easingObject = Tweenable.composeEasingObject( - from, easing || 'linear'); - - mockTweenable.set({}); - - // Alias and reuse the _filterArgs array instead of recreating it. - var filterArgs = mockTweenable._filterArgs; - filterArgs.length = 0; - filterArgs[0] = current; - filterArgs[1] = from; - filterArgs[2] = targetState; - filterArgs[3] = easingObject; - - // Any defined value transformation must be applied - Tweenable.applyFilter(mockTweenable, 'tweenCreated'); - Tweenable.applyFilter(mockTweenable, 'beforeTween'); - - var interpolatedValues = getInterpolatedValues( - from, current, targetState, position, easingObject); - - // Transform values back into their original format - Tweenable.applyFilter(mockTweenable, 'afterTween'); - - return interpolatedValues; - }; + ;(function () { + + function getInterpolatedValues ( + from, current, targetState, position, easing) { + return Tweenable.tweenProps( + position, current, from, targetState, 1, 0, easing); + } - }()); + // Fake a Tweenable and patch some internals. This approach allows us to + // skip uneccessary processing and object recreation, cutting down on garbage + // collection pauses. + var mockTweenable = new Tweenable(); + mockTweenable._filterArgs = []; /** - * Adds string interpolation support to Shifty. - * - * The Token extension allows Shifty to tween numbers inside of strings. Among other things, this allows you to animate CSS properties. For example, you can do this: - * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { transform: 'translateX(45px)'}, - * to: { transform: 'translateX(90xp)'} - * }); - * ``` - * - * `translateX(45)` will be tweened to `translateX(90)`. To demonstrate: - * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { transform: 'translateX(45px)'}, - * to: { transform: 'translateX(90px)'}, - * step: function (state) { - * console.log(state.transform); - * } - * }); - * ``` - * - * The above snippet will log something like this in the console: - * - * ``` - * translateX(60.3px) - * ... - * translateX(76.05px) - * ... - * translateX(90px) - * ``` - * - * Another use for this is animating colors: - * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { color: 'rgb(0,255,0)'}, - * to: { color: 'rgb(255,0,255)'}, - * step: function (state) { - * console.log(state.color); - * } - * }); - * ``` - * - * The above snippet will log something like this: - * - * ``` - * rgb(84,170,84) - * ... - * rgb(170,84,170) - * ... - * rgb(255,0,255) - * ``` - * - * This extension also supports hexadecimal colors, in both long (`#ff00ff`) and short (`#f0f`) forms. Be aware that hexadecimal input values will be converted into the equivalent RGB output values. This is done to optimize for performance. - * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { color: '#0f0'}, - * to: { color: '#f0f'}, - * step: function (state) { - * console.log(state.color); - * } - * }); - * ``` - * - * This snippet will generate the same output as the one before it because equivalent values were supplied (just in hexadecimal form rather than RGB): - * - * ``` - * rgb(84,170,84) - * ... - * rgb(170,84,170) - * ... - * rgb(255,0,255) - * ``` - * - * ## Easing support - * - * Easing works somewhat differently in the Token extension. This is because some CSS properties have multiple values in them, and you might need to tween each value along its own easing curve. A basic example: - * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { transform: 'translateX(0px) translateY(0px)'}, - * to: { transform: 'translateX(100px) translateY(100px)'}, - * easing: { transform: 'easeInQuad' }, - * step: function (state) { - * console.log(state.transform); - * } - * }); - * ``` + * Compute the midpoint of two Objects. This method effectively calculates a specific frame of animation that [Tweenable#tween](shifty.core.js.html#tween) does many times over the course of a tween. * - * The above snippet create values like this: + * Example: * - * ``` - * translateX(11.560000000000002px) translateY(11.560000000000002px) - * ... - * translateX(46.24000000000001px) translateY(46.24000000000001px) - * ... - * translateX(100px) translateY(100px) - * ``` + * var interpolatedValues = Tweenable.interpolate({ + * width: '100px', + * opacity: 0, + * color: '#fff' + * }, { + * width: '200px', + * opacity: 1, + * color: '#000' + * }, 0.5); * - * In this case, the values for `translateX` and `translateY` are always the same for each step of the tween, because they have the same start and end points and both use the same easing curve. We can also tween `translateX` and `translateY` along independent curves: + * console.log(interpolatedValues); + * // {opacity: 0.5, width: "150px", color: "rgb(127,127,127)"} * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { transform: 'translateX(0px) translateY(0px)'}, - * to: { transform: 'translateX(100px) translateY(100px)'}, - * easing: { transform: 'easeInQuad bounce' }, - * step: function (state) { - * console.log(state.transform); - * } - * }); - * ``` - * - * The above snippet create values like this: - * - * ``` - * translateX(10.89px) translateY(82.355625px) - * ... - * translateX(44.89000000000001px) translateY(86.73062500000002px) - * ... - * translateX(100px) translateY(100px) - * ``` - * - * `translateX` and `translateY` are not in sync anymore, because `easeInQuad` was specified for `translateX` and `bounce` for `translateY`. Mixing and matching easing curves can make for some interesting motion in your animations. - * - * The order of the space-separated easing curves correspond the token values they apply to. If there are more token values than easing curves listed, the last easing curve listed is used. + * @param {Object} from The starting values to tween from. + * @param {Object} targetState The ending values to tween to. + * @param {number} position The normalized position value (between 0.0 and 1.0) to interpolate the values between `from` and `to` for. `from` represents 0 and `to` represents `1`. + * @param {string|Object} easing The easing curve(s) to calculate the midpoint against. You can reference any easing function attached to `Tweenable.prototype.formula`. If omitted, this defaults to "linear". + * @return {Object} */ - function token () { - // Functionality for this extension runs implicitly if it is loaded. - } /*!*/ - - // token function is defined above only so that dox-foundation sees it as - // documentation and renders it. It is never used, and is optimized away at - // build time. - - ;(function (Tweenable) { - - /*! - * @typedef {{ - * formatString: string - * chunkNames: Array. - * }} - */ - var formatManifest; - - // CONSTANTS - - var R_NUMBER_COMPONENT = /(\d|\-|\.)/; - var R_FORMAT_CHUNKS = /([^\-0-9\.]+)/g; - var R_UNFORMATTED_VALUES = /[0-9.\-]+/g; - var R_RGB = new RegExp( - 'rgb\\(' + R_UNFORMATTED_VALUES.source + - (/,\s*/.source) + R_UNFORMATTED_VALUES.source + - (/,\s*/.source) + R_UNFORMATTED_VALUES.source + '\\)', 'g'); - var R_RGB_PREFIX = /^.*\(/; - var R_HEX = /#([0-9]|[a-f]){3,6}/gi; - var VALUE_PLACEHOLDER = 'VAL'; - - // HELPERS - - var getFormatChunksFrom_accumulator = []; - /*! - * @param {Array.number} rawValues - * @param {string} prefix - * - * @return {Array.} - */ - function getFormatChunksFrom (rawValues, prefix) { - getFormatChunksFrom_accumulator.length = 0; + Tweenable.interpolate = function (from, targetState, position, easing) { + var current = Tweenable.shallowCopy({}, from); + var easingObject = Tweenable.composeEasingObject( + from, easing || 'linear'); + + mockTweenable.set({}); + + // Alias and reuse the _filterArgs array instead of recreating it. + var filterArgs = mockTweenable._filterArgs; + filterArgs.length = 0; + filterArgs[0] = current; + filterArgs[1] = from; + filterArgs[2] = targetState; + filterArgs[3] = easingObject; + + // Any defined value transformation must be applied + Tweenable.applyFilter(mockTweenable, 'tweenCreated'); + Tweenable.applyFilter(mockTweenable, 'beforeTween'); + + var interpolatedValues = getInterpolatedValues( + from, current, targetState, position, easingObject); + + // Transform values back into their original format + Tweenable.applyFilter(mockTweenable, 'afterTween'); + + return interpolatedValues; + }; + + }()); + + /** + * Adds string interpolation support to Shifty. + * + * The Token extension allows Shifty to tween numbers inside of strings. Among + * other things, this allows you to animate CSS properties. For example, you + * can do this: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { transform: 'translateX(45px)'}, + * to: { transform: 'translateX(90xp)'} + * }); + * + * ` ` + * `translateX(45)` will be tweened to `translateX(90)`. To demonstrate: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { transform: 'translateX(45px)'}, + * to: { transform: 'translateX(90px)'}, + * step: function (state) { + * console.log(state.transform); + * } + * }); + * + * ` ` + * The above snippet will log something like this in the console: + * + * translateX(60.3px) + * ... + * translateX(76.05px) + * ... + * translateX(90px) + * + * ` ` + * Another use for this is animating colors: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { color: 'rgb(0,255,0)'}, + * to: { color: 'rgb(255,0,255)'}, + * step: function (state) { + * console.log(state.color); + * } + * }); + * + * ` ` + * The above snippet will log something like this: + * + * rgb(84,170,84) + * ... + * rgb(170,84,170) + * ... + * rgb(255,0,255) + * + * ` ` + * This extension also supports hexadecimal colors, in both long (`#ff00ff`) + * and short (`#f0f`) forms. Be aware that hexadecimal input values will be + * converted into the equivalent RGB output values. This is done to optimize + * for performance. + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { color: '#0f0'}, + * to: { color: '#f0f'}, + * step: function (state) { + * console.log(state.color); + * } + * }); + * + * ` ` + * This snippet will generate the same output as the one before it because + * equivalent values were supplied (just in hexadecimal form rather than RGB): + * + * rgb(84,170,84) + * ... + * rgb(170,84,170) + * ... + * rgb(255,0,255) + * + * ` ` + * ` ` + * ## Easing support + * + * Easing works somewhat differently in the Token extension. This is because + * some CSS properties have multiple values in them, and you might need to + * tween each value along its own easing curve. A basic example: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { transform: 'translateX(0px) translateY(0px)'}, + * to: { transform: 'translateX(100px) translateY(100px)'}, + * easing: { transform: 'easeInQuad' }, + * step: function (state) { + * console.log(state.transform); + * } + * }); + * + * ` ` + * The above snippet create values like this: + * + * translateX(11.560000000000002px) translateY(11.560000000000002px) + * ... + * translateX(46.24000000000001px) translateY(46.24000000000001px) + * ... + * translateX(100px) translateY(100px) + * + * ` ` + * In this case, the values for `translateX` and `translateY` are always the + * same for each step of the tween, because they have the same start and end + * points and both use the same easing curve. We can also tween `translateX` + * and `translateY` along independent curves: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { transform: 'translateX(0px) translateY(0px)'}, + * to: { transform: 'translateX(100px) translateY(100px)'}, + * easing: { transform: 'easeInQuad bounce' }, + * step: function (state) { + * console.log(state.transform); + * } + * }); + * + * ` ` + * The above snippet create values like this: + * + * translateX(10.89px) translateY(82.355625px) + * ... + * translateX(44.89000000000001px) translateY(86.73062500000002px) + * ... + * translateX(100px) translateY(100px) + * + * ` ` + * `translateX` and `translateY` are not in sync anymore, because `easeInQuad` + * was specified for `translateX` and `bounce` for `translateY`. Mixing and + * matching easing curves can make for some interesting motion in your + * animations. + * + * The order of the space-separated easing curves correspond the token values + * they apply to. If there are more token values than easing curves listed, + * the last easing curve listed is used. + */ + function token () { + // Functionality for this extension runs implicitly if it is loaded. + } /*!*/ + + // token function is defined above only so that dox-foundation sees it as + // documentation and renders it. It is never used, and is optimized away at + // build time. + + ;(function (Tweenable) { - var rawValuesLength = rawValues.length; - var i; + /*! + * @typedef {{ + * formatString: string + * chunkNames: Array. + * }} + */ + var formatManifest; - for (i = 0; i < rawValuesLength; i++) { - getFormatChunksFrom_accumulator.push('_' + prefix + '_' + i); - } + // CONSTANTS - return getFormatChunksFrom_accumulator; - } + var R_NUMBER_COMPONENT = /(\d|\-|\.)/; + var R_FORMAT_CHUNKS = /([^\-0-9\.]+)/g; + var R_UNFORMATTED_VALUES = /[0-9.\-]+/g; + var R_RGB = new RegExp( + 'rgb\\(' + R_UNFORMATTED_VALUES.source + + (/,\s*/.source) + R_UNFORMATTED_VALUES.source + + (/,\s*/.source) + R_UNFORMATTED_VALUES.source + '\\)', 'g'); + var R_RGB_PREFIX = /^.*\(/; + var R_HEX = /#([0-9]|[a-f]){3,6}/gi; + var VALUE_PLACEHOLDER = 'VAL'; - /*! - * @param {string} formattedString - * - * @return {string} - */ - function getFormatStringFrom (formattedString) { - var chunks = formattedString.match(R_FORMAT_CHUNKS); - - if (!chunks) { - // chunks will be null if there were no tokens to parse in - // formattedString (for example, if formattedString is '2'). Coerce - // chunks to be useful here. - chunks = ['', '']; - - // If there is only one chunk, assume that the string is a number - // followed by a token... - // NOTE: This may be an unwise assumption. - } else if (chunks.length === 1 || - // ...or if the string starts with a number component (".", "-", or a - // digit)... - formattedString[0].match(R_NUMBER_COMPONENT)) { - // ...prepend an empty string here to make sure that the formatted number - // is properly replaced by VALUE_PLACEHOLDER - chunks.unshift(''); - } + // HELPERS - return chunks.join(VALUE_PLACEHOLDER); - } + var getFormatChunksFrom_accumulator = []; + /*! + * @param {Array.number} rawValues + * @param {string} prefix + * + * @return {Array.} + */ + function getFormatChunksFrom (rawValues, prefix) { + getFormatChunksFrom_accumulator.length = 0; - /*! - * Convert all hex color values within a string to an rgb string. - * - * @param {Object} stateObject - * - * @return {Object} The modified obj - */ - function sanitizeObjectForHexProps (stateObject) { - Tweenable.each(stateObject, function (prop) { - var currentProp = stateObject[prop]; - - if (typeof currentProp === 'string' && currentProp.match(R_HEX)) { - stateObject[prop] = sanitizeHexChunksToRGB(currentProp); - } - }); - } + var rawValuesLength = rawValues.length; + var i; - /*! - * @param {string} str - * - * @return {string} - */ - function sanitizeHexChunksToRGB (str) { - return filterStringChunks(R_HEX, str, convertHexToRGB); + for (i = 0; i < rawValuesLength; i++) { + getFormatChunksFrom_accumulator.push('_' + prefix + '_' + i); } - /*! - * @param {string} hexString - * - * @return {string} - */ - function convertHexToRGB (hexString) { - var rgbArr = hexToRGBArray(hexString); - return 'rgb(' + rgbArr[0] + ',' + rgbArr[1] + ',' + rgbArr[2] + ')'; + return getFormatChunksFrom_accumulator; + } + + /*! + * @param {string} formattedString + * + * @return {string} + */ + function getFormatStringFrom (formattedString) { + var chunks = formattedString.match(R_FORMAT_CHUNKS); + + if (!chunks) { + // chunks will be null if there were no tokens to parse in + // formattedString (for example, if formattedString is '2'). Coerce + // chunks to be useful here. + chunks = ['', '']; + + // If there is only one chunk, assume that the string is a number + // followed by a token... + // NOTE: This may be an unwise assumption. + } else if (chunks.length === 1 || + // ...or if the string starts with a number component (".", "-", or a + // digit)... + formattedString[0].match(R_NUMBER_COMPONENT)) { + // ...prepend an empty string here to make sure that the formatted number + // is properly replaced by VALUE_PLACEHOLDER + chunks.unshift(''); } - var hexToRGBArray_returnArray = []; - /*! - * Convert a hexadecimal string to an array with three items, one each for - * the red, blue, and green decimal values. - * - * @param {string} hex A hexadecimal string. - * - * @returns {Array.} The converted Array of RGB values if `hex` is a - * valid string, or an Array of three 0's. - */ - function hexToRGBArray (hex) { - - hex = hex.replace(/#/, ''); - - // If the string is a shorthand three digit hex notation, normalize it to - // the standard six digit notation - if (hex.length === 3) { - hex = hex.split(''); - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + return chunks.join(VALUE_PLACEHOLDER); + } + + /*! + * Convert all hex color values within a string to an rgb string. + * + * @param {Object} stateObject + * + * @return {Object} The modified obj + */ + function sanitizeObjectForHexProps (stateObject) { + Tweenable.each(stateObject, function (prop) { + var currentProp = stateObject[prop]; + + if (typeof currentProp === 'string' && currentProp.match(R_HEX)) { + stateObject[prop] = sanitizeHexChunksToRGB(currentProp); } + }); + } - hexToRGBArray_returnArray[0] = hexToDec(hex.substr(0, 2)); - hexToRGBArray_returnArray[1] = hexToDec(hex.substr(2, 2)); - hexToRGBArray_returnArray[2] = hexToDec(hex.substr(4, 2)); + /*! + * @param {string} str + * + * @return {string} + */ + function sanitizeHexChunksToRGB (str) { + return filterStringChunks(R_HEX, str, convertHexToRGB); + } - return hexToRGBArray_returnArray; - } + /*! + * @param {string} hexString + * + * @return {string} + */ + function convertHexToRGB (hexString) { + var rgbArr = hexToRGBArray(hexString); + return 'rgb(' + rgbArr[0] + ',' + rgbArr[1] + ',' + rgbArr[2] + ')'; + } - /*! - * Convert a base-16 number to base-10. - * - * @param {Number|String} hex The value to convert - * - * @returns {Number} The base-10 equivalent of `hex`. - */ - function hexToDec (hex) { - return parseInt(hex, 16); - } + var hexToRGBArray_returnArray = []; + /*! + * Convert a hexadecimal string to an array with three items, one each for + * the red, blue, and green decimal values. + * + * @param {string} hex A hexadecimal string. + * + * @returns {Array.} The converted Array of RGB values if `hex` is a + * valid string, or an Array of three 0's. + */ + function hexToRGBArray (hex) { - /*! - * Runs a filter operation on all chunks of a string that match a RegExp - * - * @param {RegExp} pattern - * @param {string} unfilteredString - * @param {function(string)} filter - * - * @return {string} - */ - function filterStringChunks (pattern, unfilteredString, filter) { - var pattenMatches = unfilteredString.match(pattern); - var filteredString = unfilteredString.replace(pattern, VALUE_PLACEHOLDER); - - if (pattenMatches) { - var pattenMatchesLength = pattenMatches.length; - var currentChunk; - - for (var i = 0; i < pattenMatchesLength; i++) { - currentChunk = pattenMatches.shift(); - filteredString = filteredString.replace( - VALUE_PLACEHOLDER, filter(currentChunk)); - } - } + hex = hex.replace(/#/, ''); - return filteredString; + // If the string is a shorthand three digit hex notation, normalize it to + // the standard six digit notation + if (hex.length === 3) { + hex = hex.split(''); + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } - /*! - * Check for floating point values within rgb strings and rounds them. - * - * @param {string} formattedString - * - * @return {string} - */ - function sanitizeRGBChunks (formattedString) { - return filterStringChunks(R_RGB, formattedString, sanitizeRGBChunk); - } + hexToRGBArray_returnArray[0] = hexToDec(hex.substr(0, 2)); + hexToRGBArray_returnArray[1] = hexToDec(hex.substr(2, 2)); + hexToRGBArray_returnArray[2] = hexToDec(hex.substr(4, 2)); - /*! - * @param {string} rgbChunk - * - * @return {string} - */ - function sanitizeRGBChunk (rgbChunk) { - var numbers = rgbChunk.match(R_UNFORMATTED_VALUES); - var numbersLength = numbers.length; - var sanitizedString = rgbChunk.match(R_RGB_PREFIX)[0]; - - for (var i = 0; i < numbersLength; i++) { - sanitizedString += parseInt(numbers[i], 10) + ','; - } + return hexToRGBArray_returnArray; + } - sanitizedString = sanitizedString.slice(0, -1) + ')'; + /*! + * Convert a base-16 number to base-10. + * + * @param {Number|String} hex The value to convert + * + * @returns {Number} The base-10 equivalent of `hex`. + */ + function hexToDec (hex) { + return parseInt(hex, 16); + } - return sanitizedString; + /*! + * Runs a filter operation on all chunks of a string that match a RegExp + * + * @param {RegExp} pattern + * @param {string} unfilteredString + * @param {function(string)} filter + * + * @return {string} + */ + function filterStringChunks (pattern, unfilteredString, filter) { + var pattenMatches = unfilteredString.match(pattern); + var filteredString = unfilteredString.replace(pattern, VALUE_PLACEHOLDER); + + if (pattenMatches) { + var pattenMatchesLength = pattenMatches.length; + var currentChunk; + + for (var i = 0; i < pattenMatchesLength; i++) { + currentChunk = pattenMatches.shift(); + filteredString = filteredString.replace( + VALUE_PLACEHOLDER, filter(currentChunk)); + } } - /*! - * @param {Object} stateObject - * - * @return {Object} An Object of formatManifests that correspond to - * the string properties of stateObject - */ - function getFormatManifests (stateObject) { - var manifestAccumulator = {}; - - Tweenable.each(stateObject, function (prop) { - var currentProp = stateObject[prop]; + return filteredString; + } - if (typeof currentProp === 'string') { - var rawValues = getValuesFrom(currentProp); + /*! + * Check for floating point values within rgb strings and rounds them. + * + * @param {string} formattedString + * + * @return {string} + */ + function sanitizeRGBChunks (formattedString) { + return filterStringChunks(R_RGB, formattedString, sanitizeRGBChunk); + } - manifestAccumulator[prop] = { - 'formatString': getFormatStringFrom(currentProp) - ,'chunkNames': getFormatChunksFrom(rawValues, prop) - }; - } - }); + /*! + * @param {string} rgbChunk + * + * @return {string} + */ + function sanitizeRGBChunk (rgbChunk) { + var numbers = rgbChunk.match(R_UNFORMATTED_VALUES); + var numbersLength = numbers.length; + var sanitizedString = rgbChunk.match(R_RGB_PREFIX)[0]; - return manifestAccumulator; + for (var i = 0; i < numbersLength; i++) { + sanitizedString += parseInt(numbers[i], 10) + ','; } - /*! - * @param {Object} stateObject - * @param {Object} formatManifests - */ - function expandFormattedProperties (stateObject, formatManifests) { - Tweenable.each(formatManifests, function (prop) { - var currentProp = stateObject[prop]; - var rawValues = getValuesFrom(currentProp); - var rawValuesLength = rawValues.length; - - for (var i = 0; i < rawValuesLength; i++) { - stateObject[formatManifests[prop].chunkNames[i]] = +rawValues[i]; - } + sanitizedString = sanitizedString.slice(0, -1) + ')'; - delete stateObject[prop]; - }); - } + return sanitizedString; + } - /*! - * @param {Object} stateObject - * @param {Object} formatManifests - */ - function collapseFormattedProperties (stateObject, formatManifests) { - Tweenable.each(formatManifests, function (prop) { - var currentProp = stateObject[prop]; - var formatChunks = extractPropertyChunks( - stateObject, formatManifests[prop].chunkNames); - var valuesList = getValuesList( - formatChunks, formatManifests[prop].chunkNames); - currentProp = getFormattedValues( - formatManifests[prop].formatString, valuesList); - stateObject[prop] = sanitizeRGBChunks(currentProp); - }); - } + /*! + * @param {Object} stateObject + * + * @return {Object} An Object of formatManifests that correspond to + * the string properties of stateObject + */ + function getFormatManifests (stateObject) { + var manifestAccumulator = {}; - /*! - * @param {Object} stateObject - * @param {Array.} chunkNames - * - * @return {Object} The extracted value chunks. - */ - function extractPropertyChunks (stateObject, chunkNames) { - var extractedValues = {}; - var currentChunkName, chunkNamesLength = chunkNames.length; - - for (var i = 0; i < chunkNamesLength; i++) { - currentChunkName = chunkNames[i]; - extractedValues[currentChunkName] = stateObject[currentChunkName]; - delete stateObject[currentChunkName]; - } + Tweenable.each(stateObject, function (prop) { + var currentProp = stateObject[prop]; - return extractedValues; - } + if (typeof currentProp === 'string') { + var rawValues = getValuesFrom(currentProp); - var getValuesList_accumulator = []; - /*! - * @param {Object} stateObject - * @param {Array.} chunkNames - * - * @return {Array.} - */ - function getValuesList (stateObject, chunkNames) { - getValuesList_accumulator.length = 0; - var chunkNamesLength = chunkNames.length; - - for (var i = 0; i < chunkNamesLength; i++) { - getValuesList_accumulator.push(stateObject[chunkNames[i]]); + manifestAccumulator[prop] = { + 'formatString': getFormatStringFrom(currentProp) + ,'chunkNames': getFormatChunksFrom(rawValues, prop) + }; } + }); - return getValuesList_accumulator; - } + return manifestAccumulator; + } - /*! - * @param {string} formatString - * @param {Array.} rawValues - * - * @return {string} - */ - function getFormattedValues (formatString, rawValues) { - var formattedValueString = formatString; + /*! + * @param {Object} stateObject + * @param {Object} formatManifests + */ + function expandFormattedProperties (stateObject, formatManifests) { + Tweenable.each(formatManifests, function (prop) { + var currentProp = stateObject[prop]; + var rawValues = getValuesFrom(currentProp); var rawValuesLength = rawValues.length; for (var i = 0; i < rawValuesLength; i++) { - formattedValueString = formattedValueString.replace( - VALUE_PLACEHOLDER, +rawValues[i].toFixed(4)); + stateObject[formatManifests[prop].chunkNames[i]] = +rawValues[i]; } - return formattedValueString; - } + delete stateObject[prop]; + }); + } + + /*! + * @param {Object} stateObject + * @param {Object} formatManifests + */ + function collapseFormattedProperties (stateObject, formatManifests) { + Tweenable.each(formatManifests, function (prop) { + var currentProp = stateObject[prop]; + var formatChunks = extractPropertyChunks( + stateObject, formatManifests[prop].chunkNames); + var valuesList = getValuesList( + formatChunks, formatManifests[prop].chunkNames); + currentProp = getFormattedValues( + formatManifests[prop].formatString, valuesList); + stateObject[prop] = sanitizeRGBChunks(currentProp); + }); + } - /*! - * Note: It's the duty of the caller to convert the Array elements of the - * return value into numbers. This is a performance optimization. - * - * @param {string} formattedString - * - * @return {Array.|null} - */ - function getValuesFrom (formattedString) { - return formattedString.match(R_UNFORMATTED_VALUES); + /*! + * @param {Object} stateObject + * @param {Array.} chunkNames + * + * @return {Object} The extracted value chunks. + */ + function extractPropertyChunks (stateObject, chunkNames) { + var extractedValues = {}; + var currentChunkName, chunkNamesLength = chunkNames.length; + + for (var i = 0; i < chunkNamesLength; i++) { + currentChunkName = chunkNames[i]; + extractedValues[currentChunkName] = stateObject[currentChunkName]; + delete stateObject[currentChunkName]; } - /*! - * @param {Object} easingObject - * @param {Object} tokenData - */ - function expandEasingObject (easingObject, tokenData) { - Tweenable.each(tokenData, function (prop) { - var currentProp = tokenData[prop]; - var chunkNames = currentProp.chunkNames; - var chunkLength = chunkNames.length; - var easingChunks = easingObject[prop].split(' '); - var lastEasingChunk = easingChunks[easingChunks.length - 1]; - - for (var i = 0; i < chunkLength; i++) { - easingObject[chunkNames[i]] = easingChunks[i] || lastEasingChunk; - } + return extractedValues; + } - delete easingObject[prop]; - }); + var getValuesList_accumulator = []; + /*! + * @param {Object} stateObject + * @param {Array.} chunkNames + * + * @return {Array.} + */ + function getValuesList (stateObject, chunkNames) { + getValuesList_accumulator.length = 0; + var chunkNamesLength = chunkNames.length; + + for (var i = 0; i < chunkNamesLength; i++) { + getValuesList_accumulator.push(stateObject[chunkNames[i]]); } - /*! - * @param {Object} easingObject - * @param {Object} tokenData - */ - function collapseEasingObject (easingObject, tokenData) { - Tweenable.each(tokenData, function (prop) { - var currentProp = tokenData[prop]; - var chunkNames = currentProp.chunkNames; - var chunkLength = chunkNames.length; - var composedEasingString = ''; - - for (var i = 0; i < chunkLength; i++) { - composedEasingString += ' ' + easingObject[chunkNames[i]]; - delete easingObject[chunkNames[i]]; - } + return getValuesList_accumulator; + } - easingObject[prop] = composedEasingString.substr(1); - }); + /*! + * @param {string} formatString + * @param {Array.} rawValues + * + * @return {string} + */ + function getFormattedValues (formatString, rawValues) { + var formattedValueString = formatString; + var rawValuesLength = rawValues.length; + + for (var i = 0; i < rawValuesLength; i++) { + formattedValueString = formattedValueString.replace( + VALUE_PLACEHOLDER, +rawValues[i].toFixed(4)); } - Tweenable.prototype.filter.token = { - 'tweenCreated': function (currentState, fromState, toState, easingObject) { - sanitizeObjectForHexProps(currentState); - sanitizeObjectForHexProps(fromState); - sanitizeObjectForHexProps(toState); - this._tokenData = getFormatManifests(currentState); - }, - - 'beforeTween': function (currentState, fromState, toState, easingObject) { - expandEasingObject(easingObject, this._tokenData); - expandFormattedProperties(currentState, this._tokenData); - expandFormattedProperties(fromState, this._tokenData); - expandFormattedProperties(toState, this._tokenData); - }, - - 'afterTween': function (currentState, fromState, toState, easingObject) { - collapseFormattedProperties(currentState, this._tokenData); - collapseFormattedProperties(fromState, this._tokenData); - collapseFormattedProperties(toState, this._tokenData); - collapseEasingObject(easingObject, this._tokenData); + return formattedValueString; + } + + /*! + * Note: It's the duty of the caller to convert the Array elements of the + * return value into numbers. This is a performance optimization. + * + * @param {string} formattedString + * + * @return {Array.|null} + */ + function getValuesFrom (formattedString) { + return formattedString.match(R_UNFORMATTED_VALUES); + } + + /*! + * @param {Object} easingObject + * @param {Object} tokenData + */ + function expandEasingObject (easingObject, tokenData) { + Tweenable.each(tokenData, function (prop) { + var currentProp = tokenData[prop]; + var chunkNames = currentProp.chunkNames; + var chunkLength = chunkNames.length; + var easingChunks = easingObject[prop].split(' '); + var lastEasingChunk = easingChunks[easingChunks.length - 1]; + + for (var i = 0; i < chunkLength; i++) { + easingObject[chunkNames[i]] = easingChunks[i] || lastEasingChunk; } - }; - } (Tweenable)); + delete easingObject[prop]; + }); + } + + /*! + * @param {Object} easingObject + * @param {Object} tokenData + */ + function collapseEasingObject (easingObject, tokenData) { + Tweenable.each(tokenData, function (prop) { + var currentProp = tokenData[prop]; + var chunkNames = currentProp.chunkNames; + var chunkLength = chunkNames.length; + var composedEasingString = ''; + + for (var i = 0; i < chunkLength; i++) { + composedEasingString += ' ' + easingObject[chunkNames[i]]; + delete easingObject[chunkNames[i]]; + } + + easingObject[prop] = composedEasingString.substr(1); + }); + } + + Tweenable.prototype.filter.token = { + 'tweenCreated': function (currentState, fromState, toState, easingObject) { + sanitizeObjectForHexProps(currentState); + sanitizeObjectForHexProps(fromState); + sanitizeObjectForHexProps(toState); + this._tokenData = getFormatManifests(currentState); + }, + + 'beforeTween': function (currentState, fromState, toState, easingObject) { + expandEasingObject(easingObject, this._tokenData); + expandFormattedProperties(currentState, this._tokenData); + expandFormattedProperties(fromState, this._tokenData); + expandFormattedProperties(toState, this._tokenData); + }, + + 'afterTween': function (currentState, fromState, toState, easingObject) { + collapseFormattedProperties(currentState, this._tokenData); + collapseFormattedProperties(fromState, this._tokenData); + collapseFormattedProperties(toState, this._tokenData); + collapseEasingObject(easingObject, this._tokenData); + } + }; + + } (Tweenable)); - }(this, window)); + }(window)); return window.Tweenable; }); diff --git a/dist/angular-carousel.min.js b/dist/angular-carousel.min.js index 8e39acb..6eb7c2a 100644 --- a/dist/angular-carousel.min.js +++ b/dist/angular-carousel.min.js @@ -1,8 +1,8 @@ /** * Angular Carousel - Mobile friendly touch carousel for AngularJS - * @version v0.3.5 - 2014-11-06 + * @version v0.3.7 - 2014-11-11 * @link http://revolunet.github.com/angular-carousel * @author Julien Bouquillon * @license MIT License, http://www.opensource.org/licenses/MIT */ -angular.module("angular-carousel",["ngTouch","angular-carousel.shifty"]),angular.module("angular-carousel").directive("rnCarouselAutoSlide",["$timeout",function(a){return{restrict:"A",link:function(b,c,d){var e=Math.round(1e3*parseFloat(d.rnCarouselAutoSlide)),f=increment=!1,g=c.children().length;b.carouselExposedIndex||(b.carouselExposedIndex=0),stopAutoplay=function(){angular.isDefined(f)&&a.cancel(f),f=void 0},increment=function(){b.carouselExposedIndex=b.carouselExposedIndex\n')}]),function(){"use strict";angular.module("angular-carousel").service("DeviceCapabilities",function(){function a(){var a="transform",b="webkitTransform";return"undefined"!=typeof document.body.style[a]?["webkit","moz","o","ms"].every(function(b){var c="-"+b+"-transform";return"undefined"!=typeof document.body.style[c]?(a=c,!1):!0}):a="undefined"!=typeof document.body.style[b]?"-webkit-transform":void 0,a}function b(){var a,b=document.createElement("p"),c={webkitTransform:"-webkit-transform",msTransform:"-ms-transform",transform:"transform"};document.body.insertBefore(b,null);for(var d in c)void 0!==b.style[d]&&(b.style[d]="translate3d(1px,1px,1px)",a=window.getComputedStyle(b).getPropertyValue(c[d]));return document.body.removeChild(b),void 0!==a&&a.length>0&&"none"!==a}return{has3d:b(),transformProperty:a()}}).service("computeCarouselSlideStyle",["DeviceCapabilities",function(a){return function(b,c,d){var e,f={display:"inline-block"},g=100*b+c,h=a.has3d?"translate3d("+g+"%, 0, 0)":"translate3d("+g+"%, 0)",i=(100-Math.abs(g))/100;if(a.transformProperty)if("fadeAndSlide"==d)f[a.transformProperty]=h,e=0,Math.abs(g)<100&&(e=.3+.7*i),f.opacity=e;else if("hexagon"==d){var j=100,k=0,l=60*(i-1);j=-100*b>c?100:0,k=-100*b>c?l:-l,f[a.transformProperty]=h+" rotateY("+k+"deg)",f[a.transformProperty+"-origin"]=j+"% 50%"}else if("zoom"==d){f[a.transformProperty]=h;var m=1;Math.abs(g)<100&&(m=1+2*(1-i)),f[a.transformProperty]+=" scale("+m+")",f[a.transformProperty+"-origin"]="50% 50%",e=0,Math.abs(g)<100&&(e=.3+.7*i),f.opacity=e}else f[a.transformProperty]=h;else f["margin-left"]=g+"%";return f}}]).service("createStyleString",function(){return function(a){var b=[];return angular.forEach(a,function(a,c){b.push(c+":"+a)}),b.join(";")}}).directive("rnCarousel",["$swipe","$window","$document","$parse","$compile","$timeout","$interval","computeCarouselSlideStyle","createStyleString","Tweenable",function(a,b,c,d,e,f,g,h,i,j){function k(a,b,c){var d=c;return a.every(function(a,c){return angular.equals(a,b)?(d=c,!1):!0}),d}{var l=0;b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame}return{restrict:"A",scope:!0,compile:function(m,n){var o,p,q=m[0].querySelector("li"),r=q?q.attributes:[],s=!1,t=!1;return["ng-repeat","data-ng-repeat","ng:repeat","x-ng-repeat"].every(function(a){var b=r[a];if(angular.isDefined(b)){var c=b.value.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),d=c[3];if(o=c[1],p=c[2],o)return angular.isDefined(n.rnCarouselBuffered)&&(t=!0,b.value=o+" in "+p+"|carouselSlice:carouselBufferIndex:carouselBufferSize",d&&(b.value+=" track by "+d)),s=!0,!1}return!0}),function(m,n,o){function q(){return n[0].querySelectorAll("ul[rn-carousel] > li")}function r(a){L=!0,A({x:a.clientX,y:a.clientY},a)}function u(a){var b=100*m.carouselBufferIndex+a;angular.forEach(q(),function(a,c){a.style.cssText=i(h(c,b,I.transitionType))})}function v(a,b){if(void 0===a&&(a=m.carouselIndex),b=b||{},b.animate===!1||"none"===I.transitionType)return O=!1,K=-100*a,m.carouselIndex=a,B(),void 0;O=!0;var c=new j;c.tween({from:{x:K},to:{x:-100*a},duration:I.transitionDuration,easing:I.transitionEasing,step:function(a){u(a.x)},finish:function(){O=!1,m.$apply(function(){m.carouselIndex=a,K=-100*a,B()})}})}function w(){var a=n[0].getBoundingClientRect();return a.width?a.width:a.right-a.left}function x(){M=w()}function y(a){return c.bind("mouseup",r),x(),N=n[0].querySelector("li").getBoundingClientRect().left,D=!0,E=a.x,!1}function z(a){if(!O){var b,c;if(D&&(b=a.x,c=E-b,c>2||-2>c)){L=!0;var d=K+100*-c/M;u(d)}return!1}}function A(a,b){if((!b||L)&&(c.unbind("mouseup",r),D=!1,L=!1,F=E-a.x,0!==F&&!O))if(K+=100*-F/M,I.isSequential){var d=I.moveTreshold*M,e=-F,f=-Math[e>=0?"ceil":"floor"](e/M),g=Math.abs(e)>d;G&&f+m.carouselIndex>=G.length&&(f=G.length-1-m.carouselIndex),f+m.carouselIndex<0&&(f=-m.carouselIndex);var h=g?f:0;F=m.carouselIndex+h,v(F)}else m.$apply(function(){m.carouselIndex=parseInt(-K/100,10),B()})}function B(){var a=0,b=(m.carouselBufferSize-1)/2;t?(a=m.carouselIndex<=b?0:G&&G.lengthG.length-m.carouselBufferSize?G.length-m.carouselBufferSize:m.carouselIndex-b,m.carouselBufferIndex=a,f(function(){u(K)},0,!1)):f(function(){u(K)},0,!1)}function C(){x(),v()}l++;var D,E,F,G,H={transitionType:o.rnCarouselTransition||"slide",transitionEasing:"easeTo",transitionDuration:300,isSequential:!0,autoSlideDuration:3,bufferSize:5,moveTreshold:.1},I=angular.extend({},H),J=!1,K=0,L=!1,M=null,N=null,O=!1;if(void 0!==o.rnCarouselControls){var P='';n.append(e(angular.element(P))(m))}a.bind(n,{start:y,move:z,end:A,cancel:function(a){A({},a)}}),m.nextSlide=function(a){var b=m.carouselIndex+1;b>G.length-1&&(b=0),O||v(b,a)},m.prevSlide=function(a){var b=m.carouselIndex-1;0>b&&(b=G.length-1),v(b,a)};var Q=!0;m.carouselIndex=0,s||(G=[],angular.forEach(q(),function(a,b){G.push({id:b})}));var R;if(void 0!==o.rnCarouselAutoSlide){var S=parseInt(o.rnCarouselAutoSlide,10)||I.autoSlideDuration;R=g(function(){O||D||m.nextSlide()},1e3*S)}if(o.rnCarouselIndex){var T=function(a){U.assign(m.$parent,a)},U=d(o.rnCarouselIndex);angular.isFunction(U.assign)?(m.$watch("carouselIndex",function(a){O||T(a)}),m.$parent.$watch(U,function(a){void 0!==a&&null!==a&&(G&&a>=G.length?(a=G.length-1,T(a)):G&&0>a&&(a=0,T(a)),O||v(a,{animate:!Q}),Q=!1)}),J=!0):isNaN(o.rnCarouselIndex)||v(parseInt(o.rnCarouselIndex,10),{animate:!1})}else v(0,{animate:!Q}),Q=!1;if(o.rnCarouselLocked&&m.$watch(o.rnCarouselLocked,function(a){O=a===!0?!0:!1}),s){var V=void 0!==o.rnCarouselDeepWatch;m[V?"$watch":"$watchCollection"](p,function(a,b){(G||a).slice();if(G=a,V&&angular.isArray(a)){var c=b[m.carouselIndex],d=k(a,c,m.carouselIndex);v(d,{animate:!1})}else v(m.carouselIndex,{animate:!1})},!0)}m.$on("$destroy",function(){c.unbind("mouseup",r)}),m.carouselBufferIndex=0,m.carouselBufferSize=I.bufferSize;var W=angular.element(b);W.bind("orientationchange",C),W.bind("resize",C),m.$on("$destroy",function(){c.unbind("mouseup",r),W.unbind("orientationchange",C),W.unbind("resize",C)})}}}}])}(),angular.module("angular-carousel.shifty",[]).factory("Tweenable",function(){return function(a,b){"undefined"==typeof SHIFTY_DEBUG_NOW&&(SHIFTY_DEBUG_NOW=function(){return+new Date});var c=function(){"use strict";function c(){}function d(a,b){var c;for(c in a)Object.hasOwnProperty.call(a,c)&&b(c)}function e(a,b){return d(b,function(c){a[c]=b[c]}),a}function f(a,b){d(b,function(c){"undefined"==typeof a[c]&&(a[c]=b[c])})}function g(a,b,c,d,e,f,g){var i,j=(a-f)/e;for(i in b)b.hasOwnProperty(i)&&(b[i]=h(c[i],d[i],m[g[i]],j));return b}function h(a,b,c,d){return a+(b-a)*c(d)}function i(a,b){var c=l.prototype.filter,e=a._filterArgs;d(c,function(d){"undefined"!=typeof c[d][b]&&c[d][b].apply(a,e)})}function j(a,b,c,d,e,f,h,j,k){t=b+c,u=Math.min(s(),t),v=u>=t,a.isPlaying()&&!v?(k(a._timeoutHandler,q),i(a,"beforeTween"),g(u,d,e,f,c,b,h),i(a,"afterTween"),j(d)):v&&(j(f),a.stop(!0))}function k(a,b){var c={};return"string"==typeof b?d(a,function(a){c[a]=b}):d(a,function(a){c[a]||(c[a]=b[a]||o)}),c}function l(a,b){this._currentState=a||{},this._configured=!1,this._scheduleFunction=n,"undefined"!=typeof b&&this.setConfig(b)}var m,n,o="linear",p=500,q=1e3/60,r=Date.now?Date.now:function(){return+new Date},s=SHIFTY_DEBUG_NOW?SHIFTY_DEBUG_NOW:r;n="undefined"!=typeof b?b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.oRequestAnimationFrame||b.msRequestAnimationFrame||b.mozCancelRequestAnimationFrame&&b.mozRequestAnimationFrame||setTimeout:setTimeout;var t,u,v;return l.prototype.tween=function(a){return this._isTweening?this:(void 0===a&&this._configured||this.setConfig(a),this._start(this.get()),this.resume())},l.prototype.setConfig=function(a){a=a||{},this._configured=!0,this._pausedAtTime=null,this._start=a.start||c,this._step=a.step||c,this._finish=a.finish||c,this._duration=a.duration||p,this._currentState=a.from||this.get(),this._originalState=this.get(),this._targetState=a.to||this.get(),this._timestamp=s();var b=this._currentState,d=this._targetState;return f(d,b),this._easing=k(b,a.easing||o),this._filterArgs=[b,this._originalState,d,this._easing],i(this,"tweenCreated"),this},l.prototype.get=function(){return e({},this._currentState)},l.prototype.set=function(a){this._currentState=a},l.prototype.pause=function(){return this._pausedAtTime=s(),this._isPaused=!0,this},l.prototype.resume=function(){this._isPaused&&(this._timestamp+=s()-this._pausedAtTime),this._isPaused=!1,this._isTweening=!0;var a=this;return this._timeoutHandler=function(){j(a,a._timestamp,a._duration,a._currentState,a._originalState,a._targetState,a._easing,a._step,a._scheduleFunction)},this._timeoutHandler(),this},l.prototype.stop=function(a){return this._isTweening=!1,this._isPaused=!1,this._timeoutHandler=c,a&&(e(this._currentState,this._targetState),i(this,"afterTweenEnd"),this._finish.call(this,this._currentState)),this},l.prototype.isPlaying=function(){return this._isTweening&&!this._isPaused},l.prototype.setScheduleFunction=function(a){this._scheduleFunction=a},l.prototype.dispose=function(){var a;for(a in this)this.hasOwnProperty(a)&&delete this[a]},l.prototype.filter={},l.prototype.formula={linear:function(a){return a}},m=l.prototype.formula,e(l,{now:s,each:d,tweenProps:g,tweenProp:h,applyFilter:i,shallowCopy:e,defaults:f,composeEasingObject:k}),"function"==typeof SHIFTY_DEBUG_NOW&&(a.timeoutHandler=j),"object"==typeof exports?module.exports=l:"function"==typeof define&&define.amd?define(function(){return l}):"undefined"==typeof a.Tweenable&&(a.Tweenable=l),l}();b.Tweenable=c,function(){c.shallowCopy(c.prototype.formula,{easeInQuad:function(a){return Math.pow(a,2)},easeOutQuad:function(a){return-(Math.pow(a-1,2)-1)},easeInOutQuad:function(a){return(a/=.5)<1?.5*Math.pow(a,2):-.5*((a-=2)*a-2)},easeInCubic:function(a){return Math.pow(a,3)},easeOutCubic:function(a){return Math.pow(a-1,3)+1},easeInOutCubic:function(a){return(a/=.5)<1?.5*Math.pow(a,3):.5*(Math.pow(a-2,3)+2)},easeInQuart:function(a){return Math.pow(a,4)},easeOutQuart:function(a){return-(Math.pow(a-1,4)-1)},easeInOutQuart:function(a){return(a/=.5)<1?.5*Math.pow(a,4):-.5*((a-=2)*Math.pow(a,3)-2)},easeInQuint:function(a){return Math.pow(a,5)},easeOutQuint:function(a){return Math.pow(a-1,5)+1},easeInOutQuint:function(a){return(a/=.5)<1?.5*Math.pow(a,5):.5*(Math.pow(a-2,5)+2)},easeInSine:function(a){return-Math.cos(a*(Math.PI/2))+1},easeOutSine:function(a){return Math.sin(a*(Math.PI/2))},easeInOutSine:function(a){return-.5*(Math.cos(Math.PI*a)-1)},easeInExpo:function(a){return 0===a?0:Math.pow(2,10*(a-1))},easeOutExpo:function(a){return 1===a?1:-Math.pow(2,-10*a)+1},easeInOutExpo:function(a){return 0===a?0:1===a?1:(a/=.5)<1?.5*Math.pow(2,10*(a-1)):.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return-(Math.sqrt(1-a*a)-1)},easeOutCirc:function(a){return Math.sqrt(1-Math.pow(a-1,2))},easeInOutCirc:function(a){return(a/=.5)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)},easeOutBounce:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},easeInBack:function(a){var b=1.70158;return a*a*((b+1)*a-b)},easeOutBack:function(a){var b=1.70158;return(a-=1)*a*((b+1)*a+b)+1},easeInOutBack:function(a){var b=1.70158;return(a/=.5)<1?.5*a*a*(((b*=1.525)+1)*a-b):.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},elastic:function(a){return-1*Math.pow(4,-8*a)*Math.sin(2*(6*a-1)*Math.PI/2)+1},swingFromTo:function(a){var b=1.70158;return(a/=.5)<1?.5*a*a*(((b*=1.525)+1)*a-b):.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},swingFrom:function(a){var b=1.70158;return a*a*((b+1)*a-b)},swingTo:function(a){var b=1.70158;return(a-=1)*a*((b+1)*a+b)+1},bounce:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},bouncePast:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?2-(7.5625*(a-=1.5/2.75)*a+.75):2.5/2.75>a?2-(7.5625*(a-=2.25/2.75)*a+.9375):2-(7.5625*(a-=2.625/2.75)*a+.984375)},easeFromTo:function(a){return(a/=.5)<1?.5*Math.pow(a,4):-.5*((a-=2)*Math.pow(a,3)-2)},easeFrom:function(a){return Math.pow(a,4)},easeTo:function(a){return Math.pow(a,.25)}})}(),function(){function a(a,b,c,d,e,f){function g(a){return((n*a+o)*a+p)*a}function h(a){return((q*a+r)*a+s)*a}function i(a){return(3*n*a+2*o)*a+p}function j(a){return 1/(200*a)}function k(a,b){return h(m(a,b))}function l(a){return a>=0?a:0-a}function m(a,b){var c,d,e,f,h,j;for(e=a,j=0;8>j;j++){if(f=g(e)-a,l(f)e)return c;if(e>d)return d;for(;d>c;){if(f=g(e),l(f-a)f?c=e:d=e,e=.5*(d-c)+c}return e}var n=0,o=0,p=0,q=0,r=0,s=0;return p=3*b,o=3*(d-b)-p,n=1-p-o,s=3*c,r=3*(e-c)-s,q=1-s-r,k(a,j(f))}function b(b,c,d,e){return function(f){return a(f,b,c,d,e,1)}}c.setBezierFunction=function(a,d,e,f,g){var h=b(d,e,f,g);return h.x1=d,h.y1=e,h.x2=f,h.y2=g,c.prototype.formula[a]=h},c.unsetBezierFunction=function(a){delete c.prototype.formula[a]}}(),function(){function a(a,b,d,e,f){return c.tweenProps(e,b,a,d,1,0,f)}var b=new c;b._filterArgs=[],c.interpolate=function(d,e,f,g){var h=c.shallowCopy({},d),i=c.composeEasingObject(d,g||"linear");b.set({});var j=b._filterArgs;j.length=0,j[0]=h,j[1]=d,j[2]=e,j[3]=i,c.applyFilter(b,"tweenCreated"),c.applyFilter(b,"beforeTween");var k=a(d,h,e,f,i);return c.applyFilter(b,"afterTween"),k}}(),function(a){function b(a,b){B.length=0;var c,d=a.length;for(c=0;d>c;c++)B.push("_"+b+"_"+c);return B}function c(a){var b=a.match(v);return b?(1===b.length||a[0].match(u))&&b.unshift(""):b=["",""],b.join(A)}function d(b){a.each(b,function(a){var c=b[a];"string"==typeof c&&c.match(z)&&(b[a]=e(c))})}function e(a){return i(z,a,f)}function f(a){var b=g(a);return"rgb("+b[0]+","+b[1]+","+b[2]+")"}function g(a){return a=a.replace(/#/,""),3===a.length&&(a=a.split(""),a=a[0]+a[0]+a[1]+a[1]+a[2]+a[2]),C[0]=h(a.substr(0,2)),C[1]=h(a.substr(2,2)),C[2]=h(a.substr(4,2)),C}function h(a){return parseInt(a,16)}function i(a,b,c){var d=b.match(a),e=b.replace(a,A);if(d)for(var f,g=d.length,h=0;g>h;h++)f=d.shift(),e=e.replace(A,c(f));return e}function j(a){return i(x,a,k)}function k(a){for(var b=a.match(w),c=b.length,d=a.match(y)[0],e=0;c>e;e++)d+=parseInt(b[e],10)+",";return d=d.slice(0,-1)+")"}function l(d){var e={};return a.each(d,function(a){var f=d[a];if("string"==typeof f){var g=r(f);e[a]={formatString:c(f),chunkNames:b(g,a)}}}),e}function m(b,c){a.each(c,function(a){for(var d=b[a],e=r(d),f=e.length,g=0;f>g;g++)b[c[a].chunkNames[g]]=+e[g];delete b[a]})}function n(b,c){a.each(c,function(a){var d=b[a],e=o(b,c[a].chunkNames),f=p(e,c[a].chunkNames);d=q(c[a].formatString,f),b[a]=j(d)})}function o(a,b){for(var c,d={},e=b.length,f=0;e>f;f++)c=b[f],d[c]=a[c],delete a[c];return d}function p(a,b){D.length=0;for(var c=b.length,d=0;c>d;d++)D.push(a[b[d]]);return D}function q(a,b){for(var c=a,d=b.length,e=0;d>e;e++)c=c.replace(A,+b[e].toFixed(4));return c}function r(a){return a.match(w)}function s(b,c){a.each(c,function(a){for(var d=c[a],e=d.chunkNames,f=e.length,g=b[a].split(" "),h=g[g.length-1],i=0;f>i;i++)b[e[i]]=g[i]||h;delete b[a]})}function t(b,c){a.each(c,function(a){for(var d=c[a],e=d.chunkNames,f=e.length,g="",h=0;f>h;h++)g+=" "+b[e[h]],delete b[e[h]];b[a]=g.substr(1)})}var u=/(\d|\-|\.)/,v=/([^\-0-9\.]+)/g,w=/[0-9.\-]+/g,x=new RegExp("rgb\\("+w.source+/,\s*/.source+w.source+/,\s*/.source+w.source+"\\)","g"),y=/^.*\(/,z=/#([0-9]|[a-f]){3,6}/gi,A="VAL",B=[],C=[],D=[];a.prototype.filter.token={tweenCreated:function(a,b,c){d(a),d(b),d(c),this._tokenData=l(a)},beforeTween:function(a,b,c,d){s(d,this._tokenData),m(a,this._tokenData),m(b,this._tokenData),m(c,this._tokenData)},afterTween:function(a,b,c,d){n(a,this._tokenData),n(b,this._tokenData),n(c,this._tokenData),t(d,this._tokenData)}}}(c)}(this,window),window.Tweenable}),function(){"use strict";angular.module("angular-carousel").filter("carouselSlice",function(){return function(a,b,c){return angular.isArray(a)?a.slice(b,b+c):angular.isObject(a)?a:void 0}})}(); \ No newline at end of file +angular.module("angular-carousel",["ngTouch","angular-carousel.shifty"]),angular.module("angular-carousel").directive("rnCarouselAutoSlide",["$timeout",function(a){return{restrict:"A",link:function(b,c,d){var e=Math.round(1e3*parseFloat(d.rnCarouselAutoSlide)),f=increment=!1,g=c.children().length;b.carouselExposedIndex||(b.carouselExposedIndex=0),stopAutoplay=function(){angular.isDefined(f)&&a.cancel(f),f=void 0},increment=function(){b.carouselExposedIndex=b.carouselExposedIndex\n')}]),function(){"use strict";angular.module("angular-carousel").service("DeviceCapabilities",function(){function a(){var a="transform",b="webkitTransform";return"undefined"!=typeof document.body.style[a]?["webkit","moz","o","ms"].every(function(b){var c="-"+b+"-transform";return"undefined"!=typeof document.body.style[c]?(a=c,!1):!0}):a="undefined"!=typeof document.body.style[b]?"-webkit-transform":void 0,a}function b(){var a,b=document.createElement("p"),c={webkitTransform:"-webkit-transform",msTransform:"-ms-transform",transform:"transform"};document.body.insertBefore(b,null);for(var d in c)void 0!==b.style[d]&&(b.style[d]="translate3d(1px,1px,1px)",a=window.getComputedStyle(b).getPropertyValue(c[d]));return document.body.removeChild(b),void 0!==a&&a.length>0&&"none"!==a}return{has3d:b(),transformProperty:a()}}).service("computeCarouselSlideStyle",["DeviceCapabilities",function(a){return function(b,c,d){var e,f={display:"inline-block"},g=100*b+c,h=a.has3d?"translate3d("+g+"%, 0, 0)":"translate3d("+g+"%, 0)",i=(100-Math.abs(g))/100;if(a.transformProperty)if("fadeAndSlide"==d)f[a.transformProperty]=h,e=0,Math.abs(g)<100&&(e=.3+.7*i),f.opacity=e;else if("hexagon"==d){var j=100,k=0,l=60*(i-1);j=-100*b>c?100:0,k=-100*b>c?l:-l,f[a.transformProperty]=h+" rotateY("+k+"deg)",f[a.transformProperty+"-origin"]=j+"% 50%"}else if("zoom"==d){f[a.transformProperty]=h;var m=1;Math.abs(g)<100&&(m=1+2*(1-i)),f[a.transformProperty]+=" scale("+m+")",f[a.transformProperty+"-origin"]="50% 50%",e=0,Math.abs(g)<100&&(e=.3+.7*i),f.opacity=e}else f[a.transformProperty]=h;else f["margin-left"]=g+"%";return f}}]).service("createStyleString",function(){return function(a){var b=[];return angular.forEach(a,function(a,c){b.push(c+":"+a)}),b.join(";")}}).directive("rnCarousel",["$swipe","$window","$document","$parse","$compile","$timeout","$interval","computeCarouselSlideStyle","createStyleString","Tweenable",function(a,b,c,d,e,f,g,h,i,j){function k(a,b,c){var d=c;return a.every(function(a,c){return angular.equals(a,b)?(d=c,!1):!0}),d}{var l=0;b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame}return{restrict:"A",scope:!0,compile:function(m,n){var o,p,q=m[0].querySelector("li"),r=q?q.attributes:[],s=!1,t=!1;return["ng-repeat","data-ng-repeat","ng:repeat","x-ng-repeat"].every(function(a){var b=r[a];if(angular.isDefined(b)){var c=b.value.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),d=c[3];if(o=c[1],p=c[2],o)return angular.isDefined(n.rnCarouselBuffered)&&(t=!0,b.value=o+" in "+p+"|carouselSlice:carouselBufferIndex:carouselBufferSize",d&&(b.value+=" track by "+d)),s=!0,!1}return!0}),function(m,n,o){function q(){return n[0].querySelectorAll("ul[rn-carousel] > li")}function r(a){L=!0,A({x:a.clientX,y:a.clientY},a)}function u(a){var b=100*m.carouselBufferIndex+a;angular.forEach(q(),function(a,c){a.style.cssText=i(h(c,b,I.transitionType))})}function v(a,b){if(void 0===a&&(a=m.carouselIndex),b=b||{},b.animate===!1||"none"===I.transitionType)return O=!1,K=-100*a,m.carouselIndex=a,B(),void 0;O=!0;var c=new j;c.tween({from:{x:K},to:{x:-100*a},duration:I.transitionDuration,easing:I.transitionEasing,step:function(a){u(a.x)},finish:function(){O=!1,m.$apply(function(){m.carouselIndex=a,K=-100*a,B()})}})}function w(){var a=n[0].getBoundingClientRect();return a.width?a.width:a.right-a.left}function x(){M=w()}function y(a){return c.bind("mouseup",r),x(),N=n[0].querySelector("li").getBoundingClientRect().left,D=!0,E=a.x,!1}function z(a){if(!O){var b,c;if(D&&(b=a.x,c=E-b,c>2||-2>c)){L=!0;var d=K+100*-c/M;u(d)}return!1}}function A(a,b){if((!b||L)&&(c.unbind("mouseup",r),D=!1,L=!1,F=E-a.x,0!==F&&!O))if(K+=100*-F/M,I.isSequential){var d=I.moveTreshold*M,e=-F,f=-Math[e>=0?"ceil":"floor"](e/M),g=Math.abs(e)>d;G&&f+m.carouselIndex>=G.length&&(f=G.length-1-m.carouselIndex),f+m.carouselIndex<0&&(f=-m.carouselIndex);var h=g?f:0;F=m.carouselIndex+h,v(F)}else m.$apply(function(){m.carouselIndex=parseInt(-K/100,10),B()})}function B(){var a=0,b=(m.carouselBufferSize-1)/2;t?(a=m.carouselIndex<=b?0:G&&G.lengthG.length-m.carouselBufferSize?G.length-m.carouselBufferSize:m.carouselIndex-b,m.carouselBufferIndex=a,f(function(){u(K)},0,!1)):f(function(){u(K)},0,!1)}function C(){x(),v()}l++;var D,E,F,G,H={transitionType:o.rnCarouselTransition||"slide",transitionEasing:"easeTo",transitionDuration:300,isSequential:!0,autoSlideDuration:3,bufferSize:5,moveTreshold:.1},I=angular.extend({},H),J=!1,K=0,L=!1,M=null,N=null,O=!1;if(void 0!==o.rnCarouselControls){var P='';n.append(e(angular.element(P))(m))}a.bind(n,{start:y,move:z,end:A,cancel:function(a){A({},a)}}),m.nextSlide=function(a){var b=m.carouselIndex+1;b>G.length-1&&(b=0),O||v(b,a)},m.prevSlide=function(a){var b=m.carouselIndex-1;0>b&&(b=G.length-1),v(b,a)};var Q=!0;m.carouselIndex=0,s||(G=[],angular.forEach(q(),function(a,b){G.push({id:b})}));var R;if(void 0!==o.rnCarouselAutoSlide){var S=parseInt(o.rnCarouselAutoSlide,10)||I.autoSlideDuration;R=g(function(){O||D||m.nextSlide()},1e3*S)}if(o.rnCarouselIndex){var T=function(a){U.assign(m.$parent,a)},U=d(o.rnCarouselIndex);angular.isFunction(U.assign)?(m.$watch("carouselIndex",function(a){O||T(a)}),m.$parent.$watch(U,function(a){void 0!==a&&null!==a&&(G&&a>=G.length?(a=G.length-1,T(a)):G&&0>a&&(a=0,T(a)),O||v(a,{animate:!Q}),Q=!1)}),J=!0):isNaN(o.rnCarouselIndex)||v(parseInt(o.rnCarouselIndex,10),{animate:!1})}else v(0,{animate:!Q}),Q=!1;if(o.rnCarouselLocked&&m.$watch(o.rnCarouselLocked,function(a){O=a===!0?!0:!1}),s){var V=void 0!==o.rnCarouselDeepWatch;m[V?"$watch":"$watchCollection"](p,function(a,b){(G||a).slice();if(G=a,V&&angular.isArray(a)){var c=b[m.carouselIndex],d=k(a,c,m.carouselIndex);v(d,{animate:!1})}else v(m.carouselIndex,{animate:!1})},!0)}m.$on("$destroy",function(){c.unbind("mouseup",r)}),m.carouselBufferIndex=0,m.carouselBufferSize=I.bufferSize;var W=angular.element(b);W.bind("orientationchange",C),W.bind("resize",C),m.$on("$destroy",function(){c.unbind("mouseup",r),W.unbind("orientationchange",C),W.unbind("resize",C)})}}}}])}(),angular.module("angular-carousel.shifty",[]).factory("Tweenable",function(){return function(a){var b=function(){"use strict";function b(){}function c(a,b){var c;for(c in a)Object.hasOwnProperty.call(a,c)&&b(c)}function d(a,b){return c(b,function(c){a[c]=b[c]}),a}function e(a,b){c(b,function(c){"undefined"==typeof a[c]&&(a[c]=b[c])})}function f(a,b,c,d,e,f,h){var i,j=(a-f)/e;for(i in b)b.hasOwnProperty(i)&&(b[i]=g(c[i],d[i],l[h[i]],j));return b}function g(a,b,c,d){return a+(b-a)*c(d)}function h(a,b){var d=k.prototype.filter,e=a._filterArgs;c(d,function(c){"undefined"!=typeof d[c][b]&&d[c][b].apply(a,e)})}function i(a,b,c,d,e,g,i,j,k){s=b+c,t=Math.min(r(),s),u=t>=s,v=c-(s-t),a.isPlaying()&&!u?(a._scheduleId=k(a._timeoutHandler,p),h(a,"beforeTween"),f(t,d,e,g,c,b,i),h(a,"afterTween"),j(d,a._attachment,v)):u&&(j(g,a._attachment,v),a.stop(!0))}function j(a,b){var d={};return"string"==typeof b?c(a,function(a){d[a]=b}):c(a,function(a){d[a]||(d[a]=b[a]||n)}),d}function k(a,b){this._currentState=a||{},this._configured=!1,this._scheduleFunction=m,"undefined"!=typeof b&&this.setConfig(b)}var l,m,n="linear",o=500,p=1e3/60,q=Date.now?Date.now:function(){return+new Date},r="undefined"!=typeof SHIFTY_DEBUG_NOW?SHIFTY_DEBUG_NOW:q;m="undefined"!=typeof window?window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||window.mozCancelRequestAnimationFrame&&window.mozRequestAnimationFrame||setTimeout:setTimeout;var s,t,u,v;return k.prototype.tween=function(a){return this._isTweening?this:(void 0===a&&this._configured||this.setConfig(a),this._timestamp=r(),this._start(this.get(),this._attachment),this.resume())},k.prototype.setConfig=function(a){a=a||{},this._configured=!0,this._attachment=a.attachment,this._pausedAtTime=null,this._scheduleId=null,this._start=a.start||b,this._step=a.step||b,this._finish=a.finish||b,this._duration=a.duration||o,this._currentState=a.from||this.get(),this._originalState=this.get(),this._targetState=a.to||this.get();var c=this._currentState,d=this._targetState;return e(d,c),this._easing=j(c,a.easing||n),this._filterArgs=[c,this._originalState,d,this._easing],h(this,"tweenCreated"),this},k.prototype.get=function(){return d({},this._currentState)},k.prototype.set=function(a){this._currentState=a},k.prototype.pause=function(){return this._pausedAtTime=r(),this._isPaused=!0,this},k.prototype.resume=function(){this._isPaused&&(this._timestamp+=r()-this._pausedAtTime),this._isPaused=!1,this._isTweening=!0;var a=this;return this._timeoutHandler=function(){i(a,a._timestamp,a._duration,a._currentState,a._originalState,a._targetState,a._easing,a._step,a._scheduleFunction)},this._timeoutHandler(),this},k.prototype.seek=function(a){return this._timestamp=r()-a,this.isPlaying()||(this._isTweening=!0,this._isPaused=!1,i(this,this._timestamp,this._duration,this._currentState,this._originalState,this._targetState,this._easing,this._step,this._scheduleFunction),this._timeoutHandler(),this.pause()),this},k.prototype.stop=function(c){return this._isTweening=!1,this._isPaused=!1,this._timeoutHandler=b,(a.cancelAnimationFrame||a.webkitCancelAnimationFrame||a.oCancelAnimationFrame||a.msCancelAnimationFrame||a.mozCancelRequestAnimationFrame||a.clearTimeout)(this._scheduleId),c&&(d(this._currentState,this._targetState),h(this,"afterTweenEnd"),this._finish.call(this,this._currentState,this._attachment)),this},k.prototype.isPlaying=function(){return this._isTweening&&!this._isPaused},k.prototype.setScheduleFunction=function(a){this._scheduleFunction=a},k.prototype.dispose=function(){var a;for(a in this)this.hasOwnProperty(a)&&delete this[a]},k.prototype.filter={},k.prototype.formula={linear:function(a){return a}},l=k.prototype.formula,d(k,{now:r,each:c,tweenProps:f,tweenProp:g,applyFilter:h,shallowCopy:d,defaults:e,composeEasingObject:j}),"function"==typeof SHIFTY_DEBUG_NOW&&(a.timeoutHandler=i),"object"==typeof exports?module.exports=k:"function"==typeof define&&define.amd?define(function(){return k}):"undefined"==typeof a.Tweenable&&(a.Tweenable=k),k}();!function(){b.shallowCopy(b.prototype.formula,{easeInQuad:function(a){return Math.pow(a,2)},easeOutQuad:function(a){return-(Math.pow(a-1,2)-1)},easeInOutQuad:function(a){return(a/=.5)<1?.5*Math.pow(a,2):-.5*((a-=2)*a-2)},easeInCubic:function(a){return Math.pow(a,3)},easeOutCubic:function(a){return Math.pow(a-1,3)+1},easeInOutCubic:function(a){return(a/=.5)<1?.5*Math.pow(a,3):.5*(Math.pow(a-2,3)+2)},easeInQuart:function(a){return Math.pow(a,4)},easeOutQuart:function(a){return-(Math.pow(a-1,4)-1)},easeInOutQuart:function(a){return(a/=.5)<1?.5*Math.pow(a,4):-.5*((a-=2)*Math.pow(a,3)-2)},easeInQuint:function(a){return Math.pow(a,5)},easeOutQuint:function(a){return Math.pow(a-1,5)+1},easeInOutQuint:function(a){return(a/=.5)<1?.5*Math.pow(a,5):.5*(Math.pow(a-2,5)+2)},easeInSine:function(a){return-Math.cos(a*(Math.PI/2))+1},easeOutSine:function(a){return Math.sin(a*(Math.PI/2))},easeInOutSine:function(a){return-.5*(Math.cos(Math.PI*a)-1)},easeInExpo:function(a){return 0===a?0:Math.pow(2,10*(a-1))},easeOutExpo:function(a){return 1===a?1:-Math.pow(2,-10*a)+1},easeInOutExpo:function(a){return 0===a?0:1===a?1:(a/=.5)<1?.5*Math.pow(2,10*(a-1)):.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return-(Math.sqrt(1-a*a)-1)},easeOutCirc:function(a){return Math.sqrt(1-Math.pow(a-1,2))},easeInOutCirc:function(a){return(a/=.5)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)},easeOutBounce:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},easeInBack:function(a){var b=1.70158;return a*a*((b+1)*a-b)},easeOutBack:function(a){var b=1.70158;return(a-=1)*a*((b+1)*a+b)+1},easeInOutBack:function(a){var b=1.70158;return(a/=.5)<1?.5*a*a*(((b*=1.525)+1)*a-b):.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},elastic:function(a){return-1*Math.pow(4,-8*a)*Math.sin(2*(6*a-1)*Math.PI/2)+1},swingFromTo:function(a){var b=1.70158;return(a/=.5)<1?.5*a*a*(((b*=1.525)+1)*a-b):.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},swingFrom:function(a){var b=1.70158;return a*a*((b+1)*a-b)},swingTo:function(a){var b=1.70158;return(a-=1)*a*((b+1)*a+b)+1},bounce:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},bouncePast:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?2-(7.5625*(a-=1.5/2.75)*a+.75):2.5/2.75>a?2-(7.5625*(a-=2.25/2.75)*a+.9375):2-(7.5625*(a-=2.625/2.75)*a+.984375)},easeFromTo:function(a){return(a/=.5)<1?.5*Math.pow(a,4):-.5*((a-=2)*Math.pow(a,3)-2)},easeFrom:function(a){return Math.pow(a,4)},easeTo:function(a){return Math.pow(a,.25)}})}(),function(){function a(a,b,c,d,e,f){function g(a){return((n*a+o)*a+p)*a}function h(a){return((q*a+r)*a+s)*a}function i(a){return(3*n*a+2*o)*a+p}function j(a){return 1/(200*a)}function k(a,b){return h(m(a,b))}function l(a){return a>=0?a:0-a}function m(a,b){var c,d,e,f,h,j;for(e=a,j=0;8>j;j++){if(f=g(e)-a,l(f)e)return c;if(e>d)return d;for(;d>c;){if(f=g(e),l(f-a)f?c=e:d=e,e=.5*(d-c)+c}return e}var n=0,o=0,p=0,q=0,r=0,s=0;return p=3*b,o=3*(d-b)-p,n=1-p-o,s=3*c,r=3*(e-c)-s,q=1-s-r,k(a,j(f))}function c(b,c,d,e){return function(f){return a(f,b,c,d,e,1)}}b.setBezierFunction=function(a,d,e,f,g){var h=c(d,e,f,g);return h.x1=d,h.y1=e,h.x2=f,h.y2=g,b.prototype.formula[a]=h},b.unsetBezierFunction=function(a){delete b.prototype.formula[a]}}(),function(){function a(a,c,d,e,f){return b.tweenProps(e,c,a,d,1,0,f)}var c=new b;c._filterArgs=[],b.interpolate=function(d,e,f,g){var h=b.shallowCopy({},d),i=b.composeEasingObject(d,g||"linear");c.set({});var j=c._filterArgs;j.length=0,j[0]=h,j[1]=d,j[2]=e,j[3]=i,b.applyFilter(c,"tweenCreated"),b.applyFilter(c,"beforeTween");var k=a(d,h,e,f,i);return b.applyFilter(c,"afterTween"),k}}(),function(a){function b(a,b){B.length=0;var c,d=a.length;for(c=0;d>c;c++)B.push("_"+b+"_"+c);return B}function c(a){var b=a.match(v);return b?(1===b.length||a[0].match(u))&&b.unshift(""):b=["",""],b.join(A)}function d(b){a.each(b,function(a){var c=b[a];"string"==typeof c&&c.match(z)&&(b[a]=e(c))})}function e(a){return i(z,a,f)}function f(a){var b=g(a);return"rgb("+b[0]+","+b[1]+","+b[2]+")"}function g(a){return a=a.replace(/#/,""),3===a.length&&(a=a.split(""),a=a[0]+a[0]+a[1]+a[1]+a[2]+a[2]),C[0]=h(a.substr(0,2)),C[1]=h(a.substr(2,2)),C[2]=h(a.substr(4,2)),C}function h(a){return parseInt(a,16)}function i(a,b,c){var d=b.match(a),e=b.replace(a,A);if(d)for(var f,g=d.length,h=0;g>h;h++)f=d.shift(),e=e.replace(A,c(f));return e}function j(a){return i(x,a,k)}function k(a){for(var b=a.match(w),c=b.length,d=a.match(y)[0],e=0;c>e;e++)d+=parseInt(b[e],10)+",";return d=d.slice(0,-1)+")"}function l(d){var e={};return a.each(d,function(a){var f=d[a];if("string"==typeof f){var g=r(f);e[a]={formatString:c(f),chunkNames:b(g,a)}}}),e}function m(b,c){a.each(c,function(a){for(var d=b[a],e=r(d),f=e.length,g=0;f>g;g++)b[c[a].chunkNames[g]]=+e[g];delete b[a]})}function n(b,c){a.each(c,function(a){var d=b[a],e=o(b,c[a].chunkNames),f=p(e,c[a].chunkNames);d=q(c[a].formatString,f),b[a]=j(d)})}function o(a,b){for(var c,d={},e=b.length,f=0;e>f;f++)c=b[f],d[c]=a[c],delete a[c];return d}function p(a,b){D.length=0;for(var c=b.length,d=0;c>d;d++)D.push(a[b[d]]);return D}function q(a,b){for(var c=a,d=b.length,e=0;d>e;e++)c=c.replace(A,+b[e].toFixed(4));return c}function r(a){return a.match(w)}function s(b,c){a.each(c,function(a){for(var d=c[a],e=d.chunkNames,f=e.length,g=b[a].split(" "),h=g[g.length-1],i=0;f>i;i++)b[e[i]]=g[i]||h;delete b[a]})}function t(b,c){a.each(c,function(a){for(var d=c[a],e=d.chunkNames,f=e.length,g="",h=0;f>h;h++)g+=" "+b[e[h]],delete b[e[h]];b[a]=g.substr(1)})}var u=/(\d|\-|\.)/,v=/([^\-0-9\.]+)/g,w=/[0-9.\-]+/g,x=new RegExp("rgb\\("+w.source+/,\s*/.source+w.source+/,\s*/.source+w.source+"\\)","g"),y=/^.*\(/,z=/#([0-9]|[a-f]){3,6}/gi,A="VAL",B=[],C=[],D=[];a.prototype.filter.token={tweenCreated:function(a,b,c){d(a),d(b),d(c),this._tokenData=l(a)},beforeTween:function(a,b,c,d){s(d,this._tokenData),m(a,this._tokenData),m(b,this._tokenData),m(c,this._tokenData)},afterTween:function(a,b,c,d){n(a,this._tokenData),n(b,this._tokenData),n(c,this._tokenData),t(d,this._tokenData)}}}(b)}(window),window.Tweenable}),function(){"use strict";angular.module("angular-carousel").filter("carouselSlice",function(){return function(a,b,c){return angular.isArray(a)?a.slice(b,b+c):angular.isObject(a)?a:void 0}})}(); \ No newline at end of file diff --git a/package.json b/package.json index 0d531a0..3a3d624 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "angular-carousel", "description": "Angular Carousel - Mobile friendly touch carousel for AngularJS", - "version": "0.3.6", + "version": "0.3.7", "homepage": "http://revolunet.github.com/angular-carousel", "author": "Julien Bouquillon ", "repository": { diff --git a/src/directives/rn-carousel.js b/src/directives/rn-carousel.js index 84c756c..86d15a6 100755 --- a/src/directives/rn-carousel.js +++ b/src/directives/rn-carousel.js @@ -138,7 +138,7 @@ return true; }); return result; - }; + } return { restrict: 'A', diff --git a/src/directives/shifty.js b/src/directives/shifty.js index c327e38..ccb73ac 100644 --- a/src/directives/shifty.js +++ b/src/directives/shifty.js @@ -4,1381 +4,1420 @@ angular.module('angular-carousel.shifty', []) .factory('Tweenable', function() { - (function (root, window) { - /*! - * Shifty Core - * By Jeremy Kahn - jeremyckahn@gmail.com - */ + /*! shifty - v1.3.4 - 2014-10-29 - http://jeremyckahn.github.io/shifty */ + ;(function (root) { + + /*! + * Shifty Core + * By Jeremy Kahn - jeremyckahn@gmail.com + */ + + var Tweenable = (function () { + + 'use strict'; + + // Aliases that get defined later in this function + var formula; + + // CONSTANTS + var DEFAULT_SCHEDULE_FUNCTION; + var DEFAULT_EASING = 'linear'; + var DEFAULT_DURATION = 500; + var UPDATE_TIME = 1000 / 60; + + var _now = Date.now + ? Date.now + : function () {return +new Date();}; + + var now = typeof SHIFTY_DEBUG_NOW !== 'undefined' ? SHIFTY_DEBUG_NOW : _now; + + if (typeof window !== 'undefined') { + // requestAnimationFrame() shim by Paul Irish (modified for Shifty) + // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + DEFAULT_SCHEDULE_FUNCTION = window.requestAnimationFrame + || window.webkitRequestAnimationFrame + || window.oRequestAnimationFrame + || window.msRequestAnimationFrame + || (window.mozCancelRequestAnimationFrame + && window.mozRequestAnimationFrame) + || setTimeout; + } else { + DEFAULT_SCHEDULE_FUNCTION = setTimeout; + } - // UglifyJS define hack. Used for unit testing. Contents of this if are - // compiled away. - if (typeof SHIFTY_DEBUG_NOW === 'undefined') { - SHIFTY_DEBUG_NOW = function () { - return +new Date(); - }; + function noop () { + // NOOP! } - var Tweenable = (function () { - - 'use strict'; - - // Aliases that get defined later in this function - var formula; - - // CONSTANTS - var DEFAULT_SCHEDULE_FUNCTION; - var DEFAULT_EASING = 'linear'; - var DEFAULT_DURATION = 500; - var UPDATE_TIME = 1000 / 60; - - var _now = Date.now - ? Date.now - : function () {return +new Date();}; - - var now = SHIFTY_DEBUG_NOW - ? SHIFTY_DEBUG_NOW - : _now; - - if (typeof window !== 'undefined') { - // requestAnimationFrame() shim by Paul Irish (modified for Shifty) - // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - DEFAULT_SCHEDULE_FUNCTION = window.requestAnimationFrame - || window.webkitRequestAnimationFrame - || window.oRequestAnimationFrame - || window.msRequestAnimationFrame - || (window.mozCancelRequestAnimationFrame - && window.mozRequestAnimationFrame) - || setTimeout; - } else { - DEFAULT_SCHEDULE_FUNCTION = setTimeout; + /*! + * Handy shortcut for doing a for-in loop. This is not a "normal" each + * function, it is optimized for Shifty. The iterator function only receives + * the property name, not the value. + * @param {Object} obj + * @param {Function(string)} fn + */ + function each (obj, fn) { + var key; + for (key in obj) { + if (Object.hasOwnProperty.call(obj, key)) { + fn(key); + } } + } - function noop () { - // NOOP! - } + /*! + * Perform a shallow copy of Object properties. + * @param {Object} targetObject The object to copy into + * @param {Object} srcObject The object to copy from + * @return {Object} A reference to the augmented `targetObj` Object + */ + function shallowCopy (targetObj, srcObj) { + each(srcObj, function (prop) { + targetObj[prop] = srcObj[prop]; + }); - /*! - * Handy shortcut for doing a for-in loop. This is not a "normal" each - * function, it is optimized for Shifty. The iterator function only receives - * the property name, not the value. - * @param {Object} obj - * @param {Function(string)} fn - */ - function each (obj, fn) { - var key; - for (key in obj) { - if (Object.hasOwnProperty.call(obj, key)) { - fn(key); - } + return targetObj; + } + + /*! + * Copies each property from src onto target, but only if the property to + * copy to target is undefined. + * @param {Object} target Missing properties in this Object are filled in + * @param {Object} src + */ + function defaults (target, src) { + each(src, function (prop) { + if (typeof target[prop] === 'undefined') { + target[prop] = src[prop]; + } + }); + } + + /*! + * Calculates the interpolated tween values of an Object for a given + * timestamp. + * @param {Number} forPosition The position to compute the state for. + * @param {Object} currentState Current state properties. + * @param {Object} originalState: The original state properties the Object is + * tweening from. + * @param {Object} targetState: The destination state properties the Object + * is tweening to. + * @param {number} duration: The length of the tween in milliseconds. + * @param {number} timestamp: The UNIX epoch time at which the tween began. + * @param {Object} easing: This Object's keys must correspond to the keys in + * targetState. + */ + function tweenProps (forPosition, currentState, originalState, targetState, + duration, timestamp, easing) { + var normalizedPosition = (forPosition - timestamp) / duration; + + var prop; + for (prop in currentState) { + if (currentState.hasOwnProperty(prop)) { + currentState[prop] = tweenProp(originalState[prop], + targetState[prop], formula[easing[prop]], normalizedPosition); } } - /*! - * Perform a shallow copy of Object properties. - * @param {Object} targetObject The object to copy into - * @param {Object} srcObject The object to copy from - * @return {Object} A reference to the augmented `targetObj` Object - */ - function shallowCopy (targetObj, srcObj) { - each(srcObj, function (prop) { - targetObj[prop] = srcObj[prop]; - }); + return currentState; + } - return targetObj; - } + /*! + * Tweens a single property. + * @param {number} start The value that the tween started from. + * @param {number} end The value that the tween should end at. + * @param {Function} easingFunc The easing curve to apply to the tween. + * @param {number} position The normalized position (between 0.0 and 1.0) to + * calculate the midpoint of 'start' and 'end' against. + * @return {number} The tweened value. + */ + function tweenProp (start, end, easingFunc, position) { + return start + (end - start) * easingFunc(position); + } - /*! - * Copies each property from src onto target, but only if the property to - * copy to target is undefined. - * @param {Object} target Missing properties in this Object are filled in - * @param {Object} src - */ - function defaults (target, src) { - each(src, function (prop) { - if (typeof target[prop] === 'undefined') { - target[prop] = src[prop]; - } - }); - } + /*! + * Applies a filter to Tweenable instance. + * @param {Tweenable} tweenable The `Tweenable` instance to call the filter + * upon. + * @param {String} filterName The name of the filter to apply. + */ + function applyFilter (tweenable, filterName) { + var filters = Tweenable.prototype.filter; + var args = tweenable._filterArgs; - /*! - * Calculates the interpolated tween values of an Object for a given - * timestamp. - * @param {Number} forPosition The position to compute the state for. - * @param {Object} currentState Current state properties. - * @param {Object} originalState: The original state properties the Object is - * tweening from. - * @param {Object} targetState: The destination state properties the Object - * is tweening to. - * @param {number} duration: The length of the tween in milliseconds. - * @param {number} timestamp: The UNIX epoch time at which the tween began. - * @param {Object} easing: This Object's keys must correspond to the keys in - * targetState. - */ - function tweenProps (forPosition, currentState, originalState, targetState, - duration, timestamp, easing) { - var normalizedPosition = (forPosition - timestamp) / duration; - - var prop; - for (prop in currentState) { - if (currentState.hasOwnProperty(prop)) { - currentState[prop] = tweenProp(originalState[prop], - targetState[prop], formula[easing[prop]], normalizedPosition); - } + each(filters, function (name) { + if (typeof filters[name][filterName] !== 'undefined') { + filters[name][filterName].apply(tweenable, args); } + }); + } - return currentState; + var timeoutHandler_endTime; + var timeoutHandler_currentTime; + var timeoutHandler_isEnded; + var timeoutHandler_offset; + /*! + * Handles the update logic for one step of a tween. + * @param {Tweenable} tweenable + * @param {number} timestamp + * @param {number} duration + * @param {Object} currentState + * @param {Object} originalState + * @param {Object} targetState + * @param {Object} easing + * @param {Function(Object, *, number)} step + * @param {Function(Function,number)}} schedule + */ + function timeoutHandler (tweenable, timestamp, duration, currentState, + originalState, targetState, easing, step, schedule) { + timeoutHandler_endTime = timestamp + duration; + timeoutHandler_currentTime = Math.min(now(), timeoutHandler_endTime); + timeoutHandler_isEnded = + timeoutHandler_currentTime >= timeoutHandler_endTime; + + timeoutHandler_offset = duration - ( + timeoutHandler_endTime - timeoutHandler_currentTime); + + if (tweenable.isPlaying() && !timeoutHandler_isEnded) { + tweenable._scheduleId = schedule(tweenable._timeoutHandler, UPDATE_TIME); + + applyFilter(tweenable, 'beforeTween'); + tweenProps(timeoutHandler_currentTime, currentState, originalState, + targetState, duration, timestamp, easing); + applyFilter(tweenable, 'afterTween'); + + step(currentState, tweenable._attachment, timeoutHandler_offset); + } else if (timeoutHandler_isEnded) { + step(targetState, tweenable._attachment, timeoutHandler_offset); + tweenable.stop(true); } + } - /*! - * Tweens a single property. - * @param {number} start The value that the tween started from. - * @param {number} end The value that the tween should end at. - * @param {Function} easingFunc The easing curve to apply to the tween. - * @param {number} position The normalized position (between 0.0 and 1.0) to - * calculate the midpoint of 'start' and 'end' against. - * @return {number} The tweened value. - */ - function tweenProp (start, end, easingFunc, position) { - return start + (end - start) * easingFunc(position); - } - /*! - * Applies a filter to Tweenable instance. - * @param {Tweenable} tweenable The `Tweenable` instance to call the filter - * upon. - * @param {String} filterName The name of the filter to apply. - */ - function applyFilter (tweenable, filterName) { - var filters = Tweenable.prototype.filter; - var args = tweenable._filterArgs; - - each(filters, function (name) { - if (typeof filters[name][filterName] !== 'undefined') { - filters[name][filterName].apply(tweenable, args); + /*! + * Creates a usable easing Object from either a string or another easing + * Object. If `easing` is an Object, then this function clones it and fills + * in the missing properties with "linear". + * @param {Object} fromTweenParams + * @param {Object|string} easing + */ + function composeEasingObject (fromTweenParams, easing) { + var composedEasing = {}; + + if (typeof easing === 'string') { + each(fromTweenParams, function (prop) { + composedEasing[prop] = easing; + }); + } else { + each(fromTweenParams, function (prop) { + if (!composedEasing[prop]) { + composedEasing[prop] = easing[prop] || DEFAULT_EASING; } }); } - var timeoutHandler_endTime; - var timeoutHandler_currentTime; - var timeoutHandler_isEnded; - /*! - * Handles the update logic for one step of a tween. - * @param {Tweenable} tweenable - * @param {number} timestamp - * @param {number} duration - * @param {Object} currentState - * @param {Object} originalState - * @param {Object} targetState - * @param {Object} easing - * @param {Function} step - * @param {Function(Function,number)}} schedule - */ - function timeoutHandler (tweenable, timestamp, duration, currentState, - originalState, targetState, easing, step, schedule) { - timeoutHandler_endTime = timestamp + duration; - timeoutHandler_currentTime = Math.min(now(), timeoutHandler_endTime); - timeoutHandler_isEnded = timeoutHandler_currentTime >= timeoutHandler_endTime; - - if (tweenable.isPlaying() && !timeoutHandler_isEnded) { - schedule(tweenable._timeoutHandler, UPDATE_TIME); - - applyFilter(tweenable, 'beforeTween'); - tweenProps(timeoutHandler_currentTime, currentState, originalState, - targetState, duration, timestamp, easing); - applyFilter(tweenable, 'afterTween'); - - step(currentState); - } else if (timeoutHandler_isEnded) { - step(targetState); - tweenable.stop(true); - } - } - - - /*! - * Creates a usable easing Object from either a string or another easing - * Object. If `easing` is an Object, then this function clones it and fills - * in the missing properties with "linear". - * @param {Object} fromTweenParams - * @param {Object|string} easing - */ - function composeEasingObject (fromTweenParams, easing) { - var composedEasing = {}; - - if (typeof easing === 'string') { - each(fromTweenParams, function (prop) { - composedEasing[prop] = easing; - }); - } else { - each(fromTweenParams, function (prop) { - if (!composedEasing[prop]) { - composedEasing[prop] = easing[prop] || DEFAULT_EASING; - } - }); - } + return composedEasing; + } - return composedEasing; + /** + * Tweenable constructor. + * @param {Object=} opt_initialState The values that the initial tween should start at if a "from" object is not provided to Tweenable#tween. + * @param {Object=} opt_config See Tweenable.prototype.setConfig() + * @constructor + */ + function Tweenable (opt_initialState, opt_config) { + this._currentState = opt_initialState || {}; + this._configured = false; + this._scheduleFunction = DEFAULT_SCHEDULE_FUNCTION; + + // To prevent unnecessary calls to setConfig do not set default configuration here. + // Only set default configuration immediately before tweening if none has been set. + if (typeof opt_config !== 'undefined') { + this.setConfig(opt_config); } + } - /** - * Tweenable constructor. - * @param {Object=} opt_initialState The values that the initial tween should start at if a "from" object is not provided to Tweenable#tween. - * @param {Object=} opt_config See Tweenable.prototype.setConfig() - * @constructor - */ - function Tweenable (opt_initialState, opt_config) { - this._currentState = opt_initialState || {}; - this._configured = false; - this._scheduleFunction = DEFAULT_SCHEDULE_FUNCTION; - - // To prevent unnecessary calls to setConfig do not set default configuration here. - // Only set default configuration immediately before tweening if none has been set. - if (typeof opt_config !== 'undefined') { - this.setConfig(opt_config); - } + /** + * Configure and start a tween. + * @param {Object=} opt_config See Tweenable.prototype.setConfig() + * @return {Tweenable} + */ + Tweenable.prototype.tween = function (opt_config) { + if (this._isTweening) { + return this; } - /** - * Configure and start a tween. - * @param {Object=} opt_config See Tweenable.prototype.setConfig() - * @return {Tweenable} - */ - Tweenable.prototype.tween = function (opt_config) { - if (this._isTweening) { - return this; - } + // Only set default config if no configuration has been set previously and none is provided now. + if (opt_config !== undefined || !this._configured) { + this.setConfig(opt_config); + } - // Only set default config if no configuration has been set previously and none is provided now. - if (opt_config !== undefined || !this._configured) { - this.setConfig(opt_config); - } + this._timestamp = now(); + this._start(this.get(), this._attachment); + return this.resume(); + }; - this._start(this.get()); - return this.resume(); - }; + /** + * Sets the tween configuration. `config` may have the following options: + * + * - __from__ (_Object=_): Starting position. If omitted, the current state is used. + * - __to__ (_Object=_): Ending position. + * - __duration__ (_number=_): How many milliseconds to animate for. + * - __start__ (_Function(Object)_): Function to execute when the tween begins. Receives the state of the tween as the first parameter. Attachment is the second parameter. + * - __step__ (_Function(Object, *, number)_): Function to execute on every tick. Receives the state of the tween as the first parameter. Attachment is the second parameter, and the time elapsed since the start of the tween is the third parameter. This function is not called on the final step of the animation, but `finish` is. + * - __finish__ (_Function(Object, *)_): Function to execute upon tween completion. Receives the state of the tween as the first parameter. Attachment is the second parameter. + * - __easing__ (_Object|string=_): Easing curve name(s) to use for the tween. + * - __attachment__ (_Object|string|any=_): Value that is attached to this instance and passed on to the step/start/finish methods. + * @param {Object} config + * @return {Tweenable} + */ + Tweenable.prototype.setConfig = function (config) { + config = config || {}; + this._configured = true; - /** - * Sets the tween configuration. `config` may have the following options: - * - * - __from__ (_Object=_): Starting position. If omitted, the current state is used. - * - __to__ (_Object=_): Ending position. - * - __duration__ (_number=_): How many milliseconds to animate for. - * - __start__ (_Function(Object)=_): Function to execute when the tween begins. Receives the state of the tween as the only parameter. - * - __step__ (_Function(Object)=_): Function to execute on every tick. Receives the state of the tween as the only parameter. This function is not called on the final step of the animation, but `finish` is. - * - __finish__ (_Function(Object)=_): Function to execute upon tween completion. Receives the state of the tween as the only parameter. - * - __easing__ (_Object|string=_): Easing curve name(s) to use for the tween. - * @param {Object} config - * @return {Tweenable} - */ - Tweenable.prototype.setConfig = function (config) { - config = config || {}; - this._configured = true; - - // Init the internal state - this._pausedAtTime = null; - this._start = config.start || noop; - this._step = config.step || noop; - this._finish = config.finish || noop; - this._duration = config.duration || DEFAULT_DURATION; - this._currentState = config.from || this.get(); - this._originalState = this.get(); - this._targetState = config.to || this.get(); - this._timestamp = now(); - - // Aliases used below - var currentState = this._currentState; - var targetState = this._targetState; - - // Ensure that there is always something to tween to. - defaults(targetState, currentState); - - this._easing = composeEasingObject( - currentState, config.easing || DEFAULT_EASING); - - this._filterArgs = - [currentState, this._originalState, targetState, this._easing]; - - applyFilter(this, 'tweenCreated'); - return this; - }; + // Attach something to this Tweenable instance (e.g.: a DOM element, an object, a string, etc.); + this._attachment = config.attachment; - /** - * Gets the current state. - * @return {Object} - */ - Tweenable.prototype.get = function () { - return shallowCopy({}, this._currentState); - }; + // Init the internal state + this._pausedAtTime = null; + this._scheduleId = null; + this._start = config.start || noop; + this._step = config.step || noop; + this._finish = config.finish || noop; + this._duration = config.duration || DEFAULT_DURATION; + this._currentState = config.from || this.get(); + this._originalState = this.get(); + this._targetState = config.to || this.get(); - /** - * Sets the current state. - * @param {Object} state - */ - Tweenable.prototype.set = function (state) { - this._currentState = state; - }; + // Aliases used below + var currentState = this._currentState; + var targetState = this._targetState; - /** - * Pauses a tween. Paused tweens can be resumed from the point at which they were paused. This is different than [`stop()`](#stop), as that method causes a tween to start over when it is resumed. - * @return {Tweenable} - */ - Tweenable.prototype.pause = function () { - this._pausedAtTime = now(); - this._isPaused = true; - return this; - }; + // Ensure that there is always something to tween to. + defaults(targetState, currentState); - /** - * Resumes a paused tween. - * @return {Tweenable} - */ - Tweenable.prototype.resume = function () { - if (this._isPaused) { - this._timestamp += now() - this._pausedAtTime; - } + this._easing = composeEasingObject( + currentState, config.easing || DEFAULT_EASING); - this._isPaused = false; - this._isTweening = true; + this._filterArgs = + [currentState, this._originalState, targetState, this._easing]; - var self = this; - this._timeoutHandler = function () { - timeoutHandler(self, self._timestamp, self._duration, self._currentState, - self._originalState, self._targetState, self._easing, self._step, - self._scheduleFunction); - }; + applyFilter(this, 'tweenCreated'); + return this; + }; - this._timeoutHandler(); + /** + * Gets the current state. + * @return {Object} + */ + Tweenable.prototype.get = function () { + return shallowCopy({}, this._currentState); + }; - return this; - }; + /** + * Sets the current state. + * @param {Object} state + */ + Tweenable.prototype.set = function (state) { + this._currentState = state; + }; - /** - * Stops and cancels a tween. - * @param {boolean=} gotoEnd If false or omitted, the tween just stops at its current state, and the "finish" handler is not invoked. If true, the tweened object's values are instantly set to the target values, and "finish" is invoked. - * @return {Tweenable} - */ - Tweenable.prototype.stop = function (gotoEnd) { - this._isTweening = false; - this._isPaused = false; - this._timeoutHandler = noop; + /** + * Pauses a tween. Paused tweens can be resumed from the point at which they were paused. This is different than [`stop()`](#stop), as that method causes a tween to start over when it is resumed. + * @return {Tweenable} + */ + Tweenable.prototype.pause = function () { + this._pausedAtTime = now(); + this._isPaused = true; + return this; + }; - if (gotoEnd) { - shallowCopy(this._currentState, this._targetState); - applyFilter(this, 'afterTweenEnd'); - this._finish.call(this, this._currentState); - } + /** + * Resumes a paused tween. + * @return {Tweenable} + */ + Tweenable.prototype.resume = function () { + if (this._isPaused) { + this._timestamp += now() - this._pausedAtTime; + } - return this; - }; + this._isPaused = false; + this._isTweening = true; - /** - * Returns whether or not a tween is running. - * @return {boolean} - */ - Tweenable.prototype.isPlaying = function () { - return this._isTweening && !this._isPaused; + var self = this; + this._timeoutHandler = function () { + timeoutHandler(self, self._timestamp, self._duration, self._currentState, + self._originalState, self._targetState, self._easing, self._step, + self._scheduleFunction); }; - /** - * Sets a custom schedule function. - * - * If a custom function is not set the default one is used [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame) if available, otherwise [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout)). - * - * @param {Function(Function,number)} scheduleFunction The function to be called to schedule the next frame to be rendered - */ - Tweenable.prototype.setScheduleFunction = function (scheduleFunction) { - this._scheduleFunction = scheduleFunction; - }; + this._timeoutHandler(); - /** - * `delete`s all "own" properties. Call this when the `Tweenable` instance is no longer needed to free memory. - */ - Tweenable.prototype.dispose = function () { - var prop; - for (prop in this) { - if (this.hasOwnProperty(prop)) { - delete this[prop]; - } - } - }; + return this; + }; - /*! - * Filters are used for transforming the properties of a tween at various - * points in a Tweenable's life cycle. See the README for more info on this. - */ - Tweenable.prototype.filter = {}; - - /*! - * This object contains all of the tweens available to Shifty. It is extendible - simply attach properties to the Tweenable.prototype.formula Object following the same format at linear. - * - * `pos` should be a normalized `number` (between 0 and 1). - */ - Tweenable.prototype.formula = { - linear: function (pos) { - return pos; - } - }; + /** + * Move the state of the animation to a specific point in the tween's timeline. + * If the animation is not running, this will cause the `step` handlers to be + * called. + * @param {millisecond} millisecond The millisecond of the animation to seek to. + * @return {Tweenable} + */ + Tweenable.prototype.seek = function (millisecond) { + this._timestamp = now() - millisecond; - formula = Tweenable.prototype.formula; - - shallowCopy(Tweenable, { - 'now': now - ,'each': each - ,'tweenProps': tweenProps - ,'tweenProp': tweenProp - ,'applyFilter': applyFilter - ,'shallowCopy': shallowCopy - ,'defaults': defaults - ,'composeEasingObject': composeEasingObject - }); + if (!this.isPlaying()) { + this._isTweening = true; + this._isPaused = false; - // `root` is provided in the intro/outro files. + // If the animation is not running, call timeoutHandler to make sure that + // any step handlers are run. + timeoutHandler(this, this._timestamp, this._duration, this._currentState, + this._originalState, this._targetState, this._easing, this._step, + this._scheduleFunction); - // A hook used for unit testing. - if (typeof SHIFTY_DEBUG_NOW === 'function') { - root.timeoutHandler = timeoutHandler; + this._timeoutHandler(); + this.pause(); } - // Bootstrap Tweenable appropriately for the environment. - if (typeof exports === 'object') { - // CommonJS - module.exports = Tweenable; - } else if (typeof define === 'function' && define.amd) { - // AMD - define(function () {return Tweenable;}); - } else if (typeof root.Tweenable === 'undefined') { - // Browser: Make `Tweenable` globally accessible. - root.Tweenable = Tweenable; + return this; + }; + + /** + * Stops and cancels a tween. + * @param {boolean=} gotoEnd If false or omitted, the tween just stops at its current state, and the "finish" handler is not invoked. If true, the tweened object's values are instantly set to the target values, and "finish" is invoked. + * @return {Tweenable} + */ + Tweenable.prototype.stop = function (gotoEnd) { + this._isTweening = false; + this._isPaused = false; + this._timeoutHandler = noop; + + (root.cancelAnimationFrame || + root.webkitCancelAnimationFrame || + root.oCancelAnimationFrame || + root.msCancelAnimationFrame || + root.mozCancelRequestAnimationFrame || + root.clearTimeout)(this._scheduleId); + + if (gotoEnd) { + shallowCopy(this._currentState, this._targetState); + applyFilter(this, 'afterTweenEnd'); + this._finish.call(this, this._currentState, this._attachment); } - return Tweenable; + return this; + }; - } ()); - - window.Tweenable = Tweenable; - /*! - * All equations are adapted from Thomas Fuchs' [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/penner.js). + /** + * Returns whether or not a tween is running. + * @return {boolean} + */ + Tweenable.prototype.isPlaying = function () { + return this._isTweening && !this._isPaused; + }; + + /** + * Sets a custom schedule function. * - * Based on Easing Equations (c) 2003 [Robert Penner](http://www.robertpenner.com/), all rights reserved. This work is [subject to terms](http://www.robertpenner.com/easing_terms_of_use.html). + * If a custom function is not set the default one is used [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame) if available, otherwise [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout)). + * + * @param {Function(Function,number)} scheduleFunction The function to be called to schedule the next frame to be rendered + */ + Tweenable.prototype.setScheduleFunction = function (scheduleFunction) { + this._scheduleFunction = scheduleFunction; + }; + + /** + * `delete`s all "own" properties. Call this when the `Tweenable` instance is no longer needed to free memory. */ + Tweenable.prototype.dispose = function () { + var prop; + for (prop in this) { + if (this.hasOwnProperty(prop)) { + delete this[prop]; + } + } + }; /*! - * TERMS OF USE - EASING EQUATIONS - * Open source under the BSD License. - * Easing Equations (c) 2003 Robert Penner, all rights reserved. + * Filters are used for transforming the properties of a tween at various + * points in a Tweenable's life cycle. See the README for more info on this. */ + Tweenable.prototype.filter = {}; - ;(function () { - - Tweenable.shallowCopy(Tweenable.prototype.formula, { - easeInQuad: function (pos) { - return Math.pow(pos, 2); - }, - - easeOutQuad: function (pos) { - return -(Math.pow((pos - 1), 2) - 1); - }, - - easeInOutQuad: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,2);} - return -0.5 * ((pos -= 2) * pos - 2); - }, - - easeInCubic: function (pos) { - return Math.pow(pos, 3); - }, - - easeOutCubic: function (pos) { - return (Math.pow((pos - 1), 3) + 1); - }, - - easeInOutCubic: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,3);} - return 0.5 * (Math.pow((pos - 2),3) + 2); - }, - - easeInQuart: function (pos) { - return Math.pow(pos, 4); - }, - - easeOutQuart: function (pos) { - return -(Math.pow((pos - 1), 4) - 1); - }, - - easeInOutQuart: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);} - return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2); - }, - - easeInQuint: function (pos) { - return Math.pow(pos, 5); - }, - - easeOutQuint: function (pos) { - return (Math.pow((pos - 1), 5) + 1); - }, - - easeInOutQuint: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,5);} - return 0.5 * (Math.pow((pos - 2),5) + 2); - }, - - easeInSine: function (pos) { - return -Math.cos(pos * (Math.PI / 2)) + 1; - }, - - easeOutSine: function (pos) { - return Math.sin(pos * (Math.PI / 2)); - }, - - easeInOutSine: function (pos) { - return (-0.5 * (Math.cos(Math.PI * pos) - 1)); - }, - - easeInExpo: function (pos) { - return (pos === 0) ? 0 : Math.pow(2, 10 * (pos - 1)); - }, - - easeOutExpo: function (pos) { - return (pos === 1) ? 1 : -Math.pow(2, -10 * pos) + 1; - }, - - easeInOutExpo: function (pos) { - if (pos === 0) {return 0;} - if (pos === 1) {return 1;} - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(2,10 * (pos - 1));} - return 0.5 * (-Math.pow(2, -10 * --pos) + 2); - }, - - easeInCirc: function (pos) { - return -(Math.sqrt(1 - (pos * pos)) - 1); - }, - - easeOutCirc: function (pos) { - return Math.sqrt(1 - Math.pow((pos - 1), 2)); - }, - - easeInOutCirc: function (pos) { - if ((pos /= 0.5) < 1) {return -0.5 * (Math.sqrt(1 - pos * pos) - 1);} - return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1); - }, - - easeOutBounce: function (pos) { - if ((pos) < (1 / 2.75)) { - return (7.5625 * pos * pos); - } else if (pos < (2 / 2.75)) { - return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); - } else if (pos < (2.5 / 2.75)) { - return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); - } else { - return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); - } - }, - - easeInBack: function (pos) { - var s = 1.70158; - return (pos) * pos * ((s + 1) * pos - s); - }, - - easeOutBack: function (pos) { - var s = 1.70158; - return (pos = pos - 1) * pos * ((s + 1) * pos + s) + 1; - }, - - easeInOutBack: function (pos) { - var s = 1.70158; - if ((pos /= 0.5) < 1) {return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));} - return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2); - }, - - elastic: function (pos) { - return -1 * Math.pow(4,-8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1; - }, - - swingFromTo: function (pos) { - var s = 1.70158; - return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) : - 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2); - }, - - swingFrom: function (pos) { - var s = 1.70158; - return pos * pos * ((s + 1) * pos - s); - }, - - swingTo: function (pos) { - var s = 1.70158; - return (pos -= 1) * pos * ((s + 1) * pos + s) + 1; - }, - - bounce: function (pos) { - if (pos < (1 / 2.75)) { - return (7.5625 * pos * pos); - } else if (pos < (2 / 2.75)) { - return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); - } else if (pos < (2.5 / 2.75)) { - return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); - } else { - return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); - } - }, - - bouncePast: function (pos) { - if (pos < (1 / 2.75)) { - return (7.5625 * pos * pos); - } else if (pos < (2 / 2.75)) { - return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); - } else if (pos < (2.5 / 2.75)) { - return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); - } else { - return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); - } - }, + /*! + * This object contains all of the tweens available to Shifty. It is extendible - simply attach properties to the Tweenable.prototype.formula Object following the same format at linear. + * + * `pos` should be a normalized `number` (between 0 and 1). + */ + Tweenable.prototype.formula = { + linear: function (pos) { + return pos; + } + }; + + formula = Tweenable.prototype.formula; + + shallowCopy(Tweenable, { + 'now': now + ,'each': each + ,'tweenProps': tweenProps + ,'tweenProp': tweenProp + ,'applyFilter': applyFilter + ,'shallowCopy': shallowCopy + ,'defaults': defaults + ,'composeEasingObject': composeEasingObject + }); + + // `root` is provided in the intro/outro files. + + // A hook used for unit testing. + if (typeof SHIFTY_DEBUG_NOW === 'function') { + root.timeoutHandler = timeoutHandler; + } - easeFromTo: function (pos) { - if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);} - return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2); - }, + // Bootstrap Tweenable appropriately for the environment. + if (typeof exports === 'object') { + // CommonJS + module.exports = Tweenable; + } else if (typeof define === 'function' && define.amd) { + // AMD + define(function () {return Tweenable;}); + } else if (typeof root.Tweenable === 'undefined') { + // Browser: Make `Tweenable` globally accessible. + root.Tweenable = Tweenable; + } - easeFrom: function (pos) { - return Math.pow(pos,4); - }, + return Tweenable; - easeTo: function (pos) { - return Math.pow(pos,0.25); + } ()); + + /*! + * All equations are adapted from Thomas Fuchs' [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/penner.js). + * + * Based on Easing Equations (c) 2003 [Robert Penner](http://www.robertpenner.com/), all rights reserved. This work is [subject to terms](http://www.robertpenner.com/easing_terms_of_use.html). + */ + + /*! + * TERMS OF USE - EASING EQUATIONS + * Open source under the BSD License. + * Easing Equations (c) 2003 Robert Penner, all rights reserved. + */ + + ;(function () { + + Tweenable.shallowCopy(Tweenable.prototype.formula, { + easeInQuad: function (pos) { + return Math.pow(pos, 2); + }, + + easeOutQuad: function (pos) { + return -(Math.pow((pos - 1), 2) - 1); + }, + + easeInOutQuad: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,2);} + return -0.5 * ((pos -= 2) * pos - 2); + }, + + easeInCubic: function (pos) { + return Math.pow(pos, 3); + }, + + easeOutCubic: function (pos) { + return (Math.pow((pos - 1), 3) + 1); + }, + + easeInOutCubic: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,3);} + return 0.5 * (Math.pow((pos - 2),3) + 2); + }, + + easeInQuart: function (pos) { + return Math.pow(pos, 4); + }, + + easeOutQuart: function (pos) { + return -(Math.pow((pos - 1), 4) - 1); + }, + + easeInOutQuart: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);} + return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2); + }, + + easeInQuint: function (pos) { + return Math.pow(pos, 5); + }, + + easeOutQuint: function (pos) { + return (Math.pow((pos - 1), 5) + 1); + }, + + easeInOutQuint: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,5);} + return 0.5 * (Math.pow((pos - 2),5) + 2); + }, + + easeInSine: function (pos) { + return -Math.cos(pos * (Math.PI / 2)) + 1; + }, + + easeOutSine: function (pos) { + return Math.sin(pos * (Math.PI / 2)); + }, + + easeInOutSine: function (pos) { + return (-0.5 * (Math.cos(Math.PI * pos) - 1)); + }, + + easeInExpo: function (pos) { + return (pos === 0) ? 0 : Math.pow(2, 10 * (pos - 1)); + }, + + easeOutExpo: function (pos) { + return (pos === 1) ? 1 : -Math.pow(2, -10 * pos) + 1; + }, + + easeInOutExpo: function (pos) { + if (pos === 0) {return 0;} + if (pos === 1) {return 1;} + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(2,10 * (pos - 1));} + return 0.5 * (-Math.pow(2, -10 * --pos) + 2); + }, + + easeInCirc: function (pos) { + return -(Math.sqrt(1 - (pos * pos)) - 1); + }, + + easeOutCirc: function (pos) { + return Math.sqrt(1 - Math.pow((pos - 1), 2)); + }, + + easeInOutCirc: function (pos) { + if ((pos /= 0.5) < 1) {return -0.5 * (Math.sqrt(1 - pos * pos) - 1);} + return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1); + }, + + easeOutBounce: function (pos) { + if ((pos) < (1 / 2.75)) { + return (7.5625 * pos * pos); + } else if (pos < (2 / 2.75)) { + return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); + } else if (pos < (2.5 / 2.75)) { + return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); + } else { + return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); } - }); + }, + + easeInBack: function (pos) { + var s = 1.70158; + return (pos) * pos * ((s + 1) * pos - s); + }, + + easeOutBack: function (pos) { + var s = 1.70158; + return (pos = pos - 1) * pos * ((s + 1) * pos + s) + 1; + }, + + easeInOutBack: function (pos) { + var s = 1.70158; + if ((pos /= 0.5) < 1) {return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));} + return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2); + }, + + elastic: function (pos) { + return -1 * Math.pow(4,-8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1; + }, + + swingFromTo: function (pos) { + var s = 1.70158; + return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) : + 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2); + }, + + swingFrom: function (pos) { + var s = 1.70158; + return pos * pos * ((s + 1) * pos - s); + }, + + swingTo: function (pos) { + var s = 1.70158; + return (pos -= 1) * pos * ((s + 1) * pos + s) + 1; + }, + + bounce: function (pos) { + if (pos < (1 / 2.75)) { + return (7.5625 * pos * pos); + } else if (pos < (2 / 2.75)) { + return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); + } else if (pos < (2.5 / 2.75)) { + return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); + } else { + return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); + } + }, + + bouncePast: function (pos) { + if (pos < (1 / 2.75)) { + return (7.5625 * pos * pos); + } else if (pos < (2 / 2.75)) { + return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75); + } else if (pos < (2.5 / 2.75)) { + return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375); + } else { + return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375); + } + }, - }()); + easeFromTo: function (pos) { + if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,4);} + return -0.5 * ((pos -= 2) * Math.pow(pos,3) - 2); + }, - /*! - * The Bezier magic in this file is adapted/copied almost wholesale from - * [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/cubic-bezier.js), - * which was adapted from Apple code (which probably came from - * [here](http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h)). - * Special thanks to Apple and Thomas Fuchs for much of this code. - */ + easeFrom: function (pos) { + return Math.pow(pos,4); + }, + easeTo: function (pos) { + return Math.pow(pos,0.25); + } + }); + + }()); + + /*! + * The Bezier magic in this file is adapted/copied almost wholesale from + * [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/cubic-bezier.js), + * which was adapted from Apple code (which probably came from + * [here](http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h)). + * Special thanks to Apple and Thomas Fuchs for much of this code. + */ + + /*! + * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder(s) nor the names of any + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ;(function () { + // port of webkit cubic bezier handling by http://www.netzgesta.de/dev/ + function cubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration) { + var ax = 0,bx = 0,cx = 0,ay = 0,by = 0,cy = 0; + function sampleCurveX(t) {return ((ax * t + bx) * t + cx) * t;} + function sampleCurveY(t) {return ((ay * t + by) * t + cy) * t;} + function sampleCurveDerivativeX(t) {return (3.0 * ax * t + 2.0 * bx) * t + cx;} + function solveEpsilon(duration) {return 1.0 / (200.0 * duration);} + function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));} + function fabs(n) {if (n >= 0) {return n;}else {return 0 - n;}} + function solveCurveX(x,epsilon) { + var t0,t1,t2,x2,d2,i; + for (t2 = x, i = 0; i < 8; i++) {x2 = sampleCurveX(t2) - x; if (fabs(x2) < epsilon) {return t2;} d2 = sampleCurveDerivativeX(t2); if (fabs(d2) < 1e-6) {break;} t2 = t2 - x2 / d2;} + t0 = 0.0; t1 = 1.0; t2 = x; if (t2 < t0) {return t0;} if (t2 > t1) {return t1;} + while (t0 < t1) {x2 = sampleCurveX(t2); if (fabs(x2 - x) < epsilon) {return t2;} if (x > x2) {t0 = t2;}else {t1 = t2;} t2 = (t1 - t0) * 0.5 + t0;} + return t2; // Failure. + } + cx = 3.0 * p1x; bx = 3.0 * (p2x - p1x) - cx; ax = 1.0 - cx - bx; cy = 3.0 * p1y; by = 3.0 * (p2y - p1y) - cy; ay = 1.0 - cy - by; + return solve(t, solveEpsilon(duration)); + } /*! - * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: + * getCubicBezierTransition(x1, y1, x2, y2) -> Function * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * Generates a transition easing function that is compatible + * with WebKit's CSS transitions `-webkit-transition-timing-function` + * CSS property. * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * The W3C has more information about + * + * CSS3 transition timing functions. * - * 3. Neither the name of the copyright holder(s) nor the names of any - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @return {function} */ - ;(function () { - // port of webkit cubic bezier handling by http://www.netzgesta.de/dev/ - function cubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration) { - var ax = 0,bx = 0,cx = 0,ay = 0,by = 0,cy = 0; - function sampleCurveX(t) {return ((ax * t + bx) * t + cx) * t;} - function sampleCurveY(t) {return ((ay * t + by) * t + cy) * t;} - function sampleCurveDerivativeX(t) {return (3.0 * ax * t + 2.0 * bx) * t + cx;} - function solveEpsilon(duration) {return 1.0 / (200.0 * duration);} - function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));} - function fabs(n) {if (n >= 0) {return n;}else {return 0 - n;}} - function solveCurveX(x,epsilon) { - var t0,t1,t2,x2,d2,i; - for (t2 = x, i = 0; i < 8; i++) {x2 = sampleCurveX(t2) - x; if (fabs(x2) < epsilon) {return t2;} d2 = sampleCurveDerivativeX(t2); if (fabs(d2) < 1e-6) {break;} t2 = t2 - x2 / d2;} - t0 = 0.0; t1 = 1.0; t2 = x; if (t2 < t0) {return t0;} if (t2 > t1) {return t1;} - while (t0 < t1) {x2 = sampleCurveX(t2); if (fabs(x2 - x) < epsilon) {return t2;} if (x > x2) {t0 = t2;}else {t1 = t2;} t2 = (t1 - t0) * 0.5 + t0;} - return t2; // Failure. - } - cx = 3.0 * p1x; bx = 3.0 * (p2x - p1x) - cx; ax = 1.0 - cx - bx; cy = 3.0 * p1y; by = 3.0 * (p2y - p1y) - cy; ay = 1.0 - cy - by; - return solve(t, solveEpsilon(duration)); - } - /*! - * getCubicBezierTransition(x1, y1, x2, y2) -> Function - * - * Generates a transition easing function that is compatible - * with WebKit's CSS transitions `-webkit-transition-timing-function` - * CSS property. - * - * The W3C has more information about - * - * CSS3 transition timing functions. - * - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @return {function} - */ - function getCubicBezierTransition (x1, y1, x2, y2) { - return function (pos) { - return cubicBezierAtTime(pos,x1,y1,x2,y2,1); - }; - } - // End ported code - - /** - * Creates a Bezier easing function and attaches it to `Tweenable.prototype.formula`. This function gives you total control over the easing curve. Matthew Lein's [Ceaser](http://matthewlein.com/ceaser/) is a useful tool for visualizing the curves you can make with this function. - * - * @param {string} name The name of the easing curve. Overwrites the old easing function on Tweenable.prototype.formula if it exists. - * @param {number} x1 - * @param {number} y1 - * @param {number} x2 - * @param {number} y2 - * @return {function} The easing function that was attached to Tweenable.prototype.formula. - */ - Tweenable.setBezierFunction = function (name, x1, y1, x2, y2) { - var cubicBezierTransition = getCubicBezierTransition(x1, y1, x2, y2); - cubicBezierTransition.x1 = x1; - cubicBezierTransition.y1 = y1; - cubicBezierTransition.x2 = x2; - cubicBezierTransition.y2 = y2; - - return Tweenable.prototype.formula[name] = cubicBezierTransition; + function getCubicBezierTransition (x1, y1, x2, y2) { + return function (pos) { + return cubicBezierAtTime(pos,x1,y1,x2,y2,1); }; + } + // End ported code + /** + * Creates a Bezier easing function and attaches it to `Tweenable.prototype.formula`. This function gives you total control over the easing curve. Matthew Lein's [Ceaser](http://matthewlein.com/ceaser/) is a useful tool for visualizing the curves you can make with this function. + * + * @param {string} name The name of the easing curve. Overwrites the old easing function on Tweenable.prototype.formula if it exists. + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @return {function} The easing function that was attached to Tweenable.prototype.formula. + */ + Tweenable.setBezierFunction = function (name, x1, y1, x2, y2) { + var cubicBezierTransition = getCubicBezierTransition(x1, y1, x2, y2); + cubicBezierTransition.x1 = x1; + cubicBezierTransition.y1 = y1; + cubicBezierTransition.x2 = x2; + cubicBezierTransition.y2 = y2; - /** - * `delete`s an easing function from `Tweenable.prototype.formula`. Be careful with this method, as it `delete`s whatever easing formula matches `name` (which means you can delete default Shifty easing functions). - * - * @param {string} name The name of the easing function to delete. - * @return {function} - */ - Tweenable.unsetBezierFunction = function (name) { - delete Tweenable.prototype.formula[name]; - }; + return Tweenable.prototype.formula[name] = cubicBezierTransition; + }; - })(); - ;(function () { + /** + * `delete`s an easing function from `Tweenable.prototype.formula`. Be careful with this method, as it `delete`s whatever easing formula matches `name` (which means you can delete default Shifty easing functions). + * + * @param {string} name The name of the easing function to delete. + * @return {function} + */ + Tweenable.unsetBezierFunction = function (name) { + delete Tweenable.prototype.formula[name]; + }; - function getInterpolatedValues ( - from, current, targetState, position, easing) { - return Tweenable.tweenProps( - position, current, from, targetState, 1, 0, easing); - } + })(); - // Fake a Tweenable and patch some internals. This approach allows us to - // skip uneccessary processing and object recreation, cutting down on garbage - // collection pauses. - var mockTweenable = new Tweenable(); - mockTweenable._filterArgs = []; - - /** - * Compute the midpoint of two Objects. This method effectively calculates a specific frame of animation that [Tweenable#tween](shifty.core.js.html#tween) does many times over the course of a tween. - * - * Example: - * - * ``` - * var interpolatedValues = Tweenable.interpolate({ - * width: '100px', - * opacity: 0, - * color: '#fff' - * }, { - * width: '200px', - * opacity: 1, - * color: '#000' - * }, 0.5); - * - * console.log(interpolatedValues); - * // {opacity: 0.5, width: "150px", color: "rgb(127,127,127)"} - * ``` - * - * @param {Object} from The starting values to tween from. - * @param {Object} targetState The ending values to tween to. - * @param {number} position The normalized position value (between 0.0 and 1.0) to interpolate the values between `from` and `to` for. `from` represents 0 and `to` represents `1`. - * @param {string|Object} easing The easing curve(s) to calculate the midpoint against. You can reference any easing function attached to `Tweenable.prototype.formula`. If omitted, this defaults to "linear". - * @return {Object} - */ - Tweenable.interpolate = function (from, targetState, position, easing) { - var current = Tweenable.shallowCopy({}, from); - var easingObject = Tweenable.composeEasingObject( - from, easing || 'linear'); - - mockTweenable.set({}); - - // Alias and reuse the _filterArgs array instead of recreating it. - var filterArgs = mockTweenable._filterArgs; - filterArgs.length = 0; - filterArgs[0] = current; - filterArgs[1] = from; - filterArgs[2] = targetState; - filterArgs[3] = easingObject; - - // Any defined value transformation must be applied - Tweenable.applyFilter(mockTweenable, 'tweenCreated'); - Tweenable.applyFilter(mockTweenable, 'beforeTween'); - - var interpolatedValues = getInterpolatedValues( - from, current, targetState, position, easingObject); - - // Transform values back into their original format - Tweenable.applyFilter(mockTweenable, 'afterTween'); - - return interpolatedValues; - }; + ;(function () { + + function getInterpolatedValues ( + from, current, targetState, position, easing) { + return Tweenable.tweenProps( + position, current, from, targetState, 1, 0, easing); + } - }()); + // Fake a Tweenable and patch some internals. This approach allows us to + // skip uneccessary processing and object recreation, cutting down on garbage + // collection pauses. + var mockTweenable = new Tweenable(); + mockTweenable._filterArgs = []; /** - * Adds string interpolation support to Shifty. + * Compute the midpoint of two Objects. This method effectively calculates a specific frame of animation that [Tweenable#tween](shifty.core.js.html#tween) does many times over the course of a tween. * - * The Token extension allows Shifty to tween numbers inside of strings. Among other things, this allows you to animate CSS properties. For example, you can do this: + * Example: * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { transform: 'translateX(45px)'}, - * to: { transform: 'translateX(90xp)'} - * }); - * ``` + * var interpolatedValues = Tweenable.interpolate({ + * width: '100px', + * opacity: 0, + * color: '#fff' + * }, { + * width: '200px', + * opacity: 1, + * color: '#000' + * }, 0.5); * - * `translateX(45)` will be tweened to `translateX(90)`. To demonstrate: + * console.log(interpolatedValues); + * // {opacity: 0.5, width: "150px", color: "rgb(127,127,127)"} * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { transform: 'translateX(45px)'}, - * to: { transform: 'translateX(90px)'}, - * step: function (state) { - * console.log(state.transform); - * } - * }); - * ``` - * - * The above snippet will log something like this in the console: - * - * ``` - * translateX(60.3px) - * ... - * translateX(76.05px) - * ... - * translateX(90px) - * ``` - * - * Another use for this is animating colors: - * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { color: 'rgb(0,255,0)'}, - * to: { color: 'rgb(255,0,255)'}, - * step: function (state) { - * console.log(state.color); - * } - * }); - * ``` - * - * The above snippet will log something like this: - * - * ``` - * rgb(84,170,84) - * ... - * rgb(170,84,170) - * ... - * rgb(255,0,255) - * ``` - * - * This extension also supports hexadecimal colors, in both long (`#ff00ff`) and short (`#f0f`) forms. Be aware that hexadecimal input values will be converted into the equivalent RGB output values. This is done to optimize for performance. - * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { color: '#0f0'}, - * to: { color: '#f0f'}, - * step: function (state) { - * console.log(state.color); - * } - * }); - * ``` - * - * This snippet will generate the same output as the one before it because equivalent values were supplied (just in hexadecimal form rather than RGB): + * @param {Object} from The starting values to tween from. + * @param {Object} targetState The ending values to tween to. + * @param {number} position The normalized position value (between 0.0 and 1.0) to interpolate the values between `from` and `to` for. `from` represents 0 and `to` represents `1`. + * @param {string|Object} easing The easing curve(s) to calculate the midpoint against. You can reference any easing function attached to `Tweenable.prototype.formula`. If omitted, this defaults to "linear". + * @return {Object} + */ + Tweenable.interpolate = function (from, targetState, position, easing) { + var current = Tweenable.shallowCopy({}, from); + var easingObject = Tweenable.composeEasingObject( + from, easing || 'linear'); + + mockTweenable.set({}); + + // Alias and reuse the _filterArgs array instead of recreating it. + var filterArgs = mockTweenable._filterArgs; + filterArgs.length = 0; + filterArgs[0] = current; + filterArgs[1] = from; + filterArgs[2] = targetState; + filterArgs[3] = easingObject; + + // Any defined value transformation must be applied + Tweenable.applyFilter(mockTweenable, 'tweenCreated'); + Tweenable.applyFilter(mockTweenable, 'beforeTween'); + + var interpolatedValues = getInterpolatedValues( + from, current, targetState, position, easingObject); + + // Transform values back into their original format + Tweenable.applyFilter(mockTweenable, 'afterTween'); + + return interpolatedValues; + }; + + }()); + + /** + * Adds string interpolation support to Shifty. + * + * The Token extension allows Shifty to tween numbers inside of strings. Among + * other things, this allows you to animate CSS properties. For example, you + * can do this: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { transform: 'translateX(45px)'}, + * to: { transform: 'translateX(90xp)'} + * }); + * + * ` ` + * `translateX(45)` will be tweened to `translateX(90)`. To demonstrate: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { transform: 'translateX(45px)'}, + * to: { transform: 'translateX(90px)'}, + * step: function (state) { + * console.log(state.transform); + * } + * }); + * + * ` ` + * The above snippet will log something like this in the console: + * + * translateX(60.3px) + * ... + * translateX(76.05px) + * ... + * translateX(90px) + * + * ` ` + * Another use for this is animating colors: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { color: 'rgb(0,255,0)'}, + * to: { color: 'rgb(255,0,255)'}, + * step: function (state) { + * console.log(state.color); + * } + * }); + * + * ` ` + * The above snippet will log something like this: + * + * rgb(84,170,84) + * ... + * rgb(170,84,170) + * ... + * rgb(255,0,255) + * + * ` ` + * This extension also supports hexadecimal colors, in both long (`#ff00ff`) + * and short (`#f0f`) forms. Be aware that hexadecimal input values will be + * converted into the equivalent RGB output values. This is done to optimize + * for performance. + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { color: '#0f0'}, + * to: { color: '#f0f'}, + * step: function (state) { + * console.log(state.color); + * } + * }); + * + * ` ` + * This snippet will generate the same output as the one before it because + * equivalent values were supplied (just in hexadecimal form rather than RGB): + * + * rgb(84,170,84) + * ... + * rgb(170,84,170) + * ... + * rgb(255,0,255) + * + * ` ` + * ` ` + * ## Easing support + * + * Easing works somewhat differently in the Token extension. This is because + * some CSS properties have multiple values in them, and you might need to + * tween each value along its own easing curve. A basic example: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { transform: 'translateX(0px) translateY(0px)'}, + * to: { transform: 'translateX(100px) translateY(100px)'}, + * easing: { transform: 'easeInQuad' }, + * step: function (state) { + * console.log(state.transform); + * } + * }); + * + * ` ` + * The above snippet create values like this: + * + * translateX(11.560000000000002px) translateY(11.560000000000002px) + * ... + * translateX(46.24000000000001px) translateY(46.24000000000001px) + * ... + * translateX(100px) translateY(100px) + * + * ` ` + * In this case, the values for `translateX` and `translateY` are always the + * same for each step of the tween, because they have the same start and end + * points and both use the same easing curve. We can also tween `translateX` + * and `translateY` along independent curves: + * + * var tweenable = new Tweenable(); + * tweenable.tween({ + * from: { transform: 'translateX(0px) translateY(0px)'}, + * to: { transform: 'translateX(100px) translateY(100px)'}, + * easing: { transform: 'easeInQuad bounce' }, + * step: function (state) { + * console.log(state.transform); + * } + * }); + * + * ` ` + * The above snippet create values like this: + * + * translateX(10.89px) translateY(82.355625px) + * ... + * translateX(44.89000000000001px) translateY(86.73062500000002px) + * ... + * translateX(100px) translateY(100px) + * + * ` ` + * `translateX` and `translateY` are not in sync anymore, because `easeInQuad` + * was specified for `translateX` and `bounce` for `translateY`. Mixing and + * matching easing curves can make for some interesting motion in your + * animations. + * + * The order of the space-separated easing curves correspond the token values + * they apply to. If there are more token values than easing curves listed, + * the last easing curve listed is used. + */ + function token () { + // Functionality for this extension runs implicitly if it is loaded. + } /*!*/ + + // token function is defined above only so that dox-foundation sees it as + // documentation and renders it. It is never used, and is optimized away at + // build time. + + ;(function (Tweenable) { + + /*! + * @typedef {{ + * formatString: string + * chunkNames: Array. + * }} + */ + var formatManifest; + + // CONSTANTS + + var R_NUMBER_COMPONENT = /(\d|\-|\.)/; + var R_FORMAT_CHUNKS = /([^\-0-9\.]+)/g; + var R_UNFORMATTED_VALUES = /[0-9.\-]+/g; + var R_RGB = new RegExp( + 'rgb\\(' + R_UNFORMATTED_VALUES.source + + (/,\s*/.source) + R_UNFORMATTED_VALUES.source + + (/,\s*/.source) + R_UNFORMATTED_VALUES.source + '\\)', 'g'); + var R_RGB_PREFIX = /^.*\(/; + var R_HEX = /#([0-9]|[a-f]){3,6}/gi; + var VALUE_PLACEHOLDER = 'VAL'; + + // HELPERS + + var getFormatChunksFrom_accumulator = []; + /*! + * @param {Array.number} rawValues + * @param {string} prefix * - * ``` - * rgb(84,170,84) - * ... - * rgb(170,84,170) - * ... - * rgb(255,0,255) - * ``` + * @return {Array.} + */ + function getFormatChunksFrom (rawValues, prefix) { + getFormatChunksFrom_accumulator.length = 0; + + var rawValuesLength = rawValues.length; + var i; + + for (i = 0; i < rawValuesLength; i++) { + getFormatChunksFrom_accumulator.push('_' + prefix + '_' + i); + } + + return getFormatChunksFrom_accumulator; + } + + /*! + * @param {string} formattedString * - * ## Easing support + * @return {string} + */ + function getFormatStringFrom (formattedString) { + var chunks = formattedString.match(R_FORMAT_CHUNKS); + + if (!chunks) { + // chunks will be null if there were no tokens to parse in + // formattedString (for example, if formattedString is '2'). Coerce + // chunks to be useful here. + chunks = ['', '']; + + // If there is only one chunk, assume that the string is a number + // followed by a token... + // NOTE: This may be an unwise assumption. + } else if (chunks.length === 1 || + // ...or if the string starts with a number component (".", "-", or a + // digit)... + formattedString[0].match(R_NUMBER_COMPONENT)) { + // ...prepend an empty string here to make sure that the formatted number + // is properly replaced by VALUE_PLACEHOLDER + chunks.unshift(''); + } + + return chunks.join(VALUE_PLACEHOLDER); + } + + /*! + * Convert all hex color values within a string to an rgb string. * - * Easing works somewhat differently in the Token extension. This is because some CSS properties have multiple values in them, and you might need to tween each value along its own easing curve. A basic example: + * @param {Object} stateObject * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { transform: 'translateX(0px) translateY(0px)'}, - * to: { transform: 'translateX(100px) translateY(100px)'}, - * easing: { transform: 'easeInQuad' }, - * step: function (state) { - * console.log(state.transform); - * } - * }); - * ``` + * @return {Object} The modified obj + */ + function sanitizeObjectForHexProps (stateObject) { + Tweenable.each(stateObject, function (prop) { + var currentProp = stateObject[prop]; + + if (typeof currentProp === 'string' && currentProp.match(R_HEX)) { + stateObject[prop] = sanitizeHexChunksToRGB(currentProp); + } + }); + } + + /*! + * @param {string} str * - * The above snippet create values like this: + * @return {string} + */ + function sanitizeHexChunksToRGB (str) { + return filterStringChunks(R_HEX, str, convertHexToRGB); + } + + /*! + * @param {string} hexString * - * ``` - * translateX(11.560000000000002px) translateY(11.560000000000002px) - * ... - * translateX(46.24000000000001px) translateY(46.24000000000001px) - * ... - * translateX(100px) translateY(100px) - * ``` + * @return {string} + */ + function convertHexToRGB (hexString) { + var rgbArr = hexToRGBArray(hexString); + return 'rgb(' + rgbArr[0] + ',' + rgbArr[1] + ',' + rgbArr[2] + ')'; + } + + var hexToRGBArray_returnArray = []; + /*! + * Convert a hexadecimal string to an array with three items, one each for + * the red, blue, and green decimal values. * - * In this case, the values for `translateX` and `translateY` are always the same for each step of the tween, because they have the same start and end points and both use the same easing curve. We can also tween `translateX` and `translateY` along independent curves: + * @param {string} hex A hexadecimal string. * - * ``` - * var tweenable = new Tweenable(); - * tweenable.tween({ - * from: { transform: 'translateX(0px) translateY(0px)'}, - * to: { transform: 'translateX(100px) translateY(100px)'}, - * easing: { transform: 'easeInQuad bounce' }, - * step: function (state) { - * console.log(state.transform); - * } - * }); - * ``` + * @returns {Array.} The converted Array of RGB values if `hex` is a + * valid string, or an Array of three 0's. + */ + function hexToRGBArray (hex) { + + hex = hex.replace(/#/, ''); + + // If the string is a shorthand three digit hex notation, normalize it to + // the standard six digit notation + if (hex.length === 3) { + hex = hex.split(''); + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + + hexToRGBArray_returnArray[0] = hexToDec(hex.substr(0, 2)); + hexToRGBArray_returnArray[1] = hexToDec(hex.substr(2, 2)); + hexToRGBArray_returnArray[2] = hexToDec(hex.substr(4, 2)); + + return hexToRGBArray_returnArray; + } + + /*! + * Convert a base-16 number to base-10. * - * The above snippet create values like this: + * @param {Number|String} hex The value to convert * - * ``` - * translateX(10.89px) translateY(82.355625px) - * ... - * translateX(44.89000000000001px) translateY(86.73062500000002px) - * ... - * translateX(100px) translateY(100px) - * ``` + * @returns {Number} The base-10 equivalent of `hex`. + */ + function hexToDec (hex) { + return parseInt(hex, 16); + } + + /*! + * Runs a filter operation on all chunks of a string that match a RegExp * - * `translateX` and `translateY` are not in sync anymore, because `easeInQuad` was specified for `translateX` and `bounce` for `translateY`. Mixing and matching easing curves can make for some interesting motion in your animations. + * @param {RegExp} pattern + * @param {string} unfilteredString + * @param {function(string)} filter * - * The order of the space-separated easing curves correspond the token values they apply to. If there are more token values than easing curves listed, the last easing curve listed is used. + * @return {string} */ - function token () { - // Functionality for this extension runs implicitly if it is loaded. - } /*!*/ - - // token function is defined above only so that dox-foundation sees it as - // documentation and renders it. It is never used, and is optimized away at - // build time. - - ;(function (Tweenable) { - - /*! - * @typedef {{ - * formatString: string - * chunkNames: Array. - * }} - */ - var formatManifest; - - // CONSTANTS - - var R_NUMBER_COMPONENT = /(\d|\-|\.)/; - var R_FORMAT_CHUNKS = /([^\-0-9\.]+)/g; - var R_UNFORMATTED_VALUES = /[0-9.\-]+/g; - var R_RGB = new RegExp( - 'rgb\\(' + R_UNFORMATTED_VALUES.source + - (/,\s*/.source) + R_UNFORMATTED_VALUES.source + - (/,\s*/.source) + R_UNFORMATTED_VALUES.source + '\\)', 'g'); - var R_RGB_PREFIX = /^.*\(/; - var R_HEX = /#([0-9]|[a-f]){3,6}/gi; - var VALUE_PLACEHOLDER = 'VAL'; - - // HELPERS - - var getFormatChunksFrom_accumulator = []; - /*! - * @param {Array.number} rawValues - * @param {string} prefix - * - * @return {Array.} - */ - function getFormatChunksFrom (rawValues, prefix) { - getFormatChunksFrom_accumulator.length = 0; - - var rawValuesLength = rawValues.length; - var i; - - for (i = 0; i < rawValuesLength; i++) { - getFormatChunksFrom_accumulator.push('_' + prefix + '_' + i); + function filterStringChunks (pattern, unfilteredString, filter) { + var pattenMatches = unfilteredString.match(pattern); + var filteredString = unfilteredString.replace(pattern, VALUE_PLACEHOLDER); + + if (pattenMatches) { + var pattenMatchesLength = pattenMatches.length; + var currentChunk; + + for (var i = 0; i < pattenMatchesLength; i++) { + currentChunk = pattenMatches.shift(); + filteredString = filteredString.replace( + VALUE_PLACEHOLDER, filter(currentChunk)); } - - return getFormatChunksFrom_accumulator; } - /*! - * @param {string} formattedString - * - * @return {string} - */ - function getFormatStringFrom (formattedString) { - var chunks = formattedString.match(R_FORMAT_CHUNKS); - - if (!chunks) { - // chunks will be null if there were no tokens to parse in - // formattedString (for example, if formattedString is '2'). Coerce - // chunks to be useful here. - chunks = ['', '']; - - // If there is only one chunk, assume that the string is a number - // followed by a token... - // NOTE: This may be an unwise assumption. - } else if (chunks.length === 1 || - // ...or if the string starts with a number component (".", "-", or a - // digit)... - formattedString[0].match(R_NUMBER_COMPONENT)) { - // ...prepend an empty string here to make sure that the formatted number - // is properly replaced by VALUE_PLACEHOLDER - chunks.unshift(''); - } + return filteredString; + } - return chunks.join(VALUE_PLACEHOLDER); - } + /*! + * Check for floating point values within rgb strings and rounds them. + * + * @param {string} formattedString + * + * @return {string} + */ + function sanitizeRGBChunks (formattedString) { + return filterStringChunks(R_RGB, formattedString, sanitizeRGBChunk); + } - /*! - * Convert all hex color values within a string to an rgb string. - * - * @param {Object} stateObject - * - * @return {Object} The modified obj - */ - function sanitizeObjectForHexProps (stateObject) { - Tweenable.each(stateObject, function (prop) { - var currentProp = stateObject[prop]; - - if (typeof currentProp === 'string' && currentProp.match(R_HEX)) { - stateObject[prop] = sanitizeHexChunksToRGB(currentProp); - } - }); - } + /*! + * @param {string} rgbChunk + * + * @return {string} + */ + function sanitizeRGBChunk (rgbChunk) { + var numbers = rgbChunk.match(R_UNFORMATTED_VALUES); + var numbersLength = numbers.length; + var sanitizedString = rgbChunk.match(R_RGB_PREFIX)[0]; - /*! - * @param {string} str - * - * @return {string} - */ - function sanitizeHexChunksToRGB (str) { - return filterStringChunks(R_HEX, str, convertHexToRGB); + for (var i = 0; i < numbersLength; i++) { + sanitizedString += parseInt(numbers[i], 10) + ','; } - /*! - * @param {string} hexString - * - * @return {string} - */ - function convertHexToRGB (hexString) { - var rgbArr = hexToRGBArray(hexString); - return 'rgb(' + rgbArr[0] + ',' + rgbArr[1] + ',' + rgbArr[2] + ')'; - } + sanitizedString = sanitizedString.slice(0, -1) + ')'; - var hexToRGBArray_returnArray = []; - /*! - * Convert a hexadecimal string to an array with three items, one each for - * the red, blue, and green decimal values. - * - * @param {string} hex A hexadecimal string. - * - * @returns {Array.} The converted Array of RGB values if `hex` is a - * valid string, or an Array of three 0's. - */ - function hexToRGBArray (hex) { - - hex = hex.replace(/#/, ''); - - // If the string is a shorthand three digit hex notation, normalize it to - // the standard six digit notation - if (hex.length === 3) { - hex = hex.split(''); - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } + return sanitizedString; + } - hexToRGBArray_returnArray[0] = hexToDec(hex.substr(0, 2)); - hexToRGBArray_returnArray[1] = hexToDec(hex.substr(2, 2)); - hexToRGBArray_returnArray[2] = hexToDec(hex.substr(4, 2)); + /*! + * @param {Object} stateObject + * + * @return {Object} An Object of formatManifests that correspond to + * the string properties of stateObject + */ + function getFormatManifests (stateObject) { + var manifestAccumulator = {}; - return hexToRGBArray_returnArray; - } + Tweenable.each(stateObject, function (prop) { + var currentProp = stateObject[prop]; - /*! - * Convert a base-16 number to base-10. - * - * @param {Number|String} hex The value to convert - * - * @returns {Number} The base-10 equivalent of `hex`. - */ - function hexToDec (hex) { - return parseInt(hex, 16); - } + if (typeof currentProp === 'string') { + var rawValues = getValuesFrom(currentProp); - /*! - * Runs a filter operation on all chunks of a string that match a RegExp - * - * @param {RegExp} pattern - * @param {string} unfilteredString - * @param {function(string)} filter - * - * @return {string} - */ - function filterStringChunks (pattern, unfilteredString, filter) { - var pattenMatches = unfilteredString.match(pattern); - var filteredString = unfilteredString.replace(pattern, VALUE_PLACEHOLDER); - - if (pattenMatches) { - var pattenMatchesLength = pattenMatches.length; - var currentChunk; - - for (var i = 0; i < pattenMatchesLength; i++) { - currentChunk = pattenMatches.shift(); - filteredString = filteredString.replace( - VALUE_PLACEHOLDER, filter(currentChunk)); - } + manifestAccumulator[prop] = { + 'formatString': getFormatStringFrom(currentProp) + ,'chunkNames': getFormatChunksFrom(rawValues, prop) + }; } + }); - return filteredString; - } + return manifestAccumulator; + } - /*! - * Check for floating point values within rgb strings and rounds them. - * - * @param {string} formattedString - * - * @return {string} - */ - function sanitizeRGBChunks (formattedString) { - return filterStringChunks(R_RGB, formattedString, sanitizeRGBChunk); - } + /*! + * @param {Object} stateObject + * @param {Object} formatManifests + */ + function expandFormattedProperties (stateObject, formatManifests) { + Tweenable.each(formatManifests, function (prop) { + var currentProp = stateObject[prop]; + var rawValues = getValuesFrom(currentProp); + var rawValuesLength = rawValues.length; - /*! - * @param {string} rgbChunk - * - * @return {string} - */ - function sanitizeRGBChunk (rgbChunk) { - var numbers = rgbChunk.match(R_UNFORMATTED_VALUES); - var numbersLength = numbers.length; - var sanitizedString = rgbChunk.match(R_RGB_PREFIX)[0]; - - for (var i = 0; i < numbersLength; i++) { - sanitizedString += parseInt(numbers[i], 10) + ','; + for (var i = 0; i < rawValuesLength; i++) { + stateObject[formatManifests[prop].chunkNames[i]] = +rawValues[i]; } - sanitizedString = sanitizedString.slice(0, -1) + ')'; - - return sanitizedString; - } + delete stateObject[prop]; + }); + } - /*! - * @param {Object} stateObject - * - * @return {Object} An Object of formatManifests that correspond to - * the string properties of stateObject - */ - function getFormatManifests (stateObject) { - var manifestAccumulator = {}; - - Tweenable.each(stateObject, function (prop) { - var currentProp = stateObject[prop]; - - if (typeof currentProp === 'string') { - var rawValues = getValuesFrom(currentProp); - - manifestAccumulator[prop] = { - 'formatString': getFormatStringFrom(currentProp) - ,'chunkNames': getFormatChunksFrom(rawValues, prop) - }; - } - }); + /*! + * @param {Object} stateObject + * @param {Object} formatManifests + */ + function collapseFormattedProperties (stateObject, formatManifests) { + Tweenable.each(formatManifests, function (prop) { + var currentProp = stateObject[prop]; + var formatChunks = extractPropertyChunks( + stateObject, formatManifests[prop].chunkNames); + var valuesList = getValuesList( + formatChunks, formatManifests[prop].chunkNames); + currentProp = getFormattedValues( + formatManifests[prop].formatString, valuesList); + stateObject[prop] = sanitizeRGBChunks(currentProp); + }); + } - return manifestAccumulator; + /*! + * @param {Object} stateObject + * @param {Array.} chunkNames + * + * @return {Object} The extracted value chunks. + */ + function extractPropertyChunks (stateObject, chunkNames) { + var extractedValues = {}; + var currentChunkName, chunkNamesLength = chunkNames.length; + + for (var i = 0; i < chunkNamesLength; i++) { + currentChunkName = chunkNames[i]; + extractedValues[currentChunkName] = stateObject[currentChunkName]; + delete stateObject[currentChunkName]; } - /*! - * @param {Object} stateObject - * @param {Object} formatManifests - */ - function expandFormattedProperties (stateObject, formatManifests) { - Tweenable.each(formatManifests, function (prop) { - var currentProp = stateObject[prop]; - var rawValues = getValuesFrom(currentProp); - var rawValuesLength = rawValues.length; + return extractedValues; + } - for (var i = 0; i < rawValuesLength; i++) { - stateObject[formatManifests[prop].chunkNames[i]] = +rawValues[i]; - } + var getValuesList_accumulator = []; + /*! + * @param {Object} stateObject + * @param {Array.} chunkNames + * + * @return {Array.} + */ + function getValuesList (stateObject, chunkNames) { + getValuesList_accumulator.length = 0; + var chunkNamesLength = chunkNames.length; - delete stateObject[prop]; - }); + for (var i = 0; i < chunkNamesLength; i++) { + getValuesList_accumulator.push(stateObject[chunkNames[i]]); } - /*! - * @param {Object} stateObject - * @param {Object} formatManifests - */ - function collapseFormattedProperties (stateObject, formatManifests) { - Tweenable.each(formatManifests, function (prop) { - var currentProp = stateObject[prop]; - var formatChunks = extractPropertyChunks( - stateObject, formatManifests[prop].chunkNames); - var valuesList = getValuesList( - formatChunks, formatManifests[prop].chunkNames); - currentProp = getFormattedValues( - formatManifests[prop].formatString, valuesList); - stateObject[prop] = sanitizeRGBChunks(currentProp); - }); - } + return getValuesList_accumulator; + } - /*! - * @param {Object} stateObject - * @param {Array.} chunkNames - * - * @return {Object} The extracted value chunks. - */ - function extractPropertyChunks (stateObject, chunkNames) { - var extractedValues = {}; - var currentChunkName, chunkNamesLength = chunkNames.length; - - for (var i = 0; i < chunkNamesLength; i++) { - currentChunkName = chunkNames[i]; - extractedValues[currentChunkName] = stateObject[currentChunkName]; - delete stateObject[currentChunkName]; - } + /*! + * @param {string} formatString + * @param {Array.} rawValues + * + * @return {string} + */ + function getFormattedValues (formatString, rawValues) { + var formattedValueString = formatString; + var rawValuesLength = rawValues.length; - return extractedValues; + for (var i = 0; i < rawValuesLength; i++) { + formattedValueString = formattedValueString.replace( + VALUE_PLACEHOLDER, +rawValues[i].toFixed(4)); } - var getValuesList_accumulator = []; - /*! - * @param {Object} stateObject - * @param {Array.} chunkNames - * - * @return {Array.} - */ - function getValuesList (stateObject, chunkNames) { - getValuesList_accumulator.length = 0; - var chunkNamesLength = chunkNames.length; - - for (var i = 0; i < chunkNamesLength; i++) { - getValuesList_accumulator.push(stateObject[chunkNames[i]]); - } - - return getValuesList_accumulator; - } + return formattedValueString; + } - /*! - * @param {string} formatString - * @param {Array.} rawValues - * - * @return {string} - */ - function getFormattedValues (formatString, rawValues) { - var formattedValueString = formatString; - var rawValuesLength = rawValues.length; + /*! + * Note: It's the duty of the caller to convert the Array elements of the + * return value into numbers. This is a performance optimization. + * + * @param {string} formattedString + * + * @return {Array.|null} + */ + function getValuesFrom (formattedString) { + return formattedString.match(R_UNFORMATTED_VALUES); + } - for (var i = 0; i < rawValuesLength; i++) { - formattedValueString = formattedValueString.replace( - VALUE_PLACEHOLDER, +rawValues[i].toFixed(4)); + /*! + * @param {Object} easingObject + * @param {Object} tokenData + */ + function expandEasingObject (easingObject, tokenData) { + Tweenable.each(tokenData, function (prop) { + var currentProp = tokenData[prop]; + var chunkNames = currentProp.chunkNames; + var chunkLength = chunkNames.length; + var easingChunks = easingObject[prop].split(' '); + var lastEasingChunk = easingChunks[easingChunks.length - 1]; + + for (var i = 0; i < chunkLength; i++) { + easingObject[chunkNames[i]] = easingChunks[i] || lastEasingChunk; } - return formattedValueString; - } - - /*! - * Note: It's the duty of the caller to convert the Array elements of the - * return value into numbers. This is a performance optimization. - * - * @param {string} formattedString - * - * @return {Array.|null} - */ - function getValuesFrom (formattedString) { - return formattedString.match(R_UNFORMATTED_VALUES); - } - - /*! - * @param {Object} easingObject - * @param {Object} tokenData - */ - function expandEasingObject (easingObject, tokenData) { - Tweenable.each(tokenData, function (prop) { - var currentProp = tokenData[prop]; - var chunkNames = currentProp.chunkNames; - var chunkLength = chunkNames.length; - var easingChunks = easingObject[prop].split(' '); - var lastEasingChunk = easingChunks[easingChunks.length - 1]; - - for (var i = 0; i < chunkLength; i++) { - easingObject[chunkNames[i]] = easingChunks[i] || lastEasingChunk; - } + delete easingObject[prop]; + }); + } - delete easingObject[prop]; - }); - } + /*! + * @param {Object} easingObject + * @param {Object} tokenData + */ + function collapseEasingObject (easingObject, tokenData) { + Tweenable.each(tokenData, function (prop) { + var currentProp = tokenData[prop]; + var chunkNames = currentProp.chunkNames; + var chunkLength = chunkNames.length; + var composedEasingString = ''; + + for (var i = 0; i < chunkLength; i++) { + composedEasingString += ' ' + easingObject[chunkNames[i]]; + delete easingObject[chunkNames[i]]; + } - /*! - * @param {Object} easingObject - * @param {Object} tokenData - */ - function collapseEasingObject (easingObject, tokenData) { - Tweenable.each(tokenData, function (prop) { - var currentProp = tokenData[prop]; - var chunkNames = currentProp.chunkNames; - var chunkLength = chunkNames.length; - var composedEasingString = ''; - - for (var i = 0; i < chunkLength; i++) { - composedEasingString += ' ' + easingObject[chunkNames[i]]; - delete easingObject[chunkNames[i]]; - } + easingObject[prop] = composedEasingString.substr(1); + }); + } - easingObject[prop] = composedEasingString.substr(1); - }); + Tweenable.prototype.filter.token = { + 'tweenCreated': function (currentState, fromState, toState, easingObject) { + sanitizeObjectForHexProps(currentState); + sanitizeObjectForHexProps(fromState); + sanitizeObjectForHexProps(toState); + this._tokenData = getFormatManifests(currentState); + }, + + 'beforeTween': function (currentState, fromState, toState, easingObject) { + expandEasingObject(easingObject, this._tokenData); + expandFormattedProperties(currentState, this._tokenData); + expandFormattedProperties(fromState, this._tokenData); + expandFormattedProperties(toState, this._tokenData); + }, + + 'afterTween': function (currentState, fromState, toState, easingObject) { + collapseFormattedProperties(currentState, this._tokenData); + collapseFormattedProperties(fromState, this._tokenData); + collapseFormattedProperties(toState, this._tokenData); + collapseEasingObject(easingObject, this._tokenData); } + }; - Tweenable.prototype.filter.token = { - 'tweenCreated': function (currentState, fromState, toState, easingObject) { - sanitizeObjectForHexProps(currentState); - sanitizeObjectForHexProps(fromState); - sanitizeObjectForHexProps(toState); - this._tokenData = getFormatManifests(currentState); - }, - - 'beforeTween': function (currentState, fromState, toState, easingObject) { - expandEasingObject(easingObject, this._tokenData); - expandFormattedProperties(currentState, this._tokenData); - expandFormattedProperties(fromState, this._tokenData); - expandFormattedProperties(toState, this._tokenData); - }, - - 'afterTween': function (currentState, fromState, toState, easingObject) { - collapseFormattedProperties(currentState, this._tokenData); - collapseFormattedProperties(fromState, this._tokenData); - collapseFormattedProperties(toState, this._tokenData); - collapseEasingObject(easingObject, this._tokenData); - } - }; - - } (Tweenable)); + } (Tweenable)); - }(this, window)); + }(window)); return window.Tweenable; });