// Name: AnimationScripts.debug.js // Assembly: AjaxControlToolkit // Version: 16.1.0.0 // FileVersion: 16.1.0.0 Type.registerNamespace('Sys.Extended.UI.Animation'); // Create an alias for the namespace to save 25 chars each time it's used since // this is a very long script and will take awhile to download $AA = Sys.Extended.UI.Animation; $AA.registerAnimation = function(name, type) { // Register an animation with the AJAX Control Toolkit animation framework. This serves a dual purpose: // 1) to add standard utility methods to the animation type (such as a play method that creates // an animation, plays it, and disposes it when the animation is over), and 2) to associate a name with the // type that will be used when creating animations from a JSON description. This method can also be called // by other animation libraries to seamlessly interoperate with the AJAX Control Toolkit's animation // framework. // // "name" - name of the animation that will be used as the XML tag name in the XML animation description. It // should be a valid XML tag (i.e. an alpha-numeric sequence with no spaces, special characters, etc.). // Make sure the type inherits from Sys.Extended.UI.Animation.Animation if(type && ((type === $AA.Animation) || (type.inheritsFrom && type.inheritsFrom($AA.Animation)))) { // We'll store the animation name/type mapping in a "static" object off of // Sys.Extended.UI.Animation. If this __animations object hasn't been // created yet, demand create it on the first registration. if(!$AA.__animations) { $AA.__animations = {}; } // Add the current type to the collection of animations $AA.__animations[name.toLowerCase()] = type; // Add a play function that will make it very easy to create, play, and // dispose of an animation. This is effectively a "static" function on // each animation and will take the same parameters as that animation's // constructor. type.play = function() { // Create an animation, play it immediately, and dispose it when finished. // The play function takes the same parameters as the type's constructor // Create and initialize a new animation of the right type and pass in // any arguments given to the play function var animation = new type(); type.apply(animation, arguments); animation.initialize(); // Add an event handler to dispose the animation when it's finished var handler = Function.createDelegate(animation, function() { // Dispose the animation after playing animation.remove_ended(handler); handler = null; animation.dispose(); }); animation.add_ended(handler); // Once the animation has been created and initialized, play it and // dispose it as soon as it's finished animation.play(); } } else { // Raise an error if someone registers an animation that doesn't inherit // from our base Animation class throw Error.argumentType('type', type, $AA.Animation, Sys.Extended.UI.Resources.Animation_InvalidBaseType); } } $AA.buildAnimation = function(json, defaultTarget) { // The buildAnimation function is used to turn a JSON animation description // into an actual animation object that can be played. // // "json" - JSON description of the animation in the format expected by createAnimation // "defaultTarget" - target of the animation if none is specified in the JSON description. The semantics of // target assignment are provided in more detail in createAnimation. // Ensure we have a description to create an animation with if(!json || json === '') { return null; } // "Parse" the JSON so we can easily manipulate it // (we don't wrap it in a try/catch when debugging to raise any errors) var obj; json = '(' + json + ')'; if(!Sys.Debug.isDebug) { try { obj = Sys.Serialization.JavaScriptSerializer.deserialize(json); } catch(ex) { } } else { obj = Sys.Serialization.JavaScriptSerializer.deserialize(json); } // Create a new instance of the animation return $AA.createAnimation(obj, defaultTarget); } $AA.createAnimation = function(obj, defaultTarget) { // The createAnimation function builds a new Sys.Extended.UI.Animation.Animation instance from an object // that describes it. // Exceptions are thrown when the AnimationName cannot be found. Also, // any exceptions raised by setting properties or providing properties with invalid // names will only be raised when debugging. // // "obj" - the object provides a description of the animation to be be generated in // a very specific format. It has two special properties: AnimationName // and AnimationChildren. The AnimationName is required // and used to find the type of animation to create (this name should map to // one of the animation names supplied to registerAnimation). The // AnimationChildren property supplies an optional array for // animations that use child animations (such as // Sys.Extended.UI.Animation.ParallelAnimation and // Sys.Extended.UI.Animation.SequenceAnimation). The elements of // the AnimationChildren array are valid // Sys.Extended.UI.Animation.Animation objects that meet these same // requirements. In order for an animation to support child animations, it must // derive from the Sys.Extended.UI.Animation.ParentAnimation class // which provides common methods like add, clear, etc. The // remaining properties of the object are used to set parameters specific to the type // of animation being created (e.g. duration, minimumOpacity, // startValue, etc.) and should have a corresponding property on the // animation. You can also assign an arbitrary JavaScript expression to any property // by adding 'Script' to the end of its name (i.e., Height="70" can be replaced by // HeightScript="$get('myElement').offsetHeight") and have the property set to the // result of evaluating the expression before the animation is played each time. // "defaultTarget" - the function also takes a defaultTarget parameter that is used as the // target of the animation if the object does not specify one. This parameter should be // an instance of Sys.UI.DomElement and not just the name of an element. // Create a default instance of the animation by looking up the AnimationName // in the global __animations object. if(!obj || !obj.AnimationName) { throw Error.argument('obj', Sys.Extended.UI.Resources.Animation_MissingAnimationName); } var type = $AA.__animations[obj.AnimationName.toLowerCase()]; if(!type) { throw Error.argument('type', String.format(Sys.Extended.UI.Resources.Animation_UknownAnimationName, obj.AnimationName)); } var animation = new type(); // Set the animation's target if provided via defaultTarget (note that setting // it via AnimationTarget will happen during the regular property setting phase) if(defaultTarget) { animation.set_target(defaultTarget); } // If there is an AnimationChildren array and the animation inherits from // ParentAnimation, then we will recusively build the child animations. It is // important that we create the child animations before setting the animation's // properties or initializing (because some properties and initialization may be // propogated down from parent to child). if(obj.AnimationChildren && obj.AnimationChildren.length) { if($AA.ParentAnimation.isInstanceOfType(animation)) { for(var i = 0; i < obj.AnimationChildren.length; i++) { var child = $AA.createAnimation(obj.AnimationChildren[i]); if(child) { animation.add(child); } } } else { throw Error.argument('obj', String.format(Sys.Extended.UI.Resources.Animation_ChildrenNotAllowed, type.getName())); } } // Get the list of all properties available to set on the current animation's // type. We create a mapping from the property's lowercase friendly name // (i.e., "duration") to the name of its setter (i.e., "set_duration"). This is // essentialy in setting properties so we only copy over valid values. var properties = type.__animationProperties; if(!properties) { // Get the properties for this type by walking its prototype - by doing // this we'll effectively ignore anything not defined in the prototype type.__animationProperties = {}; type.resolveInheritance(); for(var name in type.prototype) { if(name.startsWith('set_')) { type.__animationProperties[name.substr(4).toLowerCase()] = name; } } // Remove the 'id' property as it shouldn't be set by the animation // (NOTE: the 'target' proeprty shouldn't be set to a string value, but it // isn't removed because it can be used as a valid dynamic property - i.e. // Target="myElement" *DOES NOT WORK*, but it's OKAY to use // TargetScript="$get('myElement')". Validation for this scenario will be // handled automatically by _validateParams when debugging as Target is required // to be a dom element.) delete type.__animationProperties['id']; properties = type.__animationProperties; } // Loop through each of the properties in the object and check if it's in the list // of valid property names. We will check the type of the propertyName to make sure // it's a String (as other types can be added by the ASP.NET AJAX compatability // layers to all objects and cause errors if you don't exclude them). We will first // try to set a property with the same name if it exists. If we can't find one but // the name of the property ends in 'script', then we will try to set a corresponding // dynamic property. If no matches can be found at all, we'll raise an error when // debugging. for(var property in obj) { // Ignore the special properties in the object that don't correspond // to any actual properties on the animation var prop = property.toLowerCase(); if(prop == 'animationname' || prop == 'animationchildren') { continue; } var value = obj[property]; // Try to directly set the value of this property var setter = properties[prop]; if(setter && String.isInstanceOfType(setter) && animation[setter]) { // Ignore any exceptions raised by setting the property // unless we're debugging if(!Sys.Debug.isDebug) { try { animation[setter](value); } catch(ex) { } } else { animation[setter](value); } } else { // Try to set the value of a dynamic property if(prop.endsWith('script')) { setter = properties[prop.substr(0, property.length - 6)]; if(setter && String.isInstanceOfType(setter) && animation[setter]) { animation.DynamicProperties[setter] = value; } else if(Sys.Debug.isDebug) { // Raise an error when debugging if we could not find a matching property throw Error.argument('obj', String.format(Sys.Extended.UI.Resources.Animation_NoDynamicPropertyFound, property, property.substr(0, property.length - 5))); } } else if(Sys.Debug.isDebug) { // Raise an error when debugging if we could not find a matching property throw Error.argument('obj', String.format(Sys.Extended.UI.Resources.Animation_NoPropertyFound, property)); } } } return animation; } // In the Xml comments for each of the animations below, there is a special tag // that describes how the animation is referenced from a generic XML animation description $AA.Animation = function(target, duration, fps) { // Animation is an abstract base class used as a starting point for all the other animations. // It provides the basic mechanics for the animation (playing, pausing, stopping, timing, etc.) // and leaves the actual animation to be done in the abstract methods getAnimatedValue // and setValue. // Animations need to be as fast as possible - even in debug mode. Don't add validation code to // methods involved in every step of the animation. // // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // // The DynamicProperties collection is used to associate JavaScript expressions with // properties. The expressions are evaluated just before the animation is played // everytime (in the base onStart method). The object itself maps strings with the // names of property setters (like "set_verticalOffset") to JavaScript expressions // (like "$find('MyBehavior').get_element().offsetHeight"). Note specifically that // the dynamic properties are JavaScript expressions and not abitrary statements (i.e. // you can't include things like "return foo;"), although you can include anything // inside an anonymous function definition that you immediately invoke (i.e., // "(function() { return foo; })()"). A dynamic property can be set in the generic // XML animation description by appending Script onto any legitimate property name // (for example, instead of Height="70" we could use // HeightScript="$find('MyBehavior').get_element().offsetHeight"). Any exceptions // raised when setting dynamic properties (including both JavaScript evaluation errors // and other exceptions raised by property setters) will only be propogated when // debugging. $AA.Animation.initializeBase(this); // Length of the animation in seconds this._duration = 1; // Number of steps per second this._fps = 25; // Target Sys.UI.DomElement of the animation this._target = null; // Tick event handler this._tickHandler = null; // Animation timer this._timer = null; // Percentage of the animation already played this._percentComplete = 0; // Percentage of the animation to play on each step this._percentDelta = null; // Reference to the animation that owns this animation (currently only set in // ParallelAnimation.add). This concept of ownership allows an entire animation // subtree to be driven off a single timer so all the operations are properly // synchronized. this._owner = null; // Reference to the animation that contains this as a child (this is set // in ParentAnimation.add). The primary use of the parent animation is in // resolving the animation target when one isn't specified. this._parentAnimation = null; // The DynamicProperties collection is used to associate JavaScript expressions with // properties. The expressions are evaluated just before the animation is played // everytime (in the base onStart method). See the additional information in the // XML comment above. this.DynamicProperties = {}; // Set the target, duration, and fps if they were provided in the constructor if(target) { this.set_target(target); } if(duration) { this.set_duration(duration); } if(fps) { this.set_fps(fps); } } $AA.Animation.prototype = { dispose: function() { if(this._timer) { this._timer.dispose(); this._timer = null; } this._tickHandler = null; this._target = null; $AA.Animation.callBaseMethod(this, 'dispose'); }, play: function() { // Play the animation from the beginning or where it was left off when paused. // If this animation is the child of another, you must call play on its parent instead. // If ownership of this animation has been claimed, then we'll require the parent to // handle playing the animation (this is very important because then the entire animation // tree runs on the same timer and updates consistently) if(!this._owner) { var resume = true; if(!this._timer) { resume = false; if(!this._tickHandler) { this._tickHandler = Function.createDelegate(this, this._onTimerTick); } this._timer = new Sys.Timer(); this._timer.add_tick(this._tickHandler); this.onStart(); this._timer.set_interval(1000 / this._fps); this._percentDelta = 100 / (this._duration * this._fps); this._updatePercentComplete(0, true); } this._timer.set_enabled(true); this.raisePropertyChanged('isPlaying'); if(!resume) { this.raisePropertyChanged('isActive'); } } }, pause: function() { // Pause the animation if it is playing. Calling play will resume where // the animation left off. // If this animation is the child of another, you must call pause on its parent instead. if(!this._owner) { if(this._timer) { this._timer.set_enabled(false); this.raisePropertyChanged('isPlaying'); } } }, stop: function(finish) { // Stop playing the animation. // If this animation is the child of another, you must call stop on // its parent instead. // // "finish" - Whether or not stopping the animation should leave the target element in a state // consistent with the animation playing completely by performing the last step. // The default value is true. if(!this._owner) { var t = this._timer; this._timer = null; if(t) { t.dispose(); if(this._percentComplete !== 100) { this._percentComplete = 100; this.raisePropertyChanged('percentComplete'); if(finish || finish === undefined) { this.onStep(100); } } this.onEnd(); this.raisePropertyChanged('isPlaying'); this.raisePropertyChanged('isActive'); } } }, onStart: function() { // The onStart method is called just before the animation is played each time. this.raiseStarted(); // Initialize any dynamic properties for(var property in this.DynamicProperties) { try { // Invoke the property's setter on the evaluated expression this[property](eval(this.DynamicProperties[property])); } catch(ex) { // Propogate any exceptions if we're debugging, otherwise eat them if(Sys.Debug.isDebug) { throw ex; } } } }, onStep: function(percentage) { // The onStep method is called repeatedly to progress the animation through each frame // // "percentage" - percentage of the animation already complete this.setValue(this.getAnimatedValue(percentage)); this.raiseStep(); }, onEnd: function() { this.raiseEnded(); }, getAnimatedValue: function(percentage) { // Determine the state of the animation after the given percentage of its duration has elapsed // Returns state of the animation after the given percentage of its duration has elapsed that will // be passed to setValue // // "percentage" - percentage of the animation already complete throw Error.notImplemented(); }, setValue: function(value) { // Set the current state of the animation // Returns current state of the animation (as retreived from getAnimatedValue) throw Error.notImplemented(); }, interpolate: function(start, end, percentage) { // The interpolate function is used to find the appropriate value between starting and // ending values given the current percentage. // In the future, we hope to make several implementations of this available so we can dynamically // change the apparent speed of the animations, although it may make more sense to modify the // _updatePercentComplete function instead. // Returns the desired percentage between the start and end values // // "start"- start of the range to interpolate // "end" - end of the range to interpolate // "percentage" - percentage completed in the range to interpolate return start + (end - start) * (percentage / 100); }, _onTimerTick: function() { // Handler for the tick event to move the animation along through its duration this._updatePercentComplete(this._percentComplete + this._percentDelta, true); }, _updatePercentComplete: function(percentComplete, animate) { // Update the animation and its target given the current percentage of its duration that // has already elapsed // // "percentComplete" - percentage of the animation duration that has already elapsed // "animate" - whether or not updating the animation should visually modify the animation's target if(percentComplete > 100) { percentComplete = 100; } this._percentComplete = percentComplete; this.raisePropertyChanged('percentComplete'); if(animate) { this.onStep(percentComplete); } if(percentComplete === 100) { this.stop(false); } }, setOwner: function(owner) { // Make this animation the child of another animation // // "owner" - parent animation this._owner = owner; }, raiseStarted: function() { var handlers = this.get_events().getHandler('started'); if(handlers) { handlers(this, Sys.EventArgs.Empty); } }, add_started: function(handler) { this.get_events().addHandler("started", handler); }, remove_started: function(handler) { this.get_events().removeHandler("started", handler); }, raiseEnded: function() { var handlers = this.get_events().getHandler('ended'); if(handlers) { handlers(this, Sys.EventArgs.Empty); } }, add_ended: function(handler) { this.get_events().addHandler("ended", handler); }, remove_ended: function(handler) { this.get_events().removeHandler("ended", handler); }, raiseStep: function() { var handlers = this.get_events().getHandler('step'); if(handlers) { handlers(this, Sys.EventArgs.Empty); } }, add_step: function(handler) { this.get_events().addHandler("step", handler); }, remove_step: function(handler) { this.get_events().removeHandler("step", handler); }, get_target: function() { // Target of the animation. If the target of this animation is null and // the animation has a parent, then it will recursively use the target of // the parent animation instead. // Do not set this property in a generic Xml animation description. It should be set // using either the extender's TargetControlID or the AnimationTarget property (the latter // maps to Sys.Extended.UI.Animation.set_animationTarget). The only valid way to // set this property in the generic Xml animation description is to use the dynamic // property TargetScript="$get('myElement')". if(!this._target && this._parentAnimation) { return this._parentAnimation.get_target(); } return this._target; }, set_target: function(value) { if(this._target != value) { this._target = value; this.raisePropertyChanged('target'); } }, set_animationTarget: function(id) { // ID of a Sys.UI.DomElement or Sys.UI.Control to use as the target of the animation // If no Sys.UI.DomElement or Sys.UI.Control can be found for the given ID, an // argument exception will be thrown. // Try to find a Sys.UI.DomElement var target = null; var element = $get(id); if(element) { target = element; } else { // Try to find the control in the AJAX controls collection var ctrl = $find(id); if(ctrl) { element = ctrl.get_element(); if(element) { target = element; } } } // Use the new target if we have one, or raise an error if not if(target) { this.set_target(target); } else { throw Error.argument('id', String.format(Sys.Extended.UI.Resources.Animation_TargetNotFound, id)); } }, get_duration: function() { // Length of the animation in seconds. The default is 1. return this._duration; }, set_duration: function(value) { value = this._getFloat(value); if(this._duration != value) { this._duration = value; this.raisePropertyChanged('duration'); } }, get_fps: function() { // Number of steps per second. The default is 25. return this._fps; }, set_fps: function(value) { value = this._getInteger(value); if(this.fps != value) { this._fps = value; this.raisePropertyChanged('fps'); } }, get_isActive: function() { return (this._timer !== null); }, get_isPlaying: function() { return (this._timer !== null) && this._timer.get_enabled(); }, get_percentComplete: function() { return this._percentComplete; }, _getBoolean: function(value) { if(String.isInstanceOfType(value)) { return Boolean.parse(value); } return value; }, _getInteger: function(value) { if(String.isInstanceOfType(value)) { return parseInt(value); } return value; }, _getFloat: function(value) { if(String.isInstanceOfType(value)) { return parseFloat(value); } return value; }, _getEnum: function(value, type) { // Helper to convert strings to enum values for property setters // Returns value that has been converted if it was a string // // "value" - value to convert if it's a string // "type" - type of the enum to convert to if(String.isInstanceOfType(value) && type && type.parse) { return type.parse(value); } return value; } } $AA.Animation.registerClass('Sys.Extended.UI.Animation.Animation', Sys.Component); $AA.registerAnimation('animation', $AA.Animation); $AA.ParentAnimation = function(target, duration, fps, animations) { // The ParentAnimation serves as a base class for all animations that contain children (such as // Sys.Extended.UI.Animation.ParallelAnimation, Sys.Extended.UI.SequenceAnimation, // etc.). It does not actually play the animations, so any classes that inherit from it must do so. Any animation // that requires nested child animations must inherit from this class, although it will likely want to inherit off of // Sys.Extended.UI.Animation.ParallelAnimation or Sys.Extended.UI.SequenceAnimation // which will actually play their child animations. // // "target"- target of the animation // "duration"- length of the animation in seconds. he default is 1. // "fps" - number of steps per second. The default is 25. // "animations" - array of child animations to be played $AA.ParentAnimation.initializeBase(this, [target, duration, fps]); // Array of child animations (there are no assumptions placed on order because // it will matter for some derived animations like SequenceAnimation, but not // for others like ParallelAnimation) that is demand created in add this._animations = []; // Add any child animations passed into the constructor if(animations && animations.length) { for(var i = 0; i < animations.length; i++) { this.add(animations[i]); } } } $AA.ParentAnimation.prototype = { initialize: function() { // Initialize the parent along with any child animations that have not yet been initialized themselves $AA.ParentAnimation.callBaseMethod(this, 'initialize'); // Initialize all the uninitialized child animations if(this._animations) { for(var i = 0; i < this._animations.length; i++) { var animation = this._animations[i]; if(animation && !animation.get_isInitialized) { animation.initialize(); } } } }, dispose: function() { this.clear(); this._animations = null; $AA.ParentAnimation.callBaseMethod(this, 'dispose'); }, get_animations: function() { // Array of child animations to be played (there are no assumptions placed on order because it will matter for some // derived animations like Sys.Extended.UI.Animation.SequenceAnimation, but not for // others like Sys.Extended.UI.Animation.ParallelAnimation). To manipulate the child // animations, use the functions add, clear, remove, and removeAt. return this._animations; }, add: function(animation) { // Add an animation as a child of this animation. // // "animation" - child animation to add if(this._animations) { if(animation) { animation._parentAnimation = this; } Array.add(this._animations, animation); this.raisePropertyChanged('animations'); } }, remove: function(animation) { // Remove the animation from the array of child animations. // This will dispose the removed animation. // // "animation" - child animation to remove if(this._animations) { if(animation) { animation.dispose(); } Array.remove(this._animations, animation); this.raisePropertyChanged('animations'); } }, removeAt: function(index) { // Remove the animation at a given index from the array of child animations. // // "index" - Index of the child animation to remove if(this._animations) { var animation = this._animations[index]; if(animation) { animation.dispose(); } Array.removeAt(this._animations, index); this.raisePropertyChanged('animations'); } }, clear: function() { // Clear the array of child animations. // This will dispose the cleared child animations. if(this._animations) { for(var i = this._animations.length - 1; i >= 0; i--) { this._animations[i].dispose(); this._animations[i] = null; } Array.clear(this._animations); this._animations = []; this.raisePropertyChanged('animations'); } } } $AA.ParentAnimation.registerClass('Sys.Extended.UI.Animation.ParentAnimation', $AA.Animation); $AA.registerAnimation('parent', $AA.ParentAnimation); $AA.ParallelAnimation = function(target, duration, fps, animations) { // The ParallelAnimation plays several animations simultaneously. It inherits from // Sys.Extended.UI.Animation.ParentAnimation, but makes itself the owner of all // its child animations to allow the use a single timer and syncrhonization mechanisms shared with // all the children (in other words, the duration properties of any child animations // are ignored in favor of the parent's duration). It is very useful in creating // sophisticated effects through combination of simpler animations. // // "target"- target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "animations" - array of child animations $AA.ParallelAnimation.initializeBase(this, [target, duration, fps, animations]); } $AA.ParallelAnimation.prototype = { add: function(animation) { // Add an animation as a child of this animation and make ourselves its owner. // // "animation" - child animation to add $AA.ParallelAnimation.callBaseMethod(this, 'add', [animation]); animation.setOwner(this); }, onStart: function() { // Get the child animations ready to play $AA.ParallelAnimation.callBaseMethod(this, 'onStart'); var animations = this.get_animations(); for(var i = 0; i < animations.length; i++) { animations[i].onStart(); } }, onStep: function(percentage) { // Progress the child animations through each frame // // "percentage" - percentage of the animation already complete var animations = this.get_animations(); for(var i = 0; i < animations.length; i++) { animations[i].onStep(percentage); } }, onEnd: function() { // Finish playing all of the child animations var animations = this.get_animations(); for(var i = 0; i < animations.length; i++) { animations[i].onEnd(); } $AA.ParallelAnimation.callBaseMethod(this, 'onEnd'); } } $AA.ParallelAnimation.registerClass('Sys.Extended.UI.Animation.ParallelAnimation', $AA.ParentAnimation); $AA.registerAnimation('parallel', $AA.ParallelAnimation); $AA.SequenceAnimation = function(target, duration, fps, animations, iterations) { // The SequenceAnimation runs several animations one after the other. It can also // repeat the sequence of animations for a specified number of iterations (which defaults to a // single iteration, but will repeat forever if you specify zero or less iterations). Also, the // SequenceAnimation cannot be a child of a Sys.Extended.UI.Animation.ParallelAnimation // (or any animation inheriting from it). // The SequenceAnimation ignores the duration and fps // properties, and will let each of its child animations use any settings they please. // // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps"- number of steps per second. The default is 25. // "animations" - array of child animations // "iterations" - number of times to repeatedly play the sequence. If zero or less iterations are specified, the sequence // will repeat forever. The default value is 1 iteration. $AA.SequenceAnimation.initializeBase(this, [target, duration, fps, animations]); // Handler used to determine when an animation has finished this._handler = null; // Flags to note whether we're playing, paused, or stopped this._paused = false; this._playing = false; // Index of the currently executing animation in the sequence this._index = 0; // Counter used when playing the animation to determine the remaining number of times to play the entire sequence this._remainingIterations = 0; // Number of iterations this._iterations = (iterations !== undefined) ? iterations : 1; } $AA.SequenceAnimation.prototype = { dispose: function() { this._handler = null; $AA.SequenceAnimation.callBaseMethod(this, 'dispose'); }, stop: function() { // Stop playing the entire sequence of animations // Stopping this animation will perform the last step of each child animation, thereby leaving their // target elements in a state consistent with the animation playing completely. If this animation is // the child of another, you must call stop on its parent instead. if(this._playing) { var animations = this.get_animations(); if(this._index < animations.length) { // Remove the handler from the currently running animation animations[this._index].remove_ended(this._handler); // Call stop on all remaining animations to ensure their // effects will be seen for(var i = this._index; i < animations.length; i++) { animations[i].stop(); } } this._playing = false; this._paused = false; this.raisePropertyChanged('isPlaying'); this.onEnd(); } }, pause: function() { // Pause the animation if it is playing. Calling play will resume where // the animation left off. // If this animation is the child of another, you must call pause on its parent instead. if(this.get_isPlaying()) { var current = this.get_animations()[this._index]; if(current != null) { current.pause(); } this._paused = true; this.raisePropertyChanged('isPlaying'); } }, play: function() { // Play the sequence of animations from the beginning or where it was left off when paused // If this animation is the child of another, you must call play on its parent instead var animations = this.get_animations(); if(!this._playing) { this._playing = true; if(this._paused) { this._paused = false; var current = animations[this._index]; if(current != null) { current.play(); this.raisePropertyChanged('isPlaying'); } } else { this.onStart(); // Reset the index and attach the handler to the first this._index = 0; var first = animations[this._index]; if(first) { first.add_ended(this._handler); first.play(); this.raisePropertyChanged('isPlaying'); } else { this.stop(); } } } }, onStart: function() { // The onStart method is called just before the animation is played each time $AA.SequenceAnimation.callBaseMethod(this, 'onStart'); this._remainingIterations = this._iterations - 1; // Create the handler we attach to each animation as it plays to determine when we've finished with it if(!this._handler) { this._handler = Function.createDelegate(this, this._onEndAnimation); } }, _onEndAnimation: function() { // Wait for the end of each animation, and then continue by playing the other animations remaining // in the sequence. Stop when it reaches the last animation and there are no remaining iterations. // Remove the handler from the current animation var animations = this.get_animations(); var current = animations[this._index++]; if(current) { current.remove_ended(this._handler); } // Keep running animations and stop when we're out if(this._index < animations.length) { var next = animations[this._index]; next.add_ended(this._handler); next.play(); } else if(this._remainingIterations >= 1 || this._iterations <= 0) { this._remainingIterations--; this._index = 0; var first = animations[0]; first.add_ended(this._handler); first.play(); } else { this.stop(); } }, onStep: function(percentage) { // Raises an invalid operation exception because this will only be called if a SequenceAnimation // has been nested inside an (or a derived type). // "percentage" - percentage of the animation already complete throw Error.invalidOperation(Sys.Extended.UI.Resources.Animation_CannotNestSequence); }, onEnd: function() { // The onEnd method is called just after the animation is played each time. this._remainingIterations = 0; $AA.SequenceAnimation.callBaseMethod(this, 'onEnd'); }, get_isActive: function() { return true; }, get_isPlaying: function() { return this._playing && !this._paused; }, get_iterations: function() { // Number of times to repeatedly play the sequence. If zero or less iterations are specified, the sequence // will repeat forever. The default value is 1 iteration. return this._iterations; }, set_iterations: function(value) { value = this._getInteger(value); if(this._iterations != value) { this._iterations = value; this.raisePropertyChanged('iterations'); } }, get_isInfinite: function() { return this._iterations <= 0; } } $AA.SequenceAnimation.registerClass('Sys.Extended.UI.Animation.SequenceAnimation', $AA.ParentAnimation); $AA.registerAnimation('sequence', $AA.SequenceAnimation); $AA.SelectionAnimation = function(target, duration, fps, animations) { // The SelectionAnimation will run a single animation chosen from of its child animations. It is // important to note that the SelectionAnimation ignores the duration and fps // properties, and will let each of its child animations use any settings they please. This is a base class with no // functional implementation, so consider using ConditionAnimation or CaseAnimation instead. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "animations" - array of child animations $AA.SelectionAnimation.initializeBase(this, [target, duration, fps, animations]); // Index of the animation selected to play this._selectedIndex = -1; // Reference to the animation selected to play this._selected = null; } $AA.SelectionAnimation.prototype = { getSelectedIndex: function() { // Get the index of the animation that is selected to be played. If this returns an index outside the bounds of // the child animations array, then nothing is played. // returns index of the selected child animation to play throw Error.notImplemented(); }, onStart: function() { // The onStart method is called just before the animation is played each time. $AA.SelectionAnimation.callBaseMethod(this, 'onStart'); var animations = this.get_animations(); this._selectedIndex = this.getSelectedIndex(); if(this._selectedIndex >= 0 && this._selectedIndex < animations.length) { this._selected = animations[this._selectedIndex]; if(this._selected) { this._selected.setOwner(this); this._selected.onStart(); } } }, onStep: function(percentage) { // The onStep method is called repeatedly to progress the animation through each frame // "percentage" - percentage of the animation already complete if(this._selected) { this._selected.onStep(percentage); } }, onEnd: function() { // The onEnd method is called just after the animation is played each time. if(this._selected) { this._selected.onEnd(); this._selected.setOwner(null); } this._selected = null; this._selectedIndex = null; $AA.SelectionAnimation.callBaseMethod(this, 'onEnd'); } } $AA.SelectionAnimation.registerClass('Sys.Extended.UI.Animation.SelectionAnimation', $AA.ParentAnimation); $AA.registerAnimation('selection', $AA.SelectionAnimation); $AA.ConditionAnimation = function(target, duration, fps, animations, conditionScript) { // The ConditionAnimation is used as a control structure to play a specific child animation // depending on the result of executing the conditionScript. If the conditionScript // evaluates to true, the first child animation is played. If it evaluates to false, // the second child animation is played (although nothing is played if a second animation is not present). // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "animations" - array of child animations // "conditionScript" - javaScript that should evaluate to true or false to determine which child // animation to play. $AA.ConditionAnimation.initializeBase(this, [target, duration, fps, animations]); // Condition to determine which index we will play this._conditionScript = conditionScript; } $AA.ConditionAnimation.prototype = { getSelectedIndex: function() { // Get the index of the animation that is selected to be played. If this returns an index outside the bounds of // the child animations array, then nothing is played. // returns index of the selected child animation to play var selected = -1; if(this._conditionScript && this._conditionScript.length > 0) { try { selected = eval(this._conditionScript) ? 0 : 1; } catch(ex) { } } return selected; }, get_conditionScript: function() { // JavaScript that should evaluate to true or false to determine which // child animation to play. return this._conditionScript; }, set_conditionScript: function(value) { if(this._conditionScript != value) { this._conditionScript = value; this.raisePropertyChanged('conditionScript'); } } } $AA.ConditionAnimation.registerClass('Sys.Extended.UI.Animation.ConditionAnimation', $AA.SelectionAnimation); $AA.registerAnimation('condition', $AA.ConditionAnimation); $AA.CaseAnimation = function(target, duration, fps, animations, selectScript) { // The CaseAnimation is used as a control structure to play a specific child animation depending on // the result of executing the selectScript, which should return the index of the child animation to // play (this is similar to the case or select statements in C#/VB, etc.). If the provided // index is outside the bounds of the child animations array (or if nothing was returned) then we will not play anything. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "animations" - array of child animations // "selectScript" - JavaScript that should evaluate to the index of the appropriate child animation to play. // If this returns an index outside the bounds of the child animations array, then nothing is played. $AA.CaseAnimation.initializeBase(this, [target, duration, fps, animations]); // Condition to determine which index we will play this._selectScript = selectScript; } $AA.CaseAnimation.prototype = { getSelectedIndex: function() { // Get the index of the animation that is selected to be played. If this returns an index outside the bounds of // the child animations array, then nothing is played. // returns index of the selected child animation to play var selected = -1; if(this._selectScript && this._selectScript.length > 0) { try { var result = eval(this._selectScript) if(result !== undefined) selected = result; } catch(ex) { } } return selected; }, get_selectScript: function() { // JavaScript that should evaluate to the index of the appropriate child animation to play. // If this returns an index outside the bounds of the child animations array, then nothing is played. return this._selectScript; }, set_selectScript: function(value) { if(this._selectScript != value) { this._selectScript = value; this.raisePropertyChanged('selectScript'); } } } $AA.CaseAnimation.registerClass('Sys.Extended.UI.Animation.CaseAnimation', $AA.SelectionAnimation); $AA.registerAnimation('case', $AA.CaseAnimation); $AA.FadeEffect = function() { // The FadeEffect enumeration determines whether a fade animation is used to fade in or fade out. throw Error.invalidOperation(); } $AA.FadeEffect.prototype = { FadeIn: 0, FadeOut: 1 } $AA.FadeEffect.registerEnum("Sys.Extended.UI.Animation.FadeEffect", false); $AA.FadeAnimation = function(target, duration, fps, effect, minimumOpacity, maximumOpacity, forceLayoutInIE) { // The FadeAnimation is used to fade an element in or out of view, depending on the // provided , by settings its opacity. // The minimum and maximum opacity values can be specified to precisely control the fade. // You may also consider using FadeInAnimation or FadeOutAnimation if you know the only direction you // are fading. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "effect" - determine whether to fade the element in or fade the element out. The possible values are FadeIn // and FadeOut. The default value is FadeOut. // "minimumOpacity" - minimum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 0. // "maximumOpacity" - maximum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 1. // "forceLayoutInIE" - whether or not we should force a layout to be created for Internet Explorer by giving it a width and setting its // background color (the latter is required in case the user has ClearType enabled). The default value is true. // This is obviously ignored when working in other browsers. $AA.FadeAnimation.initializeBase(this, [target, duration, fps]); // The effect determines whether or not we fade in or out this._effect = (effect !== undefined) ? effect : $AA.FadeEffect.FadeIn; // Maximum and minimum opacities default to 100% and 0% this._max = (maximumOpacity !== undefined) ? maximumOpacity : 1; this._min = (minimumOpacity !== undefined) ? minimumOpacity : 0; // Starting and ending opacities this._start = this._min; this._end = this._max; // Whether the a layout has already been created (to work around IE // problems). this._layoutCreated = false; // Whether or not we should force a layout to be created for IE by giving it a width // and setting its background color (the latter is required in case the user has ClearType enabled). // http://msdn.microsoft.com/library/default.asp?url=/workshop/author/filter/reference/filters/alpha.asp this._forceLayoutInIE = (forceLayoutInIE === undefined || forceLayoutInIE === null) ? true : forceLayoutInIE; // Current target of the animation that is cached before the animation plays (since looking up // the target could mean walking all the way up to the root of the animation's tree, which we don't // want to do for every step of the animation) this._currentTarget = null; // Properly set up the min/max values provided by the constructor this._resetOpacities(); } $AA.FadeAnimation.prototype = { _resetOpacities: function() { // Set the starting and ending opacity values based on the effect (i.e. when we're fading // in we go from _min to _max, but we go _max to // _min when fading out) if(this._effect == $AA.FadeEffect.FadeIn) { this._start = this._min; this._end = this._max; } else { this._start = this._max; this._end = this._min; } }, _createLayout: function() { // Create a layout when using Internet Explorer (which entails setting a width and also // a background color if it currently has neither) var element = this._currentTarget; if(element) { // Get the original width/height/back color this._originalWidth = $common.getCurrentStyle(element, 'width'); var originalHeight = $common.getCurrentStyle(element, 'height'); this._originalBackColor = $common.getCurrentStyle(element, 'backgroundColor'); // Set the width which will force the creation of a layout if((!this._originalWidth || this._originalWidth == '' || this._originalWidth == 'auto') && (!originalHeight || originalHeight == '' || originalHeight == 'auto')) { element.style.width = element.offsetWidth + 'px'; } // Set the back color to avoid ClearType problems if(!this._originalBackColor || this._originalBackColor == '' || this._originalBackColor == 'transparent' || this._originalBackColor == 'rgba(0, 0, 0, 0)') { element.style.backgroundColor = $common.getInheritedBackgroundColor(element); } // Mark that we've created the layout so we only do it once this._layoutCreated = true; } }, onStart: function() { // The onStart method is called just before the animation is played each time. $AA.FadeAnimation.callBaseMethod(this, 'onStart'); this._currentTarget = this.get_target(); this.setValue(this._start); // Force the creation of a layout in IE if we're supposed to and the current browser is Internet Explorer if(this._forceLayoutInIE && !this._layoutCreated && Sys.Browser.agent == Sys.Browser.InternetExplorer) { this._createLayout(); } }, getAnimatedValue: function(percentage) { // Determine the current opacity after the given percentage of its duration has elapsed // "percentage" - percentage of the animation already complete // returns - current opacity after the given percentage of its duration has elapsed that will be passed to setValue return this.interpolate(this._start, this._end, percentage); }, setValue: function(value) { // Set the current opacity of the element. // "value" - current opacity (as retreived from getAnimatedValue) // This method will be replaced by a dynamically generated function that requires no logic // to determine whether it should use filters or the style's opacity. if(this._currentTarget) { $common.setElementOpacity(this._currentTarget, value); } }, get_effect: function() { // Determine whether to fade the element in or fade the element out. The possible values are // FadeIn and FadeOut. The default value is FadeOut. return this._effect; }, set_effect: function(value) { value = this._getEnum(value, $AA.FadeEffect); if(this._effect != value) { this._effect = value; this._resetOpacities(); this.raisePropertyChanged('effect'); } }, get_minimumOpacity: function() { // Minimum opacity to use when fading in or out. Its value can range from between 0 to 1. // The default value is 0. return this._min; }, set_minimumOpacity: function(value) { value = this._getFloat(value); if(this._min != value) { this._min = value; this._resetOpacities(); this.raisePropertyChanged('minimumOpacity'); } }, get_maximumOpacity: function() { // Maximum opacity to use when fading in or out. Its value can range from between 0 to 1. // The default value is 1. return this._max; }, set_maximumOpacity: function(value) { value = this._getFloat(value); if(this._max != value) { this._max = value; this._resetOpacities(); this.raisePropertyChanged('maximumOpacity'); } }, get_forceLayoutInIE: function() { // Whether or not we should force a layout to be created for Internet Explorer by giving it a width and setting its // background color (the latter is required in case the user has ClearType enabled). The default value is true. // This is obviously ignored when working in other browsers. return this._forceLayoutInIE; }, set_forceLayoutInIE: function(value) { value = this._getBoolean(value); if(this._forceLayoutInIE != value) { this._forceLayoutInIE = value; this.raisePropertyChanged('forceLayoutInIE'); } }, set_startValue: function(value) { // Set the start value (so that child animations can set the current opacity as the start value when fading in or out) value = this._getFloat(value); this._start = value; } } $AA.FadeAnimation.registerClass('Sys.Extended.UI.Animation.FadeAnimation', $AA.Animation); $AA.registerAnimation('fade', $AA.FadeAnimation); $AA.FadeInAnimation = function(target, duration, fps, minimumOpacity, maximumOpacity, forceLayoutInIE) { // The FadeInAnimation will fade the target in by moving from hidden to visible. // It starts the animation the target's current opacity. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "minimumOpacity" - minimum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 0. // "maximumOpacity" - maximum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 1. // "forceLayoutInIE" - whether or not we should force a layout to be created for Internet Explorer by giving it a width and setting its // background color (the latter is required in case the user has ClearType enabled). The default value is true. // This is obviously ignored when working in other browsers. $AA.FadeInAnimation.initializeBase(this, [target, duration, fps, $AA.FadeEffect.FadeIn, minimumOpacity, maximumOpacity, forceLayoutInIE]); } $AA.FadeInAnimation.prototype = { onStart: function() { // The onStart method is called just before the animation is played each time. $AA.FadeInAnimation.callBaseMethod(this, 'onStart'); if(this._currentTarget) { this.set_startValue($common.getElementOpacity(this._currentTarget)); } } } $AA.FadeInAnimation.registerClass('Sys.Extended.UI.Animation.FadeInAnimation', $AA.FadeAnimation); $AA.registerAnimation('fadeIn', $AA.FadeInAnimation); $AA.FadeOutAnimation = function(target, duration, fps, minimumOpacity, maximumOpacity, forceLayoutInIE) { // The FadeInAnimation will fade the element out by moving from visible to hidden. It starts the animation // at the element's current opacity. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "minimumOpacity" - minimum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 0. // "maximumOpacity" - maximum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 1. // "forceLayoutInIE" - whether or not we should force a layout to be created for Internet Explorer by giving it a width and setting its // background color (the latter is required in case the user has ClearType enabled). The default value is true. // This is obviously ignored when working in other browsers. $AA.FadeOutAnimation.initializeBase(this, [target, duration, fps, $AA.FadeEffect.FadeOut, minimumOpacity, maximumOpacity, forceLayoutInIE]); } $AA.FadeOutAnimation.prototype = { onStart: function() { // The onStart method is called just before the animation is played each time. $AA.FadeOutAnimation.callBaseMethod(this, 'onStart'); if(this._currentTarget) { this.set_startValue($common.getElementOpacity(this._currentTarget)); } } } $AA.FadeOutAnimation.registerClass('Sys.Extended.UI.Animation.FadeOutAnimation', $AA.FadeAnimation); $AA.registerAnimation('fadeOut', $AA.FadeOutAnimation); $AA.PulseAnimation = function(target, duration, fps, iterations, minimumOpacity, maximumOpacity, forceLayoutInIE) { // The PulseAnimation fades an element in and our repeatedly to create a pulsating // effect. The iterations determines how many pulses there will be (which defaults // to three, but it will repeat infinitely if given zero or less). The duration // property defines the duration of each fade in or fade out, not the duration of // the animation as a whole. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "iterations" - number of times to repeatedly play the sequence. If zero or less iterations are specified, the sequence // will repeat forever. The default value is 1 iteration. // "minimumOpacity" - minimum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 0. // "maximumOpacity" - maximum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 1. // "forceLayoutInIE" - whether or not we should force a layout to be created for Internet Explorer by giving it a width and setting its // background color (the latter is required in case the user has ClearType enabled). The default value is true. // This is obviously ignored when working in other browsers. $AA.PulseAnimation.initializeBase(this, [target, duration, fps, null, ((iterations !== undefined) ? iterations : 3)]); // Create the FadeOutAnimation this._out = new $AA.FadeOutAnimation(target, duration, fps, minimumOpacity, maximumOpacity, forceLayoutInIE); this.add(this._out); // Create the FadeInAnimation this._in = new $AA.FadeInAnimation(target, duration, fps, minimumOpacity, maximumOpacity, forceLayoutInIE); this.add(this._in); } $AA.PulseAnimation.prototype = { get_minimumOpacity: function() { // Minimum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 0. return this._out.get_minimumOpacity(); }, set_minimumOpacity: function(value) { value = this._getFloat(value); this._out.set_minimumOpacity(value); this._in.set_minimumOpacity(value); this.raisePropertyChanged('minimumOpacity'); }, get_maximumOpacity: function() { // Maximum opacity to use when fading in or out. Its value can range from between 0 to 1. The default value is 1. return this._out.get_maximumOpacity(); }, set_maximumOpacity: function(value) { value = this._getFloat(value); this._out.set_maximumOpacity(value); this._in.set_maximumOpacity(value); this.raisePropertyChanged('maximumOpacity'); }, get_forceLayoutInIE: function() { // Whether or not we should force a layout to be created for Internet Explorer by giving it a width and setting its // background color (the latter is required in case the user has ClearType enabled). The default value is true. // This is obviously ignored when working in other browsers. return this._out.get_forceLayoutInIE(); }, set_forceLayoutInIE: function(value) { value = this._getBoolean(value); this._out.set_forceLayoutInIE(value); this._in.set_forceLayoutInIE(value); this.raisePropertyChanged('forceLayoutInIE'); }, set_duration: function(value) { // Override the duration property value = this._getFloat(value); $AA.PulseAnimation.callBaseMethod(this, 'set_duration', [value]); this._in.set_duration(value); this._out.set_duration(value); }, set_fps: function(value) { // Override the fps property value = this._getInteger(value); $AA.PulseAnimation.callBaseMethod(this, 'set_fps', [value]); this._in.set_fps(value); this._out.set_fps(value); } } $AA.PulseAnimation.registerClass('Sys.Extended.UI.Animation.PulseAnimation', $AA.SequenceAnimation); $AA.registerAnimation('pulse', $AA.PulseAnimation); $AA.PropertyAnimation = function(target, duration, fps, property, propertyKey) { // The PropertyAnimation is a useful base animation that will assign the value from // getAnimatedValue to a specified property. You can provide the name of // a property alongside an optional propertyKey (which indicates the value // property[propertyKey], like style['backgroundColor']). // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "property" - property of the target element to set when animating // "propertyKey" - optional key of the property to be set (which indicates the value property[propertyKey], // like style['backgroundColor']). Note that for the style property, the key must be in a JavaScript friendly // format (i.e. backgroundColor instead of background-color). $AA.PropertyAnimation.initializeBase(this, [target, duration, fps]); // Name of the property to set this._property = property; // Optional Key of the property to set (i.e., if the property were "style" then // this might be "backgroundColor") this._propertyKey = propertyKey; // Current target of the animation that is cached before the animation plays (since looking up // the target could mean walking all the way up to the root of the animation's tree, which we don't // want to do for every step of the animation) this._currentTarget = null; } $AA.PropertyAnimation.prototype = { onStart: function() { // The onStart method is called just before the animation is played each time. $AA.PropertyAnimation.callBaseMethod(this, 'onStart'); this._currentTarget = this.get_target(); }, setValue: function(value) { var element = this._currentTarget; if(element && this._property && this._property.length > 0) { if(this._propertyKey && this._propertyKey.length > 0 && element[this._property]) { element[this._property][this._propertyKey] = value; } else { element[this._property] = value; } } }, getValue: function() { var element = this.get_target(); if(element && this._property && this._property.length > 0) { var property = element[this._property]; if(property) { if(this._propertyKey && this._propertyKey.length > 0) { return property[this._propertyKey]; } return property; } } return null; }, get_property: function() { return this._property; }, set_property: function(value) { if(this._property != value) { this._property = value; this.raisePropertyChanged('property'); } }, get_propertyKey: function() { // Optional key of the property to be set (which indicates the value property[propertyKey], like style['backgroundColor']). // Note that for the style property, the key must be in a JavaScript friendly format (i.e. backgroundColor instead of background-color). return this._propertyKey; }, set_propertyKey: function(value) { if(this._propertyKey != value) { this._propertyKey = value; this.raisePropertyChanged('propertyKey'); } } } $AA.PropertyAnimation.registerClass('Sys.Extended.UI.Animation.PropertyAnimation', $AA.Animation); $AA.registerAnimation('property', $AA.PropertyAnimation); $AA.DiscreteAnimation = function(target, duration, fps, property, propertyKey, values) { // The DiscreteAnimation inherits from // and sets the value of the property to the elements in a provided array of values. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "property" - property of the target element to set when animating // "propertyKey" - optional key of the property to be set (which indicates the value property[propertyKey], // like style['backgroundColor']). Note that for the style property, the key must be in a JavaScript friendly // format (i.e. backgroundColor instead of background-color). // "values" - array of possible values of the property that will be iterated over as the animation is played $AA.DiscreteAnimation.initializeBase(this, [target, duration, fps, property, propertyKey]); // Values to assign to the property this._values = (values && values.length) ? values : []; } $AA.DiscreteAnimation.prototype = { getAnimatedValue: function(percentage) { // Assign the value whose index corresponds to the current percentage // "percentage" - percentage of the animation already complete // returns - state of the animation after the given percentage of its duration has elapsed that will // be passed to setValue var index = Math.floor(this.interpolate(0, this._values.length - 1, percentage)); return this._values[index]; }, get_values: function() { // Array of possible values of the property that will be iterated over as the animation is played return this._values; }, set_values: function(value) { if(this._values != value) { this._values = value; this.raisePropertyChanged('values'); } } } $AA.DiscreteAnimation.registerClass('Sys.Extended.UI.Animation.DiscreteAnimation', $AA.PropertyAnimation); $AA.registerAnimation('discrete', $AA.DiscreteAnimation); $AA.InterpolatedAnimation = function(target, duration, fps, property, propertyKey, startValue, endValue) { // The InterpolatedAnimation assigns a range of values between startValue // and endValue to the designated property. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "property" - property of the target element to set when animating. The default value is 'style'. // "propertyKey" - optional key of the property to be set (which indicates the value property[propertyKey], // like style['backgroundColor']). Note that for the style property, the key must be in a JavaScript friendly // format (i.e. backgroundColor instead of background-color). // "startValue" - start of the range of values // "endValue" - end of the range of values $AA.InterpolatedAnimation.initializeBase(this, [target, duration, fps, ((property !== undefined) ? property : 'style'), propertyKey]); // Start and end values this._startValue = startValue; this._endValue = endValue; } $AA.InterpolatedAnimation.prototype = { get_startValue: function() { return this._startValue; }, set_startValue: function(value) { value = this._getFloat(value); if(this._startValue != value) { this._startValue = value; this.raisePropertyChanged('startValue'); } }, get_endValue: function() { return this._endValue; }, set_endValue: function(value) { value = this._getFloat(value); if(this._endValue != value) { this._endValue = value; this.raisePropertyChanged('endValue'); } } } $AA.InterpolatedAnimation.registerClass('Sys.Extended.UI.Animation.InterpolatedAnimation', $AA.PropertyAnimation); $AA.registerAnimation('interpolated', $AA.InterpolatedAnimation); $AA.ColorAnimation = function(target, duration, fps, property, propertyKey, startValue, endValue) { // The ColorAnimation transitions the value of the property between // two colors (although it does ignore the alpha channel). The colors must be 7-character hex strings // (like #246ACF). // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "property" - property of the target element to set when animating. The default value is 'style'. // "propertyKey" - optional key of the property to be set (which indicates the value property[propertyKey], // like style['backgroundColor']). Note that for the style property, the key must be in a JavaScript friendly format (i.e. backgroundColor instead of background-color). // "startValue" - start of the range of colors // "endValue" - end of the range of colors $AA.ColorAnimation.initializeBase(this, [target, duration, fps, property, propertyKey, startValue, endValue]); // Cached start/end RBG triplets this._start = null; this._end = null; // Flags indicating whether each dimension of color will be interpolated this._interpolateRed = false; this._interpolateGreen = false; this._interpolateBlue = false; } $AA.ColorAnimation.prototype = { onStart: function() { // Determine which dimensions of color will be animated $AA.ColorAnimation.callBaseMethod(this, 'onStart'); this._start = $AA.ColorAnimation.getRGB(this.get_startValue()); this._end = $AA.ColorAnimation.getRGB(this.get_endValue()); this._interpolateRed = (this._start.Red != this._end.Red); this._interpolateGreen = (this._start.Green != this._end.Green); this._interpolateBlue = (this._start.Blue != this._end.Blue); }, getAnimatedValue: function(percentage) { // Get the interpolated color values // "percentage" - percentage of the animation already complete // returns current color formatted as a 7-character hex string (like #246ACF). var r = this._start.Red; var g = this._start.Green; var b = this._start.Blue; if(this._interpolateRed) r = Math.round(this.interpolate(r, this._end.Red, percentage)); if(this._interpolateGreen) g = Math.round(this.interpolate(g, this._end.Green, percentage)); if(this._interpolateBlue) b = Math.round(this.interpolate(b, this._end.Blue, percentage)); return $AA.ColorAnimation.toColor(r, g, b); }, set_startValue: function(value) { // Starting color of the transition formatted as a 7-character hex string (like #246ACF). if(this._startValue != value) { this._startValue = value; this.raisePropertyChanged('startValue'); } }, set_endValue: function(value) { // Ending color of the transition formatted as a 7-character hex string (like #246ACF). if(this._endValue != value) { this._endValue = value; this.raisePropertyChanged('endValue'); } } } $AA.ColorAnimation.getRGB = function(color) { // Convert the color to an RGB triplet // "color" - color formatted as a 7-character hex string (like #246ACF) // returns object representing the color with Red, Green, and Blue properties. if(!color || color.length != 7) { throw String.format(Sys.Extended.UI.Resources.Animation_InvalidColor, color); } return { 'Red': parseInt(color.substr(1, 2), 16), 'Green': parseInt(color.substr(3, 2), 16), 'Blue': parseInt(color.substr(5, 2), 16) }; } $AA.ColorAnimation.toColor = function(red, green, blue) { // Convert an RBG triplet into a 7-character hex string (like #246ACF) // "red" - value of the color's red dimension // "green" - value of the color's green dimension // "blue" - value of the color's blue dimension // returns color as a 7-character hex string (like #246ACF) var r = red.toString(16); var g = green.toString(16); var b = blue.toString(16); if(r.length == 1) r = '0' + r; if(g.length == 1) g = '0' + g; if(b.length == 1) b = '0' + b; return '#' + r + g + b; } $AA.ColorAnimation.registerClass('Sys.Extended.UI.Animation.ColorAnimation', $AA.InterpolatedAnimation); $AA.registerAnimation('color', $AA.ColorAnimation); $AA.LengthAnimation = function(target, duration, fps, property, propertyKey, startValue, endValue, unit) { // The LengthAnimation is identical to // except it adds a unit to the value before assigning it to the property. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "property" - property of the target element to set when animating. The default value is 'style'. // "propertyKey" - optional key of the property to be set (which indicates the value property[propertyKey], // like style['backgroundColor']). Note that for the style property, the key must be in a JavaScript friendly // format (i.e. backgroundColor instead of background-color). // "startValue" - start of the range of values // "endValue" - end of the range of values // "unit" - unit of the interpolated values. The default value is 'px'. $AA.LengthAnimation.initializeBase(this, [target, duration, fps, property, propertyKey, startValue, endValue]); // Unit of length (which defaults to px) this._unit = (unit != null) ? unit : 'px'; } $AA.LengthAnimation.prototype = { getAnimatedValue: function(percentage) { // Get the interpolated length value // "percentage" - percentage of the animation already complete // returns interpolated length var value = this.interpolate(this.get_startValue(), this.get_endValue(), percentage); return Math.round(value) + this._unit; }, get_unit: function() { // Unit of the interpolated values. The default value is 'px'. return this._unit; }, set_unit: function(value) { if(this._unit != value) { this._unit = value; this.raisePropertyChanged('unit'); } } } $AA.LengthAnimation.registerClass('Sys.Extended.UI.Animation.LengthAnimation', $AA.InterpolatedAnimation); $AA.registerAnimation('length', $AA.LengthAnimation); $AA.MoveAnimation = function(target, duration, fps, horizontal, vertical, relative, unit) { // The MoveAnimation is used to move the target element. If the // relative flag is set to true, then it treats the horizontal // and vertical properties as offsets to move the element. If the relative // flag is false, then it will treat the horizontal and vertical // properties as coordinates on the page where the target element should be moved. It is // important to note that the target must be positioned (i.e. absolutely) so // that settings its top/left style attributes will change its location. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "horizontal" - if relative is true, this is the offset to move horizontally. Otherwise this is the x // coordinate on the page where the target should be moved. // "vertical" - if relative is true, this is the offset to move vertically. Otherwise this is the y // coordinate on the page where the target should be moved. // "relative" - true if we are moving relative to the current position, false if we are moving absolutely // "unit" - length unit for the size of the target. The default value is 'px'. $AA.MoveAnimation.initializeBase(this, [target, duration, fps, null]); // Distance to move horizontally and vertically this._horizontal = horizontal ? horizontal : 0; this._vertical = vertical ? vertical : 0; this._relative = (relative === undefined) ? true : relative; // Length animations representing the movememnts this._horizontalAnimation = new $AA.LengthAnimation(target, duration, fps, 'style', 'left', null, null, unit); this._verticalAnimation = new $AA.LengthAnimation(target, duration, fps, 'style', 'top', null, null, unit); this.add(this._verticalAnimation); this.add(this._horizontalAnimation); } $AA.MoveAnimation.prototype = { onStart: function() { // Use the target's current position as the starting point for the animation $AA.MoveAnimation.callBaseMethod(this, 'onStart'); // Set the start and end values of the animations by getting // the element's current position and applying the offsets var element = this.get_target(); this._horizontalAnimation.set_startValue(element.offsetLeft); this._horizontalAnimation.set_endValue(this._relative ? element.offsetLeft + this._horizontal : this._horizontal); this._verticalAnimation.set_startValue(element.offsetTop); this._verticalAnimation.set_endValue(this._relative ? element.offsetTop + this._vertical : this._vertical); }, get_horizontal: function() { // If relative is true, this is the offset to move horizontally. Otherwise this is the x // coordinate on the page where the target should be moved. return this._horizontal; }, set_horizontal: function(value) { value = this._getFloat(value); if(this._horizontal != value) { this._horizontal = value; this.raisePropertyChanged('horizontal'); } }, get_vertical: function() { // If relative is true, this is the offset to move vertically. Otherwise this is the y // coordinate on the page where the target should be moved. return this._vertical; }, set_vertical: function(value) { value = this._getFloat(value); if(this._vertical != value) { this._vertical = value; this.raisePropertyChanged('vertical'); } }, get_relative: function() { // true if we are moving relative to the current position, false if we are moving absolutely return this._relative; }, set_relative: function(value) { value = this._getBoolean(value); if(this._relative != value) { this._relative = value; this.raisePropertyChanged('relative'); } }, get_unit: function() { // Length unit for the size of the target. The default value is 'px'. this._horizontalAnimation.get_unit(); }, set_unit: function(value) { var unit = this._horizontalAnimation.get_unit(); if(unit != value) { this._horizontalAnimation.set_unit(value); this._verticalAnimation.set_unit(value); this.raisePropertyChanged('unit'); } } } $AA.MoveAnimation.registerClass('Sys.Extended.UI.Animation.MoveAnimation', $AA.ParallelAnimation); $AA.registerAnimation('move', $AA.MoveAnimation); $AA.ResizeAnimation = function(target, duration, fps, width, height, unit) { // The ResizeAnimation changes the size of the target from its // current value to the specified width and height. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "width" - new width of the target // "height" - new height of the target // "unit" - length unit for the size of the target. The default value is 'px'. $AA.ResizeAnimation.initializeBase(this, [target, duration, fps, null]); // New size of the element this._width = width; this._height = height; // Animations to set the size across both dimensions this._horizontalAnimation = new $AA.LengthAnimation(target, duration, fps, 'style', 'width', null, null, unit); this._verticalAnimation = new $AA.LengthAnimation(target, duration, fps, 'style', 'height', null, null, unit); this.add(this._horizontalAnimation); this.add(this._verticalAnimation); } $AA.ResizeAnimation.prototype = { onStart: function() { // Use the target's current size as the starting point for the animation $AA.ResizeAnimation.callBaseMethod(this, 'onStart'); // Set the start and end values of the animations by getting // the element's current width and height var element = this.get_target(); this._horizontalAnimation.set_startValue(element.offsetWidth); this._verticalAnimation.set_startValue(element.offsetHeight); this._horizontalAnimation.set_endValue((this._width !== null && this._width !== undefined) ? this._width : element.offsetWidth); this._verticalAnimation.set_endValue((this._height !== null && this._height !== undefined) ? this._height : element.offsetHeight); }, get_width: function() { return this._width; }, set_width: function(value) { value = this._getFloat(value); if(this._width != value) { this._width = value; this.raisePropertyChanged('width'); } }, get_height: function() { return this._height; }, set_height: function(value) { value = this._getFloat(value); if(this._height != value) { this._height = value; this.raisePropertyChanged('height'); } }, get_unit: function() { // Length unit for the size of the target. The default value is 'px'. this._horizontalAnimation.get_unit(); }, set_unit: function(value) { var unit = this._horizontalAnimation.get_unit(); if(unit != value) { this._horizontalAnimation.set_unit(value); this._verticalAnimation.set_unit(value); this.raisePropertyChanged('unit'); } } } $AA.ResizeAnimation.registerClass('Sys.Extended.UI.Animation.ResizeAnimation', $AA.ParallelAnimation); $AA.registerAnimation('resize', $AA.ResizeAnimation); $AA.ScaleAnimation = function(target, duration, fps, scaleFactor, unit, center, scaleFont, fontUnit) { // The ScaleAnimation scales the size of the target element by the given scaleFactor // (i.e. a scaleFactor of .5 will shrink it in half and a scaleFactor of 2.0 // will double it). If scaleFont is true, the size of the font will also scale with the element. If // center is true, then the element's center will not move as it is scaled. It is important to note that // the target must be positioned (i.e. absolutely) so that setting its top/left properties will change // its location in order for center to have an effect. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 1. // "fps" - number of steps per second. The default is 25. // "scaleFactor" - the amount to scale the target (a scaleFactor of .5 will // shrink it in half and a scaleFactor of 2.0 will double it). The default value is // 1, which does no scaling. // "unit" - length unit for the size of the target. The default value is 'px'. // "center" - whether the target should stay centered while scaling // "scaleFont" - whether the font should be scaled along with the size // "fontUnit" - unit of the font, which is only used if scaleFont is true. // The default value is 'pt'. $AA.ScaleAnimation.initializeBase(this, [target, duration, fps]); // Percentage to scale this._scaleFactor = (scaleFactor !== undefined) ? scaleFactor : 1; this._unit = (unit !== undefined) ? unit : 'px'; // Center the content while scaling this._center = center; // Scale the font size as well this._scaleFont = scaleFont; this._fontUnit = (fontUnit !== undefined) ? fontUnit : 'pt'; // Initial values this._element = null; this._initialHeight = null; this._initialWidth = null; this._initialTop = null; this._initialLeft = null; this._initialFontSize = null; } $AA.ScaleAnimation.prototype = { getAnimatedValue: function(percentage) { // Get the amount to scale the target // "percentage" - percentage of the animation already complete // returns percentage to scale the target return this.interpolate(1.0, this._scaleFactor, percentage); }, onStart: function() { // Cache the initial size because it will be used to determine how much to scale the element at each step of the animation $AA.ScaleAnimation.callBaseMethod(this, 'onStart'); this._element = this.get_target(); if(this._element) { this._initialHeight = this._element.offsetHeight; this._initialWidth = this._element.offsetWidth; if(this._center) { this._initialTop = this._element.offsetTop; this._initialLeft = this._element.offsetLeft; } if(this._scaleFont) { // Note: we're assuming this is in the same units as fontUnit this._initialFontSize = parseFloat( $common.getCurrentStyle(this._element, 'fontSize')); } } }, setValue: function(scale) { // Scale the target by the given percentage // "scale" - percentage to scale the target if(this._element) { var width = Math.round(this._initialWidth * scale); var height = Math.round(this._initialHeight * scale); this._element.style.width = width + this._unit; this._element.style.height = height + this._unit; if(this._center) { this._element.style.top = (this._initialTop + Math.round((this._initialHeight - height) / 2)) + this._unit; this._element.style.left = (this._initialLeft + Math.round((this._initialWidth - width) / 2)) + this._unit; } if(this._scaleFont) { var size = this._initialFontSize * scale; if(this._fontUnit == 'px' || this._fontUnit == 'pt') { size = Math.round(size); } this._element.style.fontSize = size + this._fontUnit; } } }, onEnd: function() { // Wipe the cached values after the animation completes this._element = null; this._initialHeight = null; this._initialWidth = null; this._initialTop = null; this._initialLeft = null; this._initialFontSize = null; $AA.ScaleAnimation.callBaseMethod(this, 'onEnd'); }, get_scaleFactor: function() { // The amount to scale the target (a scaleFactor of .5 will // shrink it in half and a scaleFactor of 2.0 will double it). The default value is // 1, which does no scaling. return this._scaleFactor; }, set_scaleFactor: function(value) { value = this._getFloat(value); if(this._scaleFactor != value) { this._scaleFactor = value; this.raisePropertyChanged('scaleFactor'); } }, get_unit: function() { // Length unit for the size of the target. The default value is 'px'. return this._unit; }, set_unit: function(value) { if(this._unit != value) { this._unit = value; this.raisePropertyChanged('unit'); } }, get_center: function() { // Whether the target should stay centered while scaling return this._center; }, set_center: function(value) { value = this._getBoolean(value); if(this._center != value) { this._center = value; this.raisePropertyChanged('center'); } }, get_scaleFont: function() { // Whether the font should be scaled along with the size return this._scaleFont; }, set_scaleFont: function(value) { value = this._getBoolean(value); if(this._scaleFont != value) { this._scaleFont = value; this.raisePropertyChanged('scaleFont'); } }, get_fontUnit: function() { // Unit of the font, which is only used if scaleFont is true. // The default value is 'pt'. return this._fontUnit; }, set_fontUnit: function(value) { if(this._fontUnit != value) { this._fontUnit = value; this.raisePropertyChanged('fontUnit'); } } } $AA.ScaleAnimation.registerClass('Sys.Extended.UI.Animation.ScaleAnimation', $AA.Animation); $AA.registerAnimation('scale', $AA.ScaleAnimation); $AA.Action = function(target, duration, fps) { // Action is a base class for all "non-animating" animations that provides empty implementations // for abstract methods and adds a doAction method that will be called to perform the action's // operation. While regular animations perform an operation in a sequence of small steps spread over an interval, // the actions perform a single operation instantaneously. By default, all actions have a duration // of zero. The actions are very useful for defining complex animations. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 0. // "fps" - number of steps per second. The default is 25. $AA.Action.initializeBase(this, [target, duration, fps]); // Set the duration to 0 if it wasn't specified if(duration === undefined) { this.set_duration(0); } } $AA.Action.prototype = { onEnd: function() { // Call the doAction method when the animation completes this.doAction(); $AA.Action.callBaseMethod(this, 'onEnd'); }, doAction: function() { // The doAction method must be implemented by all actions throw Error.notImplemented(); }, getAnimatedValue: function() { // Empty implementation of required abstract method }, setValue: function() { // Empty implementation of required abstract method } } $AA.Action.registerClass('Sys.Extended.UI.Animation.Action', $AA.Animation); $AA.registerAnimation('action', $AA.Action); $AA.EnableAction = function(target, duration, fps, enabled) { // The EnableAction changes whether or not the target is disabled. // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 0. // "fps" - number of steps per second. The default is 25. // "enabled" - whether or not the target is disabled. The default value is true. $AA.EnableAction.initializeBase(this, [target, duration, fps]); // Whether to enable or disable this._enabled = (enabled !== undefined) ? enabled : true; } $AA.EnableAction.prototype = { doAction: function() { // Set the enabled property of the target var element = this.get_target(); if(element) { element.disabled = !this._enabled; } }, get_enabled: function() { // Whether or not the target is disabled. The default value is true. return this._enabled; }, set_enabled: function(value) { value = this._getBoolean(value); if(this._enabled != value) { this._enabled = value; this.raisePropertyChanged('enabled'); } } } $AA.EnableAction.registerClass('Sys.Extended.UI.Animation.EnableAction', $AA.Action); $AA.registerAnimation('enableAction', $AA.EnableAction); $AA.HideAction = function(target, duration, fps, visible) { // The HideAction simply hides the target from view // (by setting its style's display attribute to 'none') // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 0. // "fps" - number of steps per second. The default is 25. // "visible" - true to show the target, false to hide it. The default value is false. $AA.HideAction.initializeBase(this, [target, duration, fps]); this._visible = visible; } $AA.HideAction.prototype = { doAction: function() { // Hide the target var element = this.get_target(); if(element) { $common.setVisible(element, this._visible); } }, get_visible: function() { // True to show the target, false to hide it. The default value is false. return this._visible; }, set_visible: function(value) { if(this._visible != value) { this._visible = value; this.raisePropertyChanged('visible'); } } } $AA.HideAction.registerClass('Sys.Extended.UI.Animation.HideAction', $AA.Action); $AA.registerAnimation('hideAction', $AA.HideAction); $AA.StyleAction = function(target, duration, fps, attribute, value) { // The StyleAction is used to set a particular attribute of the target's style // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 0. // "fps" - number of steps per second. The default is 25. // "attribute" - style attribute to set (this must be in a JavaScript friendly format, i.e. backgroundColor // instead of background-color) // "value" - value to set the attribute $AA.StyleAction.initializeBase(this, [target, duration, fps]); // Style attribute (like "backgroundColor" or "borderWidth" this._attribute = attribute; // Value to assign to the style attribute this._value = value; } $AA.StyleAction.prototype = { doAction: function() { // Assign the value to the style's attribute var element = this.get_target(); if(element) { element.style[this._attribute] = this._value; } }, get_attribute: function() { // Style attribute to set (this must be in a JavaScript friendly format, i.e. backgroundColor // instead of background-color) return this._attribute; }, set_attribute: function(value) { if(this._attribute != value) { this._attribute = value; this.raisePropertyChanged('attribute'); } }, get_value: function() { return this._value; }, set_value: function(value) { if(this._value != value) { this._value = value; this.raisePropertyChanged('value'); } } } $AA.StyleAction.registerClass('Sys.Extended.UI.Animation.StyleAction', $AA.Action); $AA.registerAnimation('styleAction', $AA.StyleAction); $AA.OpacityAction = function(target, duration, fps, opacity) { // OpacityAction allows you to set the opacity of the target // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 0. // "fps" - number of steps per second. The default is 25. // "opacity" - opacity to set the target $AA.OpacityAction.initializeBase(this, [target, duration, fps]); // Opacity this._opacity = opacity; } $AA.OpacityAction.prototype = { doAction: function() { // Set the opacity var element = this.get_target(); if(element) { $common.setElementOpacity(element, this._opacity); } }, get_opacity: function() { return this._opacity; }, set_opacity: function(value) { value = this._getFloat(value); if(this._opacity != value) { this._opacity = value; this.raisePropertyChanged('opacity'); } } } $AA.OpacityAction.registerClass('Sys.Extended.UI.Animation.OpacityAction', $AA.Action); $AA.registerAnimation('opacityAction', $AA.OpacityAction); $AA.ScriptAction = function(target, duration, fps, script) { // The ScriptAction is used to execute arbitrary JavaScript // "target" - target of the animation // "duration" - length of the animation in seconds. The default is 0. // "fps" - number of steps per second. The default is 25. // "script" - javaScript to execute $AA.ScriptAction.initializeBase(this, [target, duration, fps]); // Script to execute this._script = script; } $AA.ScriptAction.prototype = { doAction: function() { try { eval(this._script); } catch(ex) { } }, get_script: function() { return this._script; }, set_script: function(value) { if(this._script != value) { this._script = value; this.raisePropertyChanged('script'); } } } $AA.ScriptAction.registerClass('Sys.Extended.UI.Animation.ScriptAction', $AA.Action); $AA.registerAnimation('scriptAction', $AA.ScriptAction); // globals var $AA;