/* 
 This file was generated by Dashcode and is covered by the 
 license.txt included in the project.  You may edit this file, 
 however it is recommended to first turn off the Dashcode 
 code generator otherwise the changes will be lost.
 */

// Note: Properties and methods beginning with underbar ("_") are considered private and subject to change in future Dashcode releases.

// Currently supported transition types
Transition.NONE_TYPE = 'none';
Transition.PUSH_TYPE = 'push';
Transition.DISSOLVE_TYPE = 'dissolve';
Transition.SLIDE_TYPE = 'slide';
Transition.FADE_TYPE = 'fade';
Transition.FLIP_TYPE = 'flip';
Transition.CUBE_TYPE = 'cube';
Transition.SWAP_TYPE = 'swap';
Transition.REVOLVE_TYPE = 'revolve';

// Transition timing functions that are defined as part of WebKit CSS animation specification. These are made available for your convenience.
Transition.EASE_TIMING = 'ease';
Transition.LINEAR_TIMING = 'linear';
Transition.EASE_IN_TIMING = 'ease-in';
Transition.EASE_OUT_TIMING = 'ease-out';
Transition.EASE_IN_OUT_TIMING = 'ease-in-out';

// Directions are only supported for certain transition types.  
// Push and Slide support all four directions.
// Flip, Cube, Swap and Revolve support only Right-to-left and Left-to-right
Transition.RIGHT_TO_LEFT_DIRECTION = 'right-left';
Transition.LEFT_TO_RIGHT_DIRECTION = 'left-right';
Transition.TOP_TO_BOTTOM_DIRECTION = 'top-bottom';
Transition.BOTTOM_TO_TOP_DIRECTION = 'bottom-top';

//
// Constructor for Transtition object. You can also use the convenience method CreateTransitionWithProperties()
//
// type         - any of the Transition type constants
// duration     - a float in seconds
// timing       - a valid CSS animation timing function value. For example, 'linear' or 'ease-in-out'
//
// After construction, you can also assign one of the direction constants above to the "direction" property 
// to set the transition direction for transition types that support different directions (see comments above.)
//
function Transition(type, duration, timing)
{
    this.type = type;
    this.setDuration(duration);
    this.timing = timing;
    
    this._useTransforms = Transition.areTransformsSupported();
}

//
// Create a new Transition object and fill its internal properties from the dictionary parameter
//
function CreateTransitionWithProperties(properties)
{
    var transition = new Transition();
    for (var property in properties) {
        if (property == 'duration') {
            transition.setDuration(properties[property]);
        } else {
            transition[property] = properties[property];
        }
    }
    return transition;
}

//
// Both newView and oldView must share the same common parent container element. The transition is constrained by
// the dimensions of the parent container. In particular, the container has 'overflow: hidden'. This is especially
// important when the container edges are not lined with the edge of the device viewport.
//
// Be careful that this method actually makes use of these inline CSS properties to make sure that all transitions
// can be performed correctly:
//  - opacity
//  - zIndex
//  - position
//  - top
//  - width
// If you also make use of these CSS properties out of this transition method, you have to make copies of them
// restore them appropriately.
//
//
// newView - must not be null
// isReverse - if flag is true, it will perform the transition in reverse. Some transitions, for example, the push transition has a reverse.
//
Transition.prototype.perform = function(newView, oldView, isReverse)
{
    if (!newView || !newView.parentNode) return;
    var containerElement = newView.parentNode;    
    if (oldView) {
        // Got to execute in the same container
        if (oldView.parentNode != containerElement) return;
		if (oldView == newView) return;
    }
    
    // Make sure that container is constraining the transitions for overflow content
    containerElement.style.overflow = (this.type != Transition.FLIP_TYPE && this.type != Transition.CUBE_TYPE) ? 'hidden' : 'visible';
    var computedStyle = document.defaultView.getComputedStyle(containerElement, null);
    if ((computedStyle.getPropertyValue('position') != 'absolute') && (computedStyle.getPropertyValue('position') != 'relative')) {
        // Assume 'static' since we don't support 'fixed'. 'relative' is less obtrusive then.
        containerElement.style.position = 'relative';
    }
    
    var newStyle = newView.style;
    if (this._useTransforms) {
        // Reset
        newStyle.webkitTransitionProperty = 'none'; // disable
        newStyle.webkitTransform = this._translateOp(0, 0);
        newStyle.webkitBackfaceVisibility = '';
    }
    
    if (oldView) {
        var oldStyle = oldView.style;
        // Reset
        oldStyle.zIndex = 0;
        oldStyle.position = 'absolute';
        // Since oldView is just taken out of the document flow, make sure its width still looks good just in case width is 'auto' and its children doesn't make up all the width
        oldStyle.width = containerElement.offsetWidth+'px';
        // This is especially important for reverse since the original value of 'top' is 'auto', which for a view lower in the document flow means that it will come after the newly restored view. Hence, let's set it to a right value before newView is put to 'relative' again.
        oldStyle.top = oldView.offsetTop + 'px';
        
        if (this._useTransforms) {
            oldStyle.webkitTransitionProperty = 'none'; // disable
            // This also makes sure that we start with an identity matrix to avoid initial performance problem
            oldStyle.webkitTransform = this._translateOp(0, 0);
            oldStyle.webkitBackfaceVisibility = '';
        }
        
        if (!this.type || this.type == Transition.NONE_TYPE || !this._useTransforms) {
            if ((this.type != Transition.FADE_TYPE) && (this.type != Transition.SLIDE_TYPE) || isReverse) {
                oldStyle.display = 'none';
            }
        }
    }
    
    // Before the new view comes in, remove any previously hard-coded inline value that would have crept in when it was transited out. Because the transition is happening in a container and we are reinstating the position to be 'relative', the new view will resize itself to react to orientation changes (if any).
    newStyle.width = null;
    newStyle.position = 'relative';
    newStyle.display = 'block';

    // Performing the transition now
    if (this.type && this.type != Transition.NONE_TYPE && this._useTransforms) {
        this._checkedForEnded = false;
        this._containerElement = containerElement;
        this._newView = newView;
        this._oldView = oldView;
        // Make sure that we make a copy of the newView's inline opacity because we are going to make use of it in various ways, for example, for the fade transition or to temporarily hide it in Flip to avoid flashes
        this._previousNewStyleOpacity = newStyle.opacity;
        // Normally, the old view disappears as part of transition. Some transitions like slide/fade requires the old view to be there though.
        this._shouldHideOldView = true;
        
        if (this.type == Transition.DISSOLVE_TYPE || this.type == Transition.FADE_TYPE) {
            this._performFadeTransition(newView, oldView, isReverse);
        }
        else if (this.type == Transition.PUSH_TYPE || this.type == Transition.SLIDE_TYPE) {
            this._performPushOrSlideTransition(containerElement, newView, oldView, isReverse);
        }
        else if (this.type == Transition.FLIP_TYPE) {
            this._performFlipTransition(containerElement, newView, oldView, isReverse);
        }
        else if (this.type == Transition.CUBE_TYPE) {
            this._performCubeTransition(containerElement, newView, oldView, isReverse);
        }
        else if (this.type == Transition.SWAP_TYPE) {
            this._performSwapTransition(containerElement, newView, oldView, isReverse);
        }
        else if (this.type == Transition.REVOLVE_TYPE) {
            this._performRevolveTransition(containerElement, newView, oldView, isReverse);
        }

        if (oldView) {
            var originalContainerElementHeight = containerElement.style.height;
            containerElement.style.height = Math.max(oldView.offsetHeight, newView.offsetHeight)+'px';
            this._originalContainerElementHeight = originalContainerElementHeight;
            
            this._preventEventsInContainer();
        }
    }
}

Transition.areTransformsSupported = function () {
    if (!Transition._areTransformsSupported) {
        // Our use of transforms and transitions is only officially supported for the iPhone and does not work correctly in desktop WebKit.
        // The commented out test would be more correct if desktop WebKit were also supported.
        /*
        var testElem = document.createElement('div');
        var style = testElem.style;
        style.setProperty('-webkit-transform', 'inherit');
        Transition._areTransformsSupported = style.getPropertyValue('-webkit-transform') == 'inherit';
         */
        
        // But currently, we are using the following test which succeeds on the iPhone but not on the desktop.
        Transition._areTransformsSupported = (window.WebKitCSSMatrix ? true : false);
    }
    return Transition._areTransformsSupported;
}

// Default duration for each transition type, if it is not specified
Transition._DEFAULT_DURATION = {
    'none'      : '0.35',
    'push'      : '0.35',
    'dissolve'  : '0.35',
    'slide'     : '0.35',
    'fade'      : '0.35',
    'flip'      : '0.55',
    'cube'      : '0.55',
    'swap'      : '0.55',
    'revolve'   : '0.35'
}

Transition.prototype.getDuration = function()
{
    var duration = this._duration;
    if (duration == '') {
        duration = Transition._DEFAULT_DURATION[this.type];
        if (!duration) duration = '0.3';
    }
    return duration;
}

Transition.prototype.setDuration = function(value)
{
    this._duration = value;
}

Transition.prototype._getDurationString = function()
{
    var value = parseFloat(this.getDuration());
    if (!isNaN(value)) {
        value += 's';
    }
    else {
        value = '0s';
    }
    return value;
}

Transition.prototype._getDurationStringForFadingEffect = function()
{
    var value = parseFloat(this.getDuration());
    if (!isNaN(value)) {
        // looks better with slightly longer timing
        value = value * (1+ ((value < 0.25) ? 0.5 : Math.pow(4, -0.25-value))) + 's';
    }
    else {
        value = '0s';
    }
    return value;
}

Transition.prototype._translateOp = function(xPixels, yPixels)
{
    return 'translate(' + xPixels + 'px, ' + yPixels + 'px)';
}

Transition.prototype._rotateOp = function(axis, degree)
{
    return 'rotate' + axis + '(' + degree + 'deg)';
}

Transition.prototype._setupTransition = function(style, property, duration, timing, propertyString, propertyValue)
{
    style.webkitTransitionProperty = property;
    style.webkitTransitionDuration = duration;
    style.webkitTransitionTimingFunction = timing;
    style[propertyString] = propertyValue;
}

Transition.prototype.handleEvent = function(event)
{
    switch (event.type) {
    case 'webkitTransitionEnd' :
        this._transitionEnded(event);
        break;
    case 'webkitAnimationStart' :
        this._animationStarted(event);
        break;
    case 'webkitAnimationEnd' :
        this._animationEnded(event);
        break;
    }
}

Transition.prototype._preventEventsInContainer = function()
{
    if (!this._maskContainerElement) return;
    
    if (this._mask) this._maskContainerElement.removeChild(this._mask);
    
    this._mask = document.createElement("div");
    this._mask.setAttribute('style', 'position: absolute; top: 0; left: 0; z-index: 1000;');
    this._mask.style.width = this._maskContainerElement.offsetWidth + 'px';
    this._mask.style.height = this._maskContainerElement.offsetHeight + 'px';
    this._maskContainerElement.appendChild(this._mask);
}

Transition.prototype._transitionEndedHelper = function()
{
    if (this._shouldHideOldView) {
        this._oldView.style.display = 'none';
    }
    this._newView.style.zIndex = 1;
    
    if (this._maskContainerElement && this._mask) {
        this._maskContainerElement.removeChild(this._mask);
        this._mask = null;
    }
    
    this._containerElement.style.height = this._originalContainerElementHeight;
}

// Callback for end of transition
Transition.prototype._transitionEnded = function(event)
{
    if (!this._checkedForEnded) {
        this._transitionEndedHelper();
        
        if (this.type == Transition.CUBE_TYPE) {
            this._containerElement.style.webkitPerspective = '';
            this._oldView.style.webkitTransformOrigin = '';
            this._newView.style.webkitTransformOrigin = '';
        }
        
        this._checkedForEnded = true;
    }
}

Transition._findAnimationRule = function(animationRuleName)
{
    var foundRule = null;
    var styleSheets = document.styleSheets;
    var re = /Parts\/Transitions.css$/;
    for (var i=0; i < styleSheets.length; i++) {
        var styleSheet = styleSheets[i];
        if (re.test(styleSheet.href)) {
            for (var j=0; j < styleSheet.cssRules.length; j++) {
                var rule = styleSheet.cssRules[j];
                // 7 means the keyframe rule
                if (rule.type == 7 && rule.name == 'dashcode-transition-flip-container') {
                    foundRule = rule;
                    break;
                }
            }
        }
    }
    return foundRule;
}

// Callback for start of animation
Transition.prototype._animationStarted = function(event)
{
    this._newView.style.opacity = 1;
}

Transition.prototype._animationEndedHelper = function()
{
    this._transitionEndedHelper();

    this._newView.style.opacity = this._previousNewStyleOpacity;

    Transition._removeClassName(this._oldView, this._oldViewAnimationName);
    Transition._removeClassName(this._newView, this._newViewAnimationName);
}

// Callback for end of animation
Transition.prototype._animationEnded = function(event)
{
    if (!this._checkedForEnded) {
        this._animationEndedHelper();
        
        if (this.type == Transition.FLIP_TYPE) {
            Transition._removeClassName(this._containerElement, 'dashcode-transition-flip-container');
        }
        
        this._checkedForEnded = true;
    }
}

Transition.prototype._performFadeTransition = function(newView, oldView, isReverse)
{
    if (oldView) {
        var _self = this;
        var newStyle = newView.style;
        var oldStyle = oldView.style;
        var isDissolve = this.type == Transition.DISSOLVE_TYPE;
        var isSimpleFade = this.type == Transition.FADE_TYPE;

        if (isSimpleFade) {
            if (!isReverse) newStyle.opacity = 0;
        }
        else if (isDissolve) {
            newStyle.opacity = 0;
        }
    
        var durationString = this._getDurationStringForFadingEffect(this.getDuration());
        Transition._addDelayedTransitionCallback(function() {
            if (isDissolve || (isSimpleFade && isReverse)) {
                _self._setupTransition(oldStyle, 'opacity', durationString, _self.timing, 'opacity', 0);
            }
            else {
                _self._shouldHideOldView = false; 
            }

            if (isDissolve || (isSimpleFade && !isReverse)) {
                // _self._previousNewStyleOpacity - restoring the saved inline opacity, instead of blindly blasting it away
                _self._setupTransition(newStyle, 'opacity', durationString, _self.timing, 'opacity', _self._previousNewStyleOpacity);
            }
            
            var duration = parseFloat(_self.getDuration());
            var timerCallback = function() {
                _self._transitionEndedHelper();
            }
            setTimeout(timerCallback, duration*1000+100);
        });
        
        // Register a callback for the end of the animation for clean up and/or resets
        newView.addEventListener('webkitTransitionEnd', this, false);
    }
}

Transition.prototype._performPushOrSlideTransition = function(containerElement, newView, oldView, isReverse)
{
    if (oldView) {
        var _self = this;
        var newStyle = newView.style;
        var oldStyle = oldView.style;
        var isPush = this.type == Transition.PUSH_TYPE;
        var isSlide = this.type == Transition.SLIDE_TYPE;
        var transformX = true;
        
        var factor = isReverse ? -1 : 1;
        var dimension = containerElement.offsetWidth;
        if (this.direction == Transition.BOTTOM_TO_TOP_DIRECTION) {
            transformX = false;
            dimension = isReverse ? newView.offsetHeight : oldView.offsetHeight;
        } else if (this.direction == Transition.TOP_TO_BOTTOM_DIRECTION) {
            transformX = false;
            dimension = isReverse ? oldView.offsetHeight : newView.offsetHeight;
        }
        if (this.direction == Transition.LEFT_TO_RIGHT_DIRECTION || this.direction == Transition.TOP_TO_BOTTOM_DIRECTION) factor *= -1;
        
        if (isPush || (isSlide && !isReverse)) {
            newStyle.webkitTransitionProperty = 'none'; // disable
            var transformOp;
            if (transformX) {
                transformOp = this._translateOp(factor*dimension, 0);
            } else {
                transformOp = this._translateOp(0, factor*dimension);
            }
            newStyle.webkitTransform = transformOp;
        }
        
        Transition._addDelayedTransitionCallback(function() {
            var durationString = _self._getDurationString();
            
            if (isPush || (isSlide && isReverse)) {
                var transformOp;
                if (transformX) {
                    transformOp = _self._translateOp(-1*factor*dimension, 0);
                } else {
                    transformOp = _self._translateOp(0, -1*factor*dimension);
                }
                _self._setupTransition(oldStyle, '-webkit-transform', durationString, _self.timing, 'webkitTransform', transformOp);
            }
            else {
                _self._shouldHideOldView = false; 
            }
            
            if (isPush || (isSlide && !isReverse)) {
                _self._setupTransition(newStyle, '-webkit-transform', durationString, _self.timing, 'webkitTransform', _self._translateOp(0, 0));
            }
            
            var duration = parseFloat(_self.getDuration());
            var timerCallback = function() {
                _self._transitionEndedHelper();
            }
            setTimeout(timerCallback, duration*1000+100);
        });
        
        // Register a callback for the end of the animation for clean up and/or resets
        newView.addEventListener('webkitTransitionEnd', this, false);
    }
}

Transition.prototype._performFlipTransition = function(containerElement, newView, oldView, isReverse)
{
    if (oldView) {
        // Using Animation
        var newStyle = newView.style;
        var oldStyle = oldView.style;
        
        var dimension = containerElement.offsetWidth;
        if ((dimension != 320) && (Transition._containerFlipTranslateZStyle === undefined)) {
            var containerFlipAnimationRule = Transition._findAnimationRule('dashcode-transition-flip-container');
            try {
                Transition._containerFlipTranslateZStyle = containerFlipAnimationRule.findRule('50%').style;
            }
            catch (e) {
                Transition._containerFlipTranslateZStyle = null;
            }
        }
        if (Transition._containerFlipTranslateZStyle) {
            var perspective = 600 - (dimension-320)*0.12; // magic numbers
            Transition._containerFlipTranslateZStyle.webkitTransform = 'perspective(' + perspective + ') translateZ(' + -1*dimension/2 + 'px)';
        }

        var durationString = this._getDurationString();
        
        var direction = this.direction;
        if (direction != Transition.RIGHT_TO_LEFT_DIRECTION && direction != Transition.LEFT_TO_RIGHT_DIRECTION) direction = Transition.RIGHT_TO_LEFT_DIRECTION;
        var fromRight = ((direction == Transition.RIGHT_TO_LEFT_DIRECTION) && !isReverse) || ((direction == Transition.LEFT_TO_RIGHT_DIRECTION) && isReverse);
        
        oldStyle.webkitAnimationDuration = durationString;
        oldStyle.webkitAnimationTimingFunction = this.timing;
        var oldViewAnimationName = fromRight ? 'dashcode-transition-flip-right-old-view' : 'dashcode-transition-flip-left-old-view';
        Transition._addClassName(oldView, oldViewAnimationName);
        newStyle.webkitAnimationDuration = durationString;
        newStyle.webkitAnimationTimingFunction = this.timing;
        newStyle.opacity = 0;
        var newViewAnimationName = fromRight ? 'dashcode-transition-flip-right-new-view' : 'dashcode-transition-flip-left-new-view';
        Transition._addClassName(newView, newViewAnimationName);
        containerElement.style.webkitAnimationDuration = durationString
        containerElement.style.webkitAnimationTimingFunction = this.timing;
        Transition._addClassName(containerElement, 'dashcode-transition-flip-container');

        // Register a callback for the start of the animation for reset
        containerElement.addEventListener('webkitAnimationStart', this, false);
        // Register a callback for the end of the animation for clean up
        containerElement.addEventListener('webkitAnimationEnd', this, false);
        this._newViewAnimationName = newViewAnimationName;
        this._oldViewAnimationName = oldViewAnimationName;
    }
}

Transition.prototype._performCubeTransition = function(containerElement, newView, oldView, isReverse)
{
    if (oldView) {
        var _self = this;
        var newStyle = newView.style;
        var oldStyle = oldView.style;
        
        var durationString = this._getDurationString();
        var direction = this.direction;
        if (direction != Transition.RIGHT_TO_LEFT_DIRECTION && direction != Transition.LEFT_TO_RIGHT_DIRECTION) direction = Transition.RIGHT_TO_LEFT_DIRECTION;
        var fromRight = ((direction == Transition.RIGHT_TO_LEFT_DIRECTION) && !isReverse) || ((direction == Transition.LEFT_TO_RIGHT_DIRECTION) && isReverse);
        
        containerElement.style.webkitPerspective = '800';
        oldStyle.webkitBackfaceVisibility = 'hidden';
        oldStyle.webkitTransformOrigin = fromRight ? '100% 50%' : '0% 50%';
        newStyle.webkitBackfaceVisibility = 'hidden';
        newStyle.webkitTransformOrigin = fromRight ? '0% 50%' : '100% 50%';
        
        var factor = fromRight ? 1 : -1;
        var dimension = containerElement.offsetWidth;
        
        newStyle.webkitTransitionProperty = 'none'; // disable
        newStyle.webkitTransform = _self._rotateOp('Y', factor*90) + ' translateZ(' + dimension + 'px)';
                
        Transition._addDelayedTransitionCallback(function() {
            var durationString = _self._getDurationString();
            
            _self._setupTransition(oldStyle, '-webkit-transform', durationString, _self.timing, 'webkitTransform', _self._rotateOp('Y', factor*-90) + ' translateZ(' + dimension + 'px)');
            _self._setupTransition(newStyle, '-webkit-transform', durationString, _self.timing, 'webkitTransform', 'rotateY(0deg) translateZ(0px)');
            
            var duration = parseFloat(_self.getDuration());
            var timerCallback = function() {
                _self._transitionEndedHelper();
            }
            setTimeout(timerCallback, duration*1000+100);
        });
        
        // Register a callback for the end of the animation for clean up and/or resets
        newView.addEventListener('webkitTransitionEnd', this, false);
    }
}

Transition.prototype._performSwapTransition = function(containerElement, newView, oldView, isReverse)
{
    if (oldView) {
        // Using Animation
        var newStyle = newView.style;
        var oldStyle = oldView.style;
        
        var durationString = this._getDurationString();
        
        var direction = this.direction;
        if (direction != Transition.RIGHT_TO_LEFT_DIRECTION && direction != Transition.LEFT_TO_RIGHT_DIRECTION) direction = Transition.RIGHT_TO_LEFT_DIRECTION;
        var fromRight = ((direction == Transition.RIGHT_TO_LEFT_DIRECTION) && !isReverse) || ((direction == Transition.LEFT_TO_RIGHT_DIRECTION) && isReverse);
        
        oldStyle.webkitAnimationDuration = durationString;
        oldStyle.webkitAnimationTimingFunction = this.timing;
        var oldViewAnimationName = fromRight ? 'dashcode-transition-swap-right-old-view' : 'dashcode-transition-swap-left-old-view';
        Transition._addClassName(oldView, oldViewAnimationName);
        newStyle.webkitAnimationDuration = durationString;
        newStyle.webkitAnimationTimingFunction = this.timing;
        var newViewAnimationName = fromRight ? 'dashcode-transition-swap-right-new-view' : 'dashcode-transition-swap-left-new-view';
        Transition._addClassName(newView, newViewAnimationName);

        // Register a callback for the end of the animation for clean up and/or resets
        oldView.addEventListener('webkitAnimationEnd', this, false);
        this._newViewAnimationName = newViewAnimationName;
        this._oldViewAnimationName = oldViewAnimationName;
    }
}

Transition.prototype._performRevolveTransition = function(containerElement, newView, oldView, isReverse)
{
    if (oldView) {
        // Using Animation
        var newStyle = newView.style;
        var oldStyle = oldView.style;
        
        var durationString = this._getDurationString();
        
        oldStyle.webkitAnimationDuration = durationString;
        oldStyle.webkitAnimationTimingFunction = this.timing;
        var oldViewAnimationName;
        var direction = this.direction;
        if (direction != Transition.RIGHT_TO_LEFT_DIRECTION && direction != Transition.LEFT_TO_RIGHT_DIRECTION) direction = Transition.RIGHT_TO_LEFT_DIRECTION;
        
        if (direction == Transition.RIGHT_TO_LEFT_DIRECTION) {
            oldViewAnimationName = isReverse ? 'dashcode-transition-revolve-right-old-view' : 'dashcode-transition-revolve-right-reverse-old-view';
        }
        else {
            oldViewAnimationName = isReverse ? 'dashcode-transition-revolve-left-old-view' : 'dashcode-transition-revolve-left-reverse-old-view';
        }
        Transition._addClassName(oldView, oldViewAnimationName);
        newStyle.webkitAnimationDuration = durationString;
        newStyle.webkitAnimationTimingFunction = this.timing;
        var newViewAnimationName;
        if (direction == Transition.RIGHT_TO_LEFT_DIRECTION) {
            newViewAnimationName = isReverse ? 'dashcode-transition-revolve-right-new-view' : 'dashcode-transition-revolve-right-reverse-new-view';
        }
        else {
            newViewAnimationName = isReverse ? 'dashcode-transition-revolve-left-new-view' : 'dashcode-transition-revolve-left-reverse-new-view';
        }
        Transition._addClassName(newView, newViewAnimationName);

        // Register a callback for the end of the animation for clean up and/or resets
        oldView.addEventListener('webkitAnimationEnd', this, false);
        this._newViewAnimationName = newViewAnimationName;
        this._oldViewAnimationName = oldViewAnimationName;
    }
}

//
// _hasClassName(element, className)
// Checks if an element's class attribute has 'className' (adopted from Prototype framework)
//
// element: element to act on
// className: value to check
//
Transition._hasClassName = function(element, className)
{
    if (element) {
        var elementClassName = element.className;
        return (elementClassName.length > 0 && (elementClassName == className || 
            new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
    }
}

//
// _addClassName(element, className)
// Add 'className' to element if an element's class attribute doesn't already have 'className' (adopted from Prototype framework)
//
// element: element to act on
// className: value to add
//
Transition._addClassName = function(element, className)
{
    if (element) {
        if (!this._hasClassName(element, className)) element.className += (element.className ? ' ' : '') + className;
        return element;
    }
    return null;
}

//
// _removeClassName(element, className)
// Remove 'className' from element if an element's class attribute has 'className' (adopted from Prototype framework)
//
// element: element to act on
// className: value to remove
//
Transition._removeClassName = function(element, className)
{
    if (element) {
        element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ');
        element.className = element.className.replace(/^\s+|\s+$/g, ""); // strip whitespace
        return element;
    }
    return null;
}

// Accumulate transitions that will be executed after a 0 delay
Transition._addDelayedTransitionCallback = function(callback)
{
	if (!Transition._delayedCallbacks) {
		Transition._delayedCallbacks = new Array();
		var performDelayedCallbacks = function () {
            var length = Transition._delayedCallbacks.length;
			for (var f=0; f<length; f++) {
				Transition._delayedCallbacks[f]();
			}
			delete Transition._delayedCallbacks;
		}
		setTimeout(performDelayedCallbacks, 0);
	}
	Transition._delayedCallbacks.push(callback);
}
