PageRenderTime 124ms CodeModel.GetById 46ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/resources/org/apache/struts2/static/animation/animation-debug.js

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