📄 animations.js
字号:
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
/// <reference name="MicrosoftAjax.debug.js" />
/// <reference name="MicrosoftAjaxTimer.debug.js" />
/// <reference name="MicrosoftAjaxWebForms.debug.js" />
/// <reference path="../Compat/Timer/Timer.js" />
/// <reference path="../Common/Common.js" />
Type.registerNamespace('AjaxControlToolkit.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
var $AA = AjaxControlToolkit.Animation;
$AA.registerAnimation = function(name, type) {
/// <summary>
/// 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 <code>play</code> 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.
/// </summary>
/// <param name="name" type="String">
/// 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.).
/// </param>
/// <param name="type" type="Type">
/// The type of the new animation must inherit from <see cref="AjaxControlToolkit.Animation.Animation" />.
/// </param>
/// <returns />
// Make sure the type inherits from AjaxControlToolkit.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
// AjaxControlToolkit.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() {
/// <summary>
/// Create an animation, play it immediately, and dispose it when finished.
/// </summary>
/// <param parameterArray="true" elementType="Object">
/// The play function takes the same parameters as the type's constructor
/// </param>
/// <returns />
// 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() {
/// <summary>
/// Dispose the animation after playing
/// </summary>
/// <returns />
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, AjaxControlToolkit.Resources.Animation_InvalidBaseType);
}
}
$AA.buildAnimation = function(json, defaultTarget) {
/// <summary>
/// The <code>buildAnimation</code> function is used to turn a JSON animation description
/// into an actual animation object that can be played.
/// </summary>
/// <param name="json" type="String" mayBeNull="true">
/// JSON description of the animation in the format expected by createAnimation
/// </param>
/// <param name="defaultTarget" type="Sys.UI.DomElement" mayBeNull="true" domElement="true">
/// Target of the animation if none is specified in the JSON description. The semantics of
/// target assignment are provided in more detail in createAnimation.
/// </param>
/// <returns type="AjaxControlToolkit.Animation.Animation" mayBeNull="true">
/// Animation created from the JSON description
/// </returns>
// 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) {
/// <summary>
/// The <code>createAnimation</code> function builds a new
/// <see cref="AjaxControlToolkit.Animation.Animation" /> instance from an object
/// that describes it.
/// </summary>
/// <param name="obj" type="Object">
/// The object provides a description of the animation to be be generated in
/// a very specific format. It has two special properties: <code>AnimationName</code>
/// and <code>AnimationChildren</code>. The <code>AnimationName</code> is required
/// and used to find the type of animation to create (this name should map to
/// one of the animation names supplied to <code>registerAnimation</code>). The
/// <code>AnimationChildren</code> property supplies an optional array for
/// animations that use child animations (such as
/// <see cref="AjaxControlToolkit.Animation.ParallelAnimation" /> and
/// <see cref="AjaxControlToolkit.Animation.SequenceAnimation" />). The elements of
/// the <code>AnimationChildren</code> array are valid
/// <see cref="AjaxControlToolkit.Animation.Animation" /> objects that meet these same
/// requirements. In order for an animation to support child animations, it must
/// derive from the <see cref="AjaxControlToolkit.Animation.ParentAnimation" /> class
/// which provides common methods like <code>add</code>, <code>clear</code>, etc. The
/// remaining properties of the object are used to set parameters specific to the type
/// of animation being created (e.g. <code>duration</code>, <code>minimumOpacity</code>,
/// <code>startValue</code>, 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.
/// </param>
/// <param name="defaultTarget" type="Sys.UI.DomElement" mayBeNull="true" domElement="true">
/// The function also takes a <code>defaultTarget</code> parameter that is used as the
/// target of the animation if the object does not specify one. This parameter should be
/// an instance of <see cref="Sys.UI.DomElement" /> and not just the name of an element.
/// </param>
/// <returns type="AjaxControlToolkit.Animation.Animation">
/// <see cref="AjaxControlToolkit.Animation.Animation" /> created from the description
/// </returns>
/// <remarks>
/// Exceptions are thrown when the <code>AnimationName</code> cannot be found. Also,
/// any exceptions raised by setting properties or providing properties with invalid
/// names will only be raised when debugging.
/// </remarks>
// 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', AjaxControlToolkit.Resources.Animation_MissingAnimationName);
}
var type = $AA.__animations[obj.AnimationName.toLowerCase()];
if (!type) {
throw Error.argument('type', String.format(AjaxControlToolkit.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(AjaxControlToolkit.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(AjaxControlToolkit.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(AjaxControlToolkit.Resources.Animation_NoPropertyFound, property));
}
}
}
return animation;
}
// In the Xml comments for each of the animations below, there is a special <animation /> tag
// that describes how the animation is referenced from a generic XML animation description
$AA.Animation = function(target, duration, fps) {
/// <summary>
/// <code>Animation</code> 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 <code>getAnimatedValue</code>
/// and <code>setValue</code>.
/// </summary>
/// <param name="target" type="Sys.UI.DomElement" mayBeNull="true" optional="true" domElement="true">
/// Target of the animation
/// </param>
/// <param name="duration" type="Number" mayBeNull="true" optional="true">
/// Length of the animation in seconds. The default is 1.
/// </param>
/// <param name="fps" type="Number" mayBeNull="true" optional="true" integer="true">
/// Number of steps per second. The default is 25.
/// </param>
/// <field name="DynamicProperties" type="Object">
/// 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -