]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/animation/animation.js
Release 6.2.0beta4
[Github/sugarcrm.git] / include / javascript / yui / build / animation / animation.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.8.0r4
6 */
7 (function() {
8
9 var Y = YAHOO.util;
10
11 /*
12 Copyright (c) 2006, Yahoo! Inc. All rights reserved.
13 Code licensed under the BSD License:
14 http://developer.yahoo.net/yui/license.txt
15 */
16
17 /**
18  * The animation module provides allows effects to be added to HTMLElements.
19  * @module animation
20  * @requires yahoo, event, dom
21  */
22
23 /**
24  *
25  * Base animation class that provides the interface for building animated effects.
26  * <p>Usage: var myAnim = new YAHOO.util.Anim(el, { width: { from: 10, to: 100 } }, 1, YAHOO.util.Easing.easeOut);</p>
27  * @class Anim
28  * @namespace YAHOO.util
29  * @requires YAHOO.util.AnimMgr
30  * @requires YAHOO.util.Easing
31  * @requires YAHOO.util.Dom
32  * @requires YAHOO.util.Event
33  * @requires YAHOO.util.CustomEvent
34  * @constructor
35  * @param {String | HTMLElement} el Reference to the element that will be animated
36  * @param {Object} attributes The attribute(s) to be animated.  
37  * Each attribute is an object with at minimum a "to" or "by" member defined.  
38  * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").  
39  * All attribute names use camelCase.
40  * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
41  * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
42  */
43
44 var Anim = function(el, attributes, duration, method) {
45     if (!el) {
46     }
47     this.init(el, attributes, duration, method); 
48 };
49
50 Anim.NAME = 'Anim';
51
52 Anim.prototype = {
53     /**
54      * Provides a readable name for the Anim instance.
55      * @method toString
56      * @return {String}
57      */
58     toString: function() {
59         var el = this.getEl() || {};
60         var id = el.id || el.tagName;
61         return (this.constructor.NAME + ': ' + id);
62     },
63     
64     patterns: { // cached for performance
65         noNegatives:        /width|height|opacity|padding/i, // keep at zero or above
66         offsetAttribute:  /^((width|height)|(top|left))$/, // use offsetValue as default
67         defaultUnit:        /width|height|top$|bottom$|left$|right$/i, // use 'px' by default
68         offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset
69     },
70     
71     /**
72      * Returns the value computed by the animation's "method".
73      * @method doMethod
74      * @param {String} attr The name of the attribute.
75      * @param {Number} start The value this attribute should start from for this animation.
76      * @param {Number} end  The value this attribute should end at for this animation.
77      * @return {Number} The Value to be applied to the attribute.
78      */
79     doMethod: function(attr, start, end) {
80         return this.method(this.currentFrame, start, end - start, this.totalFrames);
81     },
82     
83     /**
84      * Applies a value to an attribute.
85      * @method setAttribute
86      * @param {String} attr The name of the attribute.
87      * @param {Number} val The value to be applied to the attribute.
88      * @param {String} unit The unit ('px', '%', etc.) of the value.
89      */
90     setAttribute: function(attr, val, unit) {
91         var el = this.getEl();
92         if ( this.patterns.noNegatives.test(attr) ) {
93             val = (val > 0) ? val : 0;
94         }
95
96         if (attr in el && !('style' in el && attr in el.style)) {
97             el[attr] = val;
98         } else {
99             Y.Dom.setStyle(el, attr, val + unit);
100         }
101     },                        
102     
103     /**
104      * Returns current value of the attribute.
105      * @method getAttribute
106      * @param {String} attr The name of the attribute.
107      * @return {Number} val The current value of the attribute.
108      */
109     getAttribute: function(attr) {
110         var el = this.getEl();
111         var val = Y.Dom.getStyle(el, attr);
112
113         if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
114             return parseFloat(val);
115         }
116         
117         var a = this.patterns.offsetAttribute.exec(attr) || [];
118         var pos = !!( a[3] ); // top or left
119         var box = !!( a[2] ); // width or height
120         
121         if ('style' in el) {
122             // use offsets for width/height and abs pos top/left
123             if ( box || (Y.Dom.getStyle(el, 'position') == 'absolute' && pos) ) {
124                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
125             } else { // default to zero for other 'auto'
126                 val = 0;
127             }
128         } else if (attr in el) {
129             val = el[attr];
130         }
131
132         return val;
133     },
134     
135     /**
136      * Returns the unit to use when none is supplied.
137      * @method getDefaultUnit
138      * @param {attr} attr The name of the attribute.
139      * @return {String} The default unit to be used.
140      */
141     getDefaultUnit: function(attr) {
142          if ( this.patterns.defaultUnit.test(attr) ) {
143             return 'px';
144          }
145          
146          return '';
147     },
148         
149     /**
150      * Sets the actual values to be used during the animation.  Should only be needed for subclass use.
151      * @method setRuntimeAttribute
152      * @param {Object} attr The attribute object
153      * @private 
154      */
155     setRuntimeAttribute: function(attr) {
156         var start;
157         var end;
158         var attributes = this.attributes;
159
160         this.runtimeAttributes[attr] = {};
161         
162         var isset = function(prop) {
163             return (typeof prop !== 'undefined');
164         };
165         
166         if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) {
167             return false; // note return; nothing to animate to
168         }
169         
170         start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
171
172         // To beats by, per SMIL 2.1 spec
173         if ( isset(attributes[attr]['to']) ) {
174             end = attributes[attr]['to'];
175         } else if ( isset(attributes[attr]['by']) ) {
176             if (start.constructor == Array) {
177                 end = [];
178                 for (var i = 0, len = start.length; i < len; ++i) {
179                     end[i] = start[i] + attributes[attr]['by'][i] * 1; // times 1 to cast "by" 
180                 }
181             } else {
182                 end = start + attributes[attr]['by'] * 1;
183             }
184         }
185         
186         this.runtimeAttributes[attr].start = start;
187         this.runtimeAttributes[attr].end = end;
188
189         // set units if needed
190         this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ?
191                 attributes[attr]['unit'] : this.getDefaultUnit(attr);
192         return true;
193     },
194
195     /**
196      * Constructor for Anim instance.
197      * @method init
198      * @param {String | HTMLElement} el Reference to the element that will be animated
199      * @param {Object} attributes The attribute(s) to be animated.  
200      * Each attribute is an object with at minimum a "to" or "by" member defined.  
201      * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").  
202      * All attribute names use camelCase.
203      * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
204      * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
205      */ 
206     init: function(el, attributes, duration, method) {
207         /**
208          * Whether or not the animation is running.
209          * @property isAnimated
210          * @private
211          * @type Boolean
212          */
213         var isAnimated = false;
214         
215         /**
216          * A Date object that is created when the animation begins.
217          * @property startTime
218          * @private
219          * @type Date
220          */
221         var startTime = null;
222         
223         /**
224          * The number of frames this animation was able to execute.
225          * @property actualFrames
226          * @private
227          * @type Int
228          */
229         var actualFrames = 0; 
230
231         /**
232          * The element to be animated.
233          * @property el
234          * @private
235          * @type HTMLElement
236          */
237         el = Y.Dom.get(el);
238         
239         /**
240          * The collection of attributes to be animated.  
241          * Each attribute must have at least a "to" or "by" defined in order to animate.  
242          * If "to" is supplied, the animation will end with the attribute at that value.  
243          * If "by" is supplied, the animation will end at that value plus its starting value. 
244          * If both are supplied, "to" is used, and "by" is ignored. 
245          * Optional additional member include "from" (the value the attribute should start animating from, defaults to current value), and "unit" (the units to apply to the values).
246          * @property attributes
247          * @type Object
248          */
249         this.attributes = attributes || {};
250         
251         /**
252          * The length of the animation.  Defaults to "1" (second).
253          * @property duration
254          * @type Number
255          */
256         this.duration = !YAHOO.lang.isUndefined(duration) ? duration : 1;
257         
258         /**
259          * The method that will provide values to the attribute(s) during the animation. 
260          * Defaults to "YAHOO.util.Easing.easeNone".
261          * @property method
262          * @type Function
263          */
264         this.method = method || Y.Easing.easeNone;
265
266         /**
267          * Whether or not the duration should be treated as seconds.
268          * Defaults to true.
269          * @property useSeconds
270          * @type Boolean
271          */
272         this.useSeconds = true; // default to seconds
273         
274         /**
275          * The location of the current animation on the timeline.
276          * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
277          * @property currentFrame
278          * @type Int
279          */
280         this.currentFrame = 0;
281         
282         /**
283          * The total number of frames to be executed.
284          * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
285          * @property totalFrames
286          * @type Int
287          */
288         this.totalFrames = Y.AnimMgr.fps;
289         
290         /**
291          * Changes the animated element
292          * @method setEl
293          */
294         this.setEl = function(element) {
295             el = Y.Dom.get(element);
296         };
297         
298         /**
299          * Returns a reference to the animated element.
300          * @method getEl
301          * @return {HTMLElement}
302          */
303         this.getEl = function() { return el; };
304         
305         /**
306          * Checks whether the element is currently animated.
307          * @method isAnimated
308          * @return {Boolean} current value of isAnimated.     
309          */
310         this.isAnimated = function() {
311             return isAnimated;
312         };
313         
314         /**
315          * Returns the animation start time.
316          * @method getStartTime
317          * @return {Date} current value of startTime.      
318          */
319         this.getStartTime = function() {
320             return startTime;
321         };        
322         
323         this.runtimeAttributes = {};
324         
325         
326         
327         /**
328          * Starts the animation by registering it with the animation manager. 
329          * @method animate  
330          */
331         this.animate = function() {
332             if ( this.isAnimated() ) {
333                 return false;
334             }
335             
336             this.currentFrame = 0;
337             
338             this.totalFrames = ( this.useSeconds ) ? Math.ceil(Y.AnimMgr.fps * this.duration) : this.duration;
339     
340             if (this.duration === 0 && this.useSeconds) { // jump to last frame if zero second duration 
341                 this.totalFrames = 1; 
342             }
343             Y.AnimMgr.registerElement(this);
344             return true;
345         };
346           
347         /**
348          * Stops the animation.  Normally called by AnimMgr when animation completes.
349          * @method stop
350          * @param {Boolean} finish (optional) If true, animation will jump to final frame.
351          */ 
352         this.stop = function(finish) {
353             if (!this.isAnimated()) { // nothing to stop
354                 return false;
355             }
356
357             if (finish) {
358                  this.currentFrame = this.totalFrames;
359                  this._onTween.fire();
360             }
361             Y.AnimMgr.stop(this);
362         };
363         
364         var onStart = function() {            
365             this.onStart.fire();
366             
367             this.runtimeAttributes = {};
368             for (var attr in this.attributes) {
369                 this.setRuntimeAttribute(attr);
370             }
371             
372             isAnimated = true;
373             actualFrames = 0;
374             startTime = new Date(); 
375         };
376         
377         /**
378          * Feeds the starting and ending values for each animated attribute to doMethod once per frame, then applies the resulting value to the attribute(s).
379          * @private
380          */
381          
382         var onTween = function() {
383             var data = {
384                 duration: new Date() - this.getStartTime(),
385                 currentFrame: this.currentFrame
386             };
387             
388             data.toString = function() {
389                 return (
390                     'duration: ' + data.duration +
391                     ', currentFrame: ' + data.currentFrame
392                 );
393             };
394             
395             this.onTween.fire(data);
396             
397             var runtimeAttributes = this.runtimeAttributes;
398             
399             for (var attr in runtimeAttributes) {
400                 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit); 
401             }
402             
403             actualFrames += 1;
404         };
405         
406         var onComplete = function() {
407             var actual_duration = (new Date() - startTime) / 1000 ;
408             
409             var data = {
410                 duration: actual_duration,
411                 frames: actualFrames,
412                 fps: actualFrames / actual_duration
413             };
414             
415             data.toString = function() {
416                 return (
417                     'duration: ' + data.duration +
418                     ', frames: ' + data.frames +
419                     ', fps: ' + data.fps
420                 );
421             };
422             
423             isAnimated = false;
424             actualFrames = 0;
425             this.onComplete.fire(data);
426         };
427         
428         /**
429          * Custom event that fires after onStart, useful in subclassing
430          * @private
431          */    
432         this._onStart = new Y.CustomEvent('_start', this, true);
433
434         /**
435          * Custom event that fires when animation begins
436          * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction)
437          * @event onStart
438          */    
439         this.onStart = new Y.CustomEvent('start', this);
440         
441         /**
442          * Custom event that fires between each frame
443          * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction)
444          * @event onTween
445          */
446         this.onTween = new Y.CustomEvent('tween', this);
447         
448         /**
449          * Custom event that fires after onTween
450          * @private
451          */
452         this._onTween = new Y.CustomEvent('_tween', this, true);
453         
454         /**
455          * Custom event that fires when animation ends
456          * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction)
457          * @event onComplete
458          */
459         this.onComplete = new Y.CustomEvent('complete', this);
460         /**
461          * Custom event that fires after onComplete
462          * @private
463          */
464         this._onComplete = new Y.CustomEvent('_complete', this, true);
465
466         this._onStart.subscribe(onStart);
467         this._onTween.subscribe(onTween);
468         this._onComplete.subscribe(onComplete);
469     }
470 };
471
472     Y.Anim = Anim;
473 })();
474 /**
475  * Handles animation queueing and threading.
476  * Used by Anim and subclasses.
477  * @class AnimMgr
478  * @namespace YAHOO.util
479  */
480 YAHOO.util.AnimMgr = new function() {
481     /** 
482      * Reference to the animation Interval.
483      * @property thread
484      * @private
485      * @type Int
486      */
487     var thread = null;
488     
489     /** 
490      * The current queue of registered animation objects.
491      * @property queue
492      * @private
493      * @type Array
494      */    
495     var queue = [];
496
497     /** 
498      * The number of active animations.
499      * @property tweenCount
500      * @private
501      * @type Int
502      */        
503     var tweenCount = 0;
504
505     /** 
506      * Base frame rate (frames per second). 
507      * Arbitrarily high for better x-browser calibration (slower browsers drop more frames).
508      * @property fps
509      * @type Int
510      * 
511      */
512     this.fps = 1000;
513
514     /** 
515      * Interval delay in milliseconds, defaults to fastest possible.
516      * @property delay
517      * @type Int
518      * 
519      */
520     this.delay = 1;
521
522     /**
523      * Adds an animation instance to the animation queue.
524      * All animation instances must be registered in order to animate.
525      * @method registerElement
526      * @param {object} tween The Anim instance to be be registered
527      */
528     this.registerElement = function(tween) {
529         queue[queue.length] = tween;
530         tweenCount += 1;
531         tween._onStart.fire();
532         this.start();
533     };
534     
535     /**
536      * removes an animation instance from the animation queue.
537      * All animation instances must be registered in order to animate.
538      * @method unRegister
539      * @param {object} tween The Anim instance to be be registered
540      * @param {Int} index The index of the Anim instance
541      * @private
542      */
543     this.unRegister = function(tween, index) {
544         index = index || getIndex(tween);
545         if (!tween.isAnimated() || index === -1) {
546             return false;
547         }
548         
549         tween._onComplete.fire();
550         queue.splice(index, 1);
551
552         tweenCount -= 1;
553         if (tweenCount <= 0) {
554             this.stop();
555         }
556
557         return true;
558     };
559     
560     /**
561      * Starts the animation thread.
562         * Only one thread can run at a time.
563      * @method start
564      */    
565     this.start = function() {
566         if (thread === null) {
567             thread = setInterval(this.run, this.delay);
568         }
569     };
570
571     /**
572      * Stops the animation thread or a specific animation instance.
573      * @method stop
574      * @param {object} tween A specific Anim instance to stop (optional)
575      * If no instance given, Manager stops thread and all animations.
576      */    
577     this.stop = function(tween) {
578         if (!tween) {
579             clearInterval(thread);
580             
581             for (var i = 0, len = queue.length; i < len; ++i) {
582                 this.unRegister(queue[0], 0);  
583             }
584
585             queue = [];
586             thread = null;
587             tweenCount = 0;
588         }
589         else {
590             this.unRegister(tween);
591         }
592     };
593     
594     /**
595      * Called per Interval to handle each animation frame.
596      * @method run
597      */    
598     this.run = function() {
599         for (var i = 0, len = queue.length; i < len; ++i) {
600             var tween = queue[i];
601             if ( !tween || !tween.isAnimated() ) { continue; }
602
603             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
604             {
605                 tween.currentFrame += 1;
606                 
607                 if (tween.useSeconds) {
608                     correctFrame(tween);
609                 }
610                 tween._onTween.fire();          
611             }
612             else { YAHOO.util.AnimMgr.stop(tween, i); }
613         }
614     };
615     
616     var getIndex = function(anim) {
617         for (var i = 0, len = queue.length; i < len; ++i) {
618             if (queue[i] === anim) {
619                 return i; // note return;
620             }
621         }
622         return -1;
623     };
624     
625     /**
626      * On the fly frame correction to keep animation on time.
627      * @method correctFrame
628      * @private
629      * @param {Object} tween The Anim instance being corrected.
630      */
631     var correctFrame = function(tween) {
632         var frames = tween.totalFrames;
633         var frame = tween.currentFrame;
634         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
635         var elapsed = (new Date() - tween.getStartTime());
636         var tweak = 0;
637         
638         if (elapsed < tween.duration * 1000) { // check if falling behind
639             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
640         } else { // went over duration, so jump to end
641             tweak = frames - (frame + 1); 
642         }
643         if (tweak > 0 && isFinite(tweak)) { // adjust if needed
644             if (tween.currentFrame + tweak >= frames) {// dont go past last frame
645                 tweak = frames - (frame + 1);
646             }
647             
648             tween.currentFrame += tweak;      
649         }
650     };
651     this._queue = queue;
652     this._getIndex = getIndex;
653 };
654 /**
655  * Used to calculate Bezier splines for any number of control points.
656  * @class Bezier
657  * @namespace YAHOO.util
658  *
659  */
660 YAHOO.util.Bezier = new function() {
661     /**
662      * Get the current position of the animated element based on t.
663      * Each point is an array of "x" and "y" values (0 = x, 1 = y)
664      * At least 2 points are required (start and end).
665      * First point is start. Last point is end.
666      * Additional control points are optional.     
667      * @method getPosition
668      * @param {Array} points An array containing Bezier points
669      * @param {Number} t A number between 0 and 1 which is the basis for determining current position
670      * @return {Array} An array containing int x and y member data
671      */
672     this.getPosition = function(points, t) {  
673         var n = points.length;
674         var tmp = [];
675
676         for (var i = 0; i < n; ++i){
677             tmp[i] = [points[i][0], points[i][1]]; // save input
678         }
679         
680         for (var j = 1; j < n; ++j) {
681             for (i = 0; i < n - j; ++i) {
682                 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
683                 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1]; 
684             }
685         }
686     
687         return [ tmp[0][0], tmp[0][1] ]; 
688     
689     };
690 };
691 (function() {
692 /**
693  * Anim subclass for color transitions.
694  * <p>Usage: <code>var myAnim = new Y.ColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.Easing.easeOut);</code> Color values can be specified with either 112233, #112233, 
695  * [255,255,255], or rgb(255,255,255)</p>
696  * @class ColorAnim
697  * @namespace YAHOO.util
698  * @requires YAHOO.util.Anim
699  * @requires YAHOO.util.AnimMgr
700  * @requires YAHOO.util.Easing
701  * @requires YAHOO.util.Bezier
702  * @requires YAHOO.util.Dom
703  * @requires YAHOO.util.Event
704  * @constructor
705  * @extends YAHOO.util.Anim
706  * @param {HTMLElement | String} el Reference to the element that will be animated
707  * @param {Object} attributes The attribute(s) to be animated.
708  * Each attribute is an object with at minimum a "to" or "by" member defined.
709  * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
710  * All attribute names use camelCase.
711  * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
712  * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
713  */
714     var ColorAnim = function(el, attributes, duration,  method) {
715         ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
716     };
717     
718     ColorAnim.NAME = 'ColorAnim';
719
720     ColorAnim.DEFAULT_BGCOLOR = '#fff';
721     // shorthand
722     var Y = YAHOO.util;
723     YAHOO.extend(ColorAnim, Y.Anim);
724
725     var superclass = ColorAnim.superclass;
726     var proto = ColorAnim.prototype;
727     
728     proto.patterns.color = /color$/i;
729     proto.patterns.rgb            = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
730     proto.patterns.hex            = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
731     proto.patterns.hex3          = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
732     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/; // need rgba for safari
733     
734     /**
735      * Attempts to parse the given string and return a 3-tuple.
736      * @method parseColor
737      * @param {String} s The string to parse.
738      * @return {Array} The 3-tuple of rgb values.
739      */
740     proto.parseColor = function(s) {
741         if (s.length == 3) { return s; }
742     
743         var c = this.patterns.hex.exec(s);
744         if (c && c.length == 4) {
745             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
746         }
747     
748         c = this.patterns.rgb.exec(s);
749         if (c && c.length == 4) {
750             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
751         }
752     
753         c = this.patterns.hex3.exec(s);
754         if (c && c.length == 4) {
755             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
756         }
757         
758         return null;
759     };
760
761     proto.getAttribute = function(attr) {
762         var el = this.getEl();
763         if (this.patterns.color.test(attr) ) {
764             var val = YAHOO.util.Dom.getStyle(el, attr);
765             
766             var that = this;
767             if (this.patterns.transparent.test(val)) { // bgcolor default
768                 var parent = YAHOO.util.Dom.getAncestorBy(el, function(node) {
769                     return !that.patterns.transparent.test(val);
770                 });
771
772                 if (parent) {
773                     val = Y.Dom.getStyle(parent, attr);
774                 } else {
775                     val = ColorAnim.DEFAULT_BGCOLOR;
776                 }
777             }
778         } else {
779             val = superclass.getAttribute.call(this, attr);
780         }
781
782         return val;
783     };
784     
785     proto.doMethod = function(attr, start, end) {
786         var val;
787     
788         if ( this.patterns.color.test(attr) ) {
789             val = [];
790             for (var i = 0, len = start.length; i < len; ++i) {
791                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
792             }
793             
794             val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')';
795         }
796         else {
797             val = superclass.doMethod.call(this, attr, start, end);
798         }
799
800         return val;
801     };
802
803     proto.setRuntimeAttribute = function(attr) {
804         superclass.setRuntimeAttribute.call(this, attr);
805         
806         if ( this.patterns.color.test(attr) ) {
807             var attributes = this.attributes;
808             var start = this.parseColor(this.runtimeAttributes[attr].start);
809             var end = this.parseColor(this.runtimeAttributes[attr].end);
810             // fix colors if going "by"
811             if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) {
812                 end = this.parseColor(attributes[attr].by);
813             
814                 for (var i = 0, len = start.length; i < len; ++i) {
815                     end[i] = start[i] + end[i];
816                 }
817             }
818             
819             this.runtimeAttributes[attr].start = start;
820             this.runtimeAttributes[attr].end = end;
821         }
822     };
823
824     Y.ColorAnim = ColorAnim;
825 })();
826 /*!
827 TERMS OF USE - EASING EQUATIONS
828 Open source under the BSD License.
829 Copyright 2001 Robert Penner All rights reserved.
830
831 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
832
833  * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
834  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
835  * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
836
837 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
838 */
839
840 /**
841  * Singleton that determines how an animation proceeds from start to end.
842  * @class Easing
843  * @namespace YAHOO.util
844 */
845
846 YAHOO.util.Easing = {
847
848     /**
849      * Uniform speed between points.
850      * @method easeNone
851      * @param {Number} t Time value used to compute current value
852      * @param {Number} b Starting value
853      * @param {Number} c Delta between start and end values
854      * @param {Number} d Total length of animation
855      * @return {Number} The computed value for the current animation frame
856      */
857     easeNone: function (t, b, c, d) {
858         return c*t/d + b;
859     },
860     
861     /**
862      * Begins slowly and accelerates towards end.
863      * @method easeIn
864      * @param {Number} t Time value used to compute current value
865      * @param {Number} b Starting value
866      * @param {Number} c Delta between start and end values
867      * @param {Number} d Total length of animation
868      * @return {Number} The computed value for the current animation frame
869      */
870     easeIn: function (t, b, c, d) {
871         return c*(t/=d)*t + b;
872     },
873
874     /**
875      * Begins quickly and decelerates towards end.
876      * @method easeOut
877      * @param {Number} t Time value used to compute current value
878      * @param {Number} b Starting value
879      * @param {Number} c Delta between start and end values
880      * @param {Number} d Total length of animation
881      * @return {Number} The computed value for the current animation frame
882      */
883     easeOut: function (t, b, c, d) {
884         return -c *(t/=d)*(t-2) + b;
885     },
886     
887     /**
888      * Begins slowly and decelerates towards end.
889      * @method easeBoth
890      * @param {Number} t Time value used to compute current value
891      * @param {Number} b Starting value
892      * @param {Number} c Delta between start and end values
893      * @param {Number} d Total length of animation
894      * @return {Number} The computed value for the current animation frame
895      */
896     easeBoth: function (t, b, c, d) {
897         if ((t/=d/2) < 1) {
898             return c/2*t*t + b;
899         }
900         
901         return -c/2 * ((--t)*(t-2) - 1) + b;
902     },
903     
904     /**
905      * Begins slowly and accelerates towards end.
906      * @method easeInStrong
907      * @param {Number} t Time value used to compute current value
908      * @param {Number} b Starting value
909      * @param {Number} c Delta between start and end values
910      * @param {Number} d Total length of animation
911      * @return {Number} The computed value for the current animation frame
912      */
913     easeInStrong: function (t, b, c, d) {
914         return c*(t/=d)*t*t*t + b;
915     },
916     
917     /**
918      * Begins quickly and decelerates towards end.
919      * @method easeOutStrong
920      * @param {Number} t Time value used to compute current value
921      * @param {Number} b Starting value
922      * @param {Number} c Delta between start and end values
923      * @param {Number} d Total length of animation
924      * @return {Number} The computed value for the current animation frame
925      */
926     easeOutStrong: function (t, b, c, d) {
927         return -c * ((t=t/d-1)*t*t*t - 1) + b;
928     },
929     
930     /**
931      * Begins slowly and decelerates towards end.
932      * @method easeBothStrong
933      * @param {Number} t Time value used to compute current value
934      * @param {Number} b Starting value
935      * @param {Number} c Delta between start and end values
936      * @param {Number} d Total length of animation
937      * @return {Number} The computed value for the current animation frame
938      */
939     easeBothStrong: function (t, b, c, d) {
940         if ((t/=d/2) < 1) {
941             return c/2*t*t*t*t + b;
942         }
943         
944         return -c/2 * ((t-=2)*t*t*t - 2) + b;
945     },
946
947     /**
948      * Snap in elastic effect.
949      * @method elasticIn
950      * @param {Number} t Time value used to compute current value
951      * @param {Number} b Starting value
952      * @param {Number} c Delta between start and end values
953      * @param {Number} d Total length of animation
954      * @param {Number} a Amplitude (optional)
955      * @param {Number} p Period (optional)
956      * @return {Number} The computed value for the current animation frame
957      */
958
959     elasticIn: function (t, b, c, d, a, p) {
960         if (t == 0) {
961             return b;
962         }
963         if ( (t /= d) == 1 ) {
964             return b+c;
965         }
966         if (!p) {
967             p=d*.3;
968         }
969         
970         if (!a || a < Math.abs(c)) {
971             a = c; 
972             var s = p/4;
973         }
974         else {
975             var s = p/(2*Math.PI) * Math.asin (c/a);
976         }
977         
978         return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
979     },
980
981     /**
982      * Snap out elastic effect.
983      * @method elasticOut
984      * @param {Number} t Time value used to compute current value
985      * @param {Number} b Starting value
986      * @param {Number} c Delta between start and end values
987      * @param {Number} d Total length of animation
988      * @param {Number} a Amplitude (optional)
989      * @param {Number} p Period (optional)
990      * @return {Number} The computed value for the current animation frame
991      */
992     elasticOut: function (t, b, c, d, a, p) {
993         if (t == 0) {
994             return b;
995         }
996         if ( (t /= d) == 1 ) {
997             return b+c;
998         }
999         if (!p) {
1000             p=d*.3;
1001         }
1002         
1003         if (!a || a < Math.abs(c)) {
1004             a = c;
1005             var s = p / 4;
1006         }
1007         else {
1008             var s = p/(2*Math.PI) * Math.asin (c/a);
1009         }
1010         
1011         return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
1012     },
1013     
1014     /**
1015      * Snap both elastic effect.
1016      * @method elasticBoth
1017      * @param {Number} t Time value used to compute current value
1018      * @param {Number} b Starting value
1019      * @param {Number} c Delta between start and end values
1020      * @param {Number} d Total length of animation
1021      * @param {Number} a Amplitude (optional)
1022      * @param {Number} p Period (optional)
1023      * @return {Number} The computed value for the current animation frame
1024      */
1025     elasticBoth: function (t, b, c, d, a, p) {
1026         if (t == 0) {
1027             return b;
1028         }
1029         
1030         if ( (t /= d/2) == 2 ) {
1031             return b+c;
1032         }
1033         
1034         if (!p) {
1035             p = d*(.3*1.5);
1036         }
1037         
1038         if ( !a || a < Math.abs(c) ) {
1039             a = c; 
1040             var s = p/4;
1041         }
1042         else {
1043             var s = p/(2*Math.PI) * Math.asin (c/a);
1044         }
1045         
1046         if (t < 1) {
1047             return -.5*(a*Math.pow(2,10*(t-=1)) * 
1048                     Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
1049         }
1050         return a*Math.pow(2,-10*(t-=1)) * 
1051                 Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
1052     },
1053
1054
1055     /**
1056      * Backtracks slightly, then reverses direction and moves to end.
1057      * @method backIn
1058      * @param {Number} t Time value used to compute current value
1059      * @param {Number} b Starting value
1060      * @param {Number} c Delta between start and end values
1061      * @param {Number} d Total length of animation
1062      * @param {Number} s Overshoot (optional)
1063      * @return {Number} The computed value for the current animation frame
1064      */
1065     backIn: function (t, b, c, d, s) {
1066         if (typeof s == 'undefined') {
1067             s = 1.70158;
1068         }
1069         return c*(t/=d)*t*((s+1)*t - s) + b;
1070     },
1071
1072     /**
1073      * Overshoots end, then reverses and comes back to end.
1074      * @method backOut
1075      * @param {Number} t Time value used to compute current value
1076      * @param {Number} b Starting value
1077      * @param {Number} c Delta between start and end values
1078      * @param {Number} d Total length of animation
1079      * @param {Number} s Overshoot (optional)
1080      * @return {Number} The computed value for the current animation frame
1081      */
1082     backOut: function (t, b, c, d, s) {
1083         if (typeof s == 'undefined') {
1084             s = 1.70158;
1085         }
1086         return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
1087     },
1088     
1089     /**
1090      * Backtracks slightly, then reverses direction, overshoots end, 
1091      * then reverses and comes back to end.
1092      * @method backBoth
1093      * @param {Number} t Time value used to compute current value
1094      * @param {Number} b Starting value
1095      * @param {Number} c Delta between start and end values
1096      * @param {Number} d Total length of animation
1097      * @param {Number} s Overshoot (optional)
1098      * @return {Number} The computed value for the current animation frame
1099      */
1100     backBoth: function (t, b, c, d, s) {
1101         if (typeof s == 'undefined') {
1102             s = 1.70158; 
1103         }
1104         
1105         if ((t /= d/2 ) < 1) {
1106             return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
1107         }
1108         return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
1109     },
1110
1111     /**
1112      * Bounce off of start.
1113      * @method bounceIn
1114      * @param {Number} t Time value used to compute current value
1115      * @param {Number} b Starting value
1116      * @param {Number} c Delta between start and end values
1117      * @param {Number} d Total length of animation
1118      * @return {Number} The computed value for the current animation frame
1119      */
1120     bounceIn: function (t, b, c, d) {
1121         return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b;
1122     },
1123     
1124     /**
1125      * Bounces off end.
1126      * @method bounceOut
1127      * @param {Number} t Time value used to compute current value
1128      * @param {Number} b Starting value
1129      * @param {Number} c Delta between start and end values
1130      * @param {Number} d Total length of animation
1131      * @return {Number} The computed value for the current animation frame
1132      */
1133     bounceOut: function (t, b, c, d) {
1134         if ((t/=d) < (1/2.75)) {
1135                 return c*(7.5625*t*t) + b;
1136         } else if (t < (2/2.75)) {
1137                 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
1138         } else if (t < (2.5/2.75)) {
1139                 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
1140         }
1141         return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
1142     },
1143     
1144     /**
1145      * Bounces off start and end.
1146      * @method bounceBoth
1147      * @param {Number} t Time value used to compute current value
1148      * @param {Number} b Starting value
1149      * @param {Number} c Delta between start and end values
1150      * @param {Number} d Total length of animation
1151      * @return {Number} The computed value for the current animation frame
1152      */
1153     bounceBoth: function (t, b, c, d) {
1154         if (t < d/2) {
1155             return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b;
1156         }
1157         return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
1158     }
1159 };
1160
1161 (function() {
1162 /**
1163  * Anim subclass for moving elements along a path defined by the "points" 
1164  * member of "attributes".  All "points" are arrays with x, y coordinates.
1165  * <p>Usage: <code>var myAnim = new YAHOO.util.Motion(el, { points: { to: [800, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1166  * @class Motion
1167  * @namespace YAHOO.util
1168  * @requires YAHOO.util.Anim
1169  * @requires YAHOO.util.AnimMgr
1170  * @requires YAHOO.util.Easing
1171  * @requires YAHOO.util.Bezier
1172  * @requires YAHOO.util.Dom
1173  * @requires YAHOO.util.Event
1174  * @requires YAHOO.util.CustomEvent 
1175  * @constructor
1176  * @extends YAHOO.util.ColorAnim
1177  * @param {String | HTMLElement} el Reference to the element that will be animated
1178  * @param {Object} attributes The attribute(s) to be animated.  
1179  * Each attribute is an object with at minimum a "to" or "by" member defined.  
1180  * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").  
1181  * All attribute names use camelCase.
1182  * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1183  * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
1184  */
1185     var Motion = function(el, attributes, duration,  method) {
1186         if (el) { // dont break existing subclasses not using YAHOO.extend
1187             Motion.superclass.constructor.call(this, el, attributes, duration, method);
1188         }
1189     };
1190
1191
1192     Motion.NAME = 'Motion';
1193
1194     // shorthand
1195     var Y = YAHOO.util;
1196     YAHOO.extend(Motion, Y.ColorAnim);
1197     
1198     var superclass = Motion.superclass;
1199     var proto = Motion.prototype;
1200
1201     proto.patterns.points = /^points$/i;
1202     
1203     proto.setAttribute = function(attr, val, unit) {
1204         if (  this.patterns.points.test(attr) ) {
1205             unit = unit || 'px';
1206             superclass.setAttribute.call(this, 'left', val[0], unit);
1207             superclass.setAttribute.call(this, 'top', val[1], unit);
1208         } else {
1209             superclass.setAttribute.call(this, attr, val, unit);
1210         }
1211     };
1212
1213     proto.getAttribute = function(attr) {
1214         if (  this.patterns.points.test(attr) ) {
1215             var val = [
1216                 superclass.getAttribute.call(this, 'left'),
1217                 superclass.getAttribute.call(this, 'top')
1218             ];
1219         } else {
1220             val = superclass.getAttribute.call(this, attr);
1221         }
1222
1223         return val;
1224     };
1225
1226     proto.doMethod = function(attr, start, end) {
1227         var val = null;
1228
1229         if ( this.patterns.points.test(attr) ) {
1230             var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;                             
1231             val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
1232         } else {
1233             val = superclass.doMethod.call(this, attr, start, end);
1234         }
1235         return val;
1236     };
1237
1238     proto.setRuntimeAttribute = function(attr) {
1239         if ( this.patterns.points.test(attr) ) {
1240             var el = this.getEl();
1241             var attributes = this.attributes;
1242             var start;
1243             var control = attributes['points']['control'] || [];
1244             var end;
1245             var i, len;
1246             
1247             if (control.length > 0 && !(control[0] instanceof Array) ) { // could be single point or array of points
1248                 control = [control];
1249             } else { // break reference to attributes.points.control
1250                 var tmp = []; 
1251                 for (i = 0, len = control.length; i< len; ++i) {
1252                     tmp[i] = control[i];
1253                 }
1254                 control = tmp;
1255             }
1256
1257             if (Y.Dom.getStyle(el, 'position') == 'static') { // default to relative
1258                 Y.Dom.setStyle(el, 'position', 'relative');
1259             }
1260     
1261             if ( isset(attributes['points']['from']) ) {
1262                 Y.Dom.setXY(el, attributes['points']['from']); // set position to from point
1263             } 
1264             else { Y.Dom.setXY( el, Y.Dom.getXY(el) ); } // set it to current position
1265             
1266             start = this.getAttribute('points'); // get actual top & left
1267             
1268             // TO beats BY, per SMIL 2.1 spec
1269             if ( isset(attributes['points']['to']) ) {
1270                 end = translateValues.call(this, attributes['points']['to'], start);
1271                 
1272                 var pageXY = Y.Dom.getXY(this.getEl());
1273                 for (i = 0, len = control.length; i < len; ++i) {
1274                     control[i] = translateValues.call(this, control[i], start);
1275                 }
1276
1277                 
1278             } else if ( isset(attributes['points']['by']) ) {
1279                 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
1280                 
1281                 for (i = 0, len = control.length; i < len; ++i) {
1282                     control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
1283                 }
1284             }
1285
1286             this.runtimeAttributes[attr] = [start];
1287             
1288             if (control.length > 0) {
1289                 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control); 
1290             }
1291
1292             this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
1293         }
1294         else {
1295             superclass.setRuntimeAttribute.call(this, attr);
1296         }
1297     };
1298     
1299     var translateValues = function(val, start) {
1300         var pageXY = Y.Dom.getXY(this.getEl());
1301         val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
1302
1303         return val; 
1304     };
1305     
1306     var isset = function(prop) {
1307         return (typeof prop !== 'undefined');
1308     };
1309
1310     Y.Motion = Motion;
1311 })();
1312 (function() {
1313 /**
1314  * Anim subclass for scrolling elements to a position defined by the "scroll"
1315  * member of "attributes".  All "scroll" members are arrays with x, y scroll positions.
1316  * <p>Usage: <code>var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1317  * @class Scroll
1318  * @namespace YAHOO.util
1319  * @requires YAHOO.util.Anim
1320  * @requires YAHOO.util.AnimMgr
1321  * @requires YAHOO.util.Easing
1322  * @requires YAHOO.util.Bezier
1323  * @requires YAHOO.util.Dom
1324  * @requires YAHOO.util.Event
1325  * @requires YAHOO.util.CustomEvent 
1326  * @extends YAHOO.util.ColorAnim
1327  * @constructor
1328  * @param {String or HTMLElement} el Reference to the element that will be animated
1329  * @param {Object} attributes The attribute(s) to be animated.  
1330  * Each attribute is an object with at minimum a "to" or "by" member defined.  
1331  * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").  
1332  * All attribute names use camelCase.
1333  * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1334  * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
1335  */
1336     var Scroll = function(el, attributes, duration,  method) {
1337         if (el) { // dont break existing subclasses not using YAHOO.extend
1338             Scroll.superclass.constructor.call(this, el, attributes, duration, method);
1339         }
1340     };
1341
1342     Scroll.NAME = 'Scroll';
1343
1344     // shorthand
1345     var Y = YAHOO.util;
1346     YAHOO.extend(Scroll, Y.ColorAnim);
1347     
1348     var superclass = Scroll.superclass;
1349     var proto = Scroll.prototype;
1350
1351     proto.doMethod = function(attr, start, end) {
1352         var val = null;
1353     
1354         if (attr == 'scroll') {
1355             val = [
1356                 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
1357                 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
1358             ];
1359             
1360         } else {
1361             val = superclass.doMethod.call(this, attr, start, end);
1362         }
1363         return val;
1364     };
1365
1366     proto.getAttribute = function(attr) {
1367         var val = null;
1368         var el = this.getEl();
1369         
1370         if (attr == 'scroll') {
1371             val = [ el.scrollLeft, el.scrollTop ];
1372         } else {
1373             val = superclass.getAttribute.call(this, attr);
1374         }
1375         
1376         return val;
1377     };
1378
1379     proto.setAttribute = function(attr, val, unit) {
1380         var el = this.getEl();
1381         
1382         if (attr == 'scroll') {
1383             el.scrollLeft = val[0];
1384             el.scrollTop = val[1];
1385         } else {
1386             superclass.setAttribute.call(this, attr, val, unit);
1387         }
1388     };
1389
1390     Y.Scroll = Scroll;
1391 })();
1392 YAHOO.register("animation", YAHOO.util.Anim, {version: "2.8.0r4", build: "2449"});