]> git.wh0rd.org - tt-rss.git/blobdiff - lib/dojo/_base/fx.js
build custom layer of Dojo to speed up loading of tt-rss (refs #293)
[tt-rss.git] / lib / dojo / _base / fx.js
index 1c589402e7ed5633e8a7406e2774325a6377254e..21243c1c9a1fe5e386ee48758e8f523537089b53 100644 (file)
 */
 
 
-if(!dojo._hasResource["dojo._base.fx"]){
-dojo._hasResource["dojo._base.fx"]=true;
+if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.fx"] = true;
 dojo.provide("dojo._base.fx");
 dojo.require("dojo._base.Color");
 dojo.require("dojo._base.connect");
 dojo.require("dojo._base.lang");
 dojo.require("dojo._base.html");
+
+/*
+       Animation loosely package based on Dan Pupius' work, contributed under CLA:
+               http://pupius.co.uk/js/Toolkit.Drawing.js
+*/
 (function(){
-var d=dojo;
-var _1=d._mixin;
-dojo._Line=function(_2,_3){
-this.start=_2;
-this.end=_3;
-};
-dojo._Line.prototype.getValue=function(n){
-return ((this.end-this.start)*n)+this.start;
-};
-dojo.Animation=function(_4){
-_1(this,_4);
-if(d.isArray(this.curve)){
-this.curve=new d._Line(this.curve[0],this.curve[1]);
-}
-};
-d._Animation=d.Animation;
-d.extend(dojo.Animation,{duration:350,repeat:0,rate:20,_percent:0,_startRepeatCount:0,_getStep:function(){
-var _5=this._percent,_6=this.easing;
-return _6?_6(_5):_5;
-},_fire:function(_7,_8){
-var a=_8||[];
-if(this[_7]){
-if(d.config.debugAtAllCosts){
-this[_7].apply(this,a);
-}else{
-try{
-this[_7].apply(this,a);
-}
-catch(e){
-console.error("exception in animation handler for:",_7);
-console.error(e);
-}
-}
-}
-return this;
-},play:function(_9,_a){
-var _b=this;
-if(_b._delayTimer){
-_b._clearTimer();
-}
-if(_a){
-_b._stopTimer();
-_b._active=_b._paused=false;
-_b._percent=0;
-}else{
-if(_b._active&&!_b._paused){
-return _b;
-}
-}
-_b._fire("beforeBegin",[_b.node]);
-var de=_9||_b.delay,_c=dojo.hitch(_b,"_play",_a);
-if(de>0){
-_b._delayTimer=setTimeout(_c,de);
-return _b;
-}
-_c();
-return _b;
-},_play:function(_d){
-var _e=this;
-if(_e._delayTimer){
-_e._clearTimer();
-}
-_e._startTime=new Date().valueOf();
-if(_e._paused){
-_e._startTime-=_e.duration*_e._percent;
-}
-_e._active=true;
-_e._paused=false;
-var _f=_e.curve.getValue(_e._getStep());
-if(!_e._percent){
-if(!_e._startRepeatCount){
-_e._startRepeatCount=_e.repeat;
-}
-_e._fire("onBegin",[_f]);
-}
-_e._fire("onPlay",[_f]);
-_e._cycle();
-return _e;
-},pause:function(){
-var _10=this;
-if(_10._delayTimer){
-_10._clearTimer();
-}
-_10._stopTimer();
-if(!_10._active){
-return _10;
-}
-_10._paused=true;
-_10._fire("onPause",[_10.curve.getValue(_10._getStep())]);
-return _10;
-},gotoPercent:function(_11,_12){
-var _13=this;
-_13._stopTimer();
-_13._active=_13._paused=true;
-_13._percent=_11;
-if(_12){
-_13.play();
-}
-return _13;
-},stop:function(_14){
-var _15=this;
-if(_15._delayTimer){
-_15._clearTimer();
-}
-if(!_15._timer){
-return _15;
-}
-_15._stopTimer();
-if(_14){
-_15._percent=1;
-}
-_15._fire("onStop",[_15.curve.getValue(_15._getStep())]);
-_15._active=_15._paused=false;
-return _15;
-},status:function(){
-if(this._active){
-return this._paused?"paused":"playing";
-}
-return "stopped";
-},_cycle:function(){
-var _16=this;
-if(_16._active){
-var _17=new Date().valueOf();
-var _18=(_17-_16._startTime)/(_16.duration);
-if(_18>=1){
-_18=1;
-}
-_16._percent=_18;
-if(_16.easing){
-_18=_16.easing(_18);
-}
-_16._fire("onAnimate",[_16.curve.getValue(_18)]);
-if(_16._percent<1){
-_16._startTimer();
-}else{
-_16._active=false;
-if(_16.repeat>0){
-_16.repeat--;
-_16.play(null,true);
-}else{
-if(_16.repeat==-1){
-_16.play(null,true);
-}else{
-if(_16._startRepeatCount){
-_16.repeat=_16._startRepeatCount;
-_16._startRepeatCount=0;
-}
-}
-}
-_16._percent=0;
-_16._fire("onEnd",[_16.node]);
-!_16.repeat&&_16._stopTimer();
-}
-}
-return _16;
-},_clearTimer:function(){
-clearTimeout(this._delayTimer);
-delete this._delayTimer;
-}});
-var ctr=0,_19=null,_1a={run:function(){
-}};
-d.extend(d.Animation,{_startTimer:function(){
-if(!this._timer){
-this._timer=d.connect(_1a,"run",this,"_cycle");
-ctr++;
-}
-if(!_19){
-_19=setInterval(d.hitch(_1a,"run"),this.rate);
-}
-},_stopTimer:function(){
-if(this._timer){
-d.disconnect(this._timer);
-this._timer=null;
-ctr--;
-}
-if(ctr<=0){
-clearInterval(_19);
-_19=null;
-ctr=0;
-}
-}});
-var _1b=d.isIE?function(_1c){
-var ns=_1c.style;
-if(!ns.width.length&&d.style(_1c,"width")=="auto"){
-ns.width="auto";
-}
-}:function(){
-};
-dojo._fade=function(_1d){
-_1d.node=d.byId(_1d.node);
-var _1e=_1({properties:{}},_1d),_1f=(_1e.properties.opacity={});
-_1f.start=!("start" in _1e)?function(){
-return +d.style(_1e.node,"opacity")||0;
-}:_1e.start;
-_1f.end=_1e.end;
-var _20=d.animateProperty(_1e);
-d.connect(_20,"beforeBegin",d.partial(_1b,_1e.node));
-return _20;
-};
-dojo.fadeIn=function(_21){
-return d._fade(_1({end:1},_21));
-};
-dojo.fadeOut=function(_22){
-return d._fade(_1({end:0},_22));
-};
-dojo._defaultEasing=function(n){
-return 0.5+((Math.sin((n+1.5)*Math.PI))/2);
-};
-var _23=function(_24){
-this._properties=_24;
-for(var p in _24){
-var _25=_24[p];
-if(_25.start instanceof d.Color){
-_25.tempColor=new d.Color();
-}
-}
-};
-_23.prototype.getValue=function(r){
-var ret={};
-for(var p in this._properties){
-var _26=this._properties[p],_27=_26.start;
-if(_27 instanceof d.Color){
-ret[p]=d.blendColors(_27,_26.end,r,_26.tempColor).toCss();
-}else{
-if(!d.isArray(_27)){
-ret[p]=((_26.end-_27)*r)+_27+(p!="opacity"?_26.units||"px":0);
-}
-}
-}
-return ret;
-};
-dojo.animateProperty=function(_28){
-var n=_28.node=d.byId(_28.node);
-if(!_28.easing){
-_28.easing=d._defaultEasing;
-}
-var _29=new d.Animation(_28);
-d.connect(_29,"beforeBegin",_29,function(){
-var pm={};
-for(var p in this.properties){
-if(p=="width"||p=="height"){
-this.node.display="block";
-}
-var _2a=this.properties[p];
-if(d.isFunction(_2a)){
-_2a=_2a(n);
-}
-_2a=pm[p]=_1({},(d.isObject(_2a)?_2a:{end:_2a}));
-if(d.isFunction(_2a.start)){
-_2a.start=_2a.start(n);
-}
-if(d.isFunction(_2a.end)){
-_2a.end=_2a.end(n);
-}
-var _2b=(p.toLowerCase().indexOf("color")>=0);
-function _2c(_2d,p){
-var v={height:_2d.offsetHeight,width:_2d.offsetWidth}[p];
-if(v!==undefined){
-return v;
-}
-v=d.style(_2d,p);
-return (p=="opacity")?+v:(_2b?v:parseFloat(v));
-};
-if(!("end" in _2a)){
-_2a.end=_2c(n,p);
-}else{
-if(!("start" in _2a)){
-_2a.start=_2c(n,p);
-}
-}
-if(_2b){
-_2a.start=new d.Color(_2a.start);
-_2a.end=new d.Color(_2a.end);
-}else{
-_2a.start=(p=="opacity")?+_2a.start:parseFloat(_2a.start);
-}
-}
-this.curve=new _23(pm);
-});
-d.connect(_29,"onAnimate",d.hitch(d,"style",_29.node));
-return _29;
-};
-dojo.anim=function(_2e,_2f,_30,_31,_32,_33){
-return d.animateProperty({node:_2e,duration:_30||d.Animation.prototype.duration,properties:_2f,easing:_31,onEnd:_32}).play(_33||0);
-};
+       var d = dojo;
+       var _mixin = d._mixin;
+
+       dojo._Line = function(/*int*/ start, /*int*/ end){
+               //      summary:
+               //              dojo._Line is the object used to generate values from a start value
+               //              to an end value
+               //      start: int
+               //              Beginning value for range
+               //      end: int
+               //              Ending value for range
+               this.start = start;
+               this.end = end;
+       };
+
+       dojo._Line.prototype.getValue = function(/*float*/ n){
+               //      summary: Returns the point on the line
+               //      n: a floating point number greater than 0 and less than 1
+               return ((this.end - this.start) * n) + this.start; // Decimal
+       };
+
+       dojo.Animation = function(args){
+               //      summary:
+               //              A generic animation class that fires callbacks into its handlers
+               //              object at various states.
+               //      description:
+               //              A generic animation class that fires callbacks into its handlers
+               //              object at various states. Nearly all dojo animation functions
+               //              return an instance of this method, usually without calling the
+               //              .play() method beforehand. Therefore, you will likely need to
+               //              call .play() on instances of `dojo.Animation` when one is
+               //              returned.
+               // args: Object
+               //              The 'magic argument', mixing all the properties into this
+               //              animation instance.
+
+               _mixin(this, args);
+               if(d.isArray(this.curve)){
+                       this.curve = new d._Line(this.curve[0], this.curve[1]);
+               }
+
+       };
+
+       // Alias to drop come 2.0:
+       d._Animation = d.Animation;
+
+       d.extend(dojo.Animation, {
+               // duration: Integer
+               //              The time in milliseonds the animation will take to run
+               duration: 350,
+
+       /*=====
+               // curve: dojo._Line|Array
+               //              A two element array of start and end values, or a `dojo._Line` instance to be
+               //              used in the Animation.
+               curve: null,
+
+               // easing: Function?
+               //              A Function to adjust the acceleration (or deceleration) of the progress
+               //              across a dojo._Line
+               easing: null,
+       =====*/
+
+               // repeat: Integer?
+               //              The number of times to loop the animation
+               repeat: 0,
+
+               // rate: Integer?
+               //              the time in milliseconds to wait before advancing to next frame
+               //              (used as a fps timer: 1000/rate = fps)
+               rate: 20 /* 50 fps */,
+
+       /*=====
+               // delay: Integer?
+               //              The time in milliseconds to wait before starting animation after it
+               //              has been .play()'ed
+               delay: null,
+
+               // beforeBegin: Event?
+               //              Synthetic event fired before a dojo.Animation begins playing (synchronous)
+               beforeBegin: null,
+
+               // onBegin: Event?
+               //              Synthetic event fired as a dojo.Animation begins playing (useful?)
+               onBegin: null,
+
+               // onAnimate: Event?
+               //              Synthetic event fired at each interval of a `dojo.Animation`
+               onAnimate: null,
+
+               // onEnd: Event?
+               //              Synthetic event fired after the final frame of a `dojo.Animation`
+               onEnd: null,
+
+               // onPlay: Event?
+               //              Synthetic event fired any time a `dojo.Animation` is play()'ed
+               onPlay: null,
+
+               // onPause: Event?
+               //              Synthetic event fired when a `dojo.Animation` is paused
+               onPause: null,
+
+               // onStop: Event
+               //              Synthetic event fires when a `dojo.Animation` is stopped
+               onStop: null,
+
+       =====*/
+
+               _percent: 0,
+               _startRepeatCount: 0,
+
+               _getStep: function(){
+                       var _p = this._percent,
+                               _e = this.easing
+                       ;
+                       return _e ? _e(_p) : _p;
+               },
+               _fire: function(/*Event*/ evt, /*Array?*/ args){
+                       //      summary:
+                       //              Convenience function.  Fire event "evt" and pass it the
+                       //              arguments specified in "args".
+                       //      description:
+                       //              Convenience function.  Fire event "evt" and pass it the
+                       //              arguments specified in "args".
+                       //              Fires the callback in the scope of the `dojo.Animation`
+                       //              instance.
+                       //      evt:
+                       //              The event to fire.
+                       //      args:
+                       //              The arguments to pass to the event.
+                       var a = args||[];
+                       if(this[evt]){
+                               if(d.config.debugAtAllCosts){
+                                       this[evt].apply(this, a);
+                               }else{
+                                       try{
+                                               this[evt].apply(this, a);
+                                       }catch(e){
+                                               // squelch and log because we shouldn't allow exceptions in
+                                               // synthetic event handlers to cause the internal timer to run
+                                               // amuck, potentially pegging the CPU. I'm not a fan of this
+                                               // squelch, but hopefully logging will make it clear what's
+                                               // going on
+                                               console.error("exception in animation handler for:", evt);
+                                               console.error(e);
+                                       }
+                               }
+                       }
+                       return this; // dojo.Animation
+               },
+
+               play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
+                       // summary:
+                       //              Start the animation.
+                       // delay:
+                       //              How many milliseconds to delay before starting.
+                       // gotoStart:
+                       //              If true, starts the animation from the beginning; otherwise,
+                       //              starts it from its current position.
+                       // returns: dojo.Animation
+                       //              The instance to allow chaining.
+
+                       var _t = this;
+                       if(_t._delayTimer){ _t._clearTimer(); }
+                       if(gotoStart){
+                               _t._stopTimer();
+                               _t._active = _t._paused = false;
+                               _t._percent = 0;
+                       }else if(_t._active && !_t._paused){
+                               return _t;
+                       }
+
+                       _t._fire("beforeBegin", [_t.node]);
+
+                       var de = delay || _t.delay,
+                               _p = dojo.hitch(_t, "_play", gotoStart);
+
+                       if(de > 0){
+                               _t._delayTimer = setTimeout(_p, de);
+                               return _t;
+                       }
+                       _p();
+                       return _t;
+               },
+
+               _play: function(gotoStart){
+                       var _t = this;
+                       if(_t._delayTimer){ _t._clearTimer(); }
+                       _t._startTime = new Date().valueOf();
+                       if(_t._paused){
+                               _t._startTime -= _t.duration * _t._percent;
+                       }
+
+                       _t._active = true;
+                       _t._paused = false;
+                       var value = _t.curve.getValue(_t._getStep());
+                       if(!_t._percent){
+                               if(!_t._startRepeatCount){
+                                       _t._startRepeatCount = _t.repeat;
+                               }
+                               _t._fire("onBegin", [value]);
+                       }
+
+                       _t._fire("onPlay", [value]);
+
+                       _t._cycle();
+                       return _t; // dojo.Animation
+               },
+
+               pause: function(){
+                       // summary: Pauses a running animation.
+                       var _t = this;
+                       if(_t._delayTimer){ _t._clearTimer(); }
+                       _t._stopTimer();
+                       if(!_t._active){ return _t; /*dojo.Animation*/ }
+                       _t._paused = true;
+                       _t._fire("onPause", [_t.curve.getValue(_t._getStep())]);
+                       return _t; // dojo.Animation
+               },
+
+               gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
+                       //      summary:
+                       //              Sets the progress of the animation.
+                       //      percent:
+                       //              A percentage in decimal notation (between and including 0.0 and 1.0).
+                       //      andPlay:
+                       //              If true, play the animation after setting the progress.
+                       var _t = this;
+                       _t._stopTimer();
+                       _t._active = _t._paused = true;
+                       _t._percent = percent;
+                       if(andPlay){ _t.play(); }
+                       return _t; // dojo.Animation
+               },
+
+               stop: function(/*boolean?*/ gotoEnd){
+                       // summary: Stops a running animation.
+                       // gotoEnd: If true, the animation will end.
+                       var _t = this;
+                       if(_t._delayTimer){ _t._clearTimer(); }
+                       if(!_t._timer){ return _t; /* dojo.Animation */ }
+                       _t._stopTimer();
+                       if(gotoEnd){
+                               _t._percent = 1;
+                       }
+                       _t._fire("onStop", [_t.curve.getValue(_t._getStep())]);
+                       _t._active = _t._paused = false;
+                       return _t; // dojo.Animation
+               },
+
+               status: function(){
+                       // summary:
+                       //              Returns a string token representation of the status of
+                       //              the animation, one of: "paused", "playing", "stopped"
+                       if(this._active){
+                               return this._paused ? "paused" : "playing"; // String
+                       }
+                       return "stopped"; // String
+               },
+
+               _cycle: function(){
+                       var _t = this;
+                       if(_t._active){
+                               var curr = new Date().valueOf();
+                               var step = (curr - _t._startTime) / (_t.duration);
+
+                               if(step >= 1){
+                                       step = 1;
+                               }
+                               _t._percent = step;
+
+                               // Perform easing
+                               if(_t.easing){
+                                       step = _t.easing(step);
+                               }
+
+                               _t._fire("onAnimate", [_t.curve.getValue(step)]);
+
+                               if(_t._percent < 1){
+                                       _t._startTimer();
+                               }else{
+                                       _t._active = false;
+
+                                       if(_t.repeat > 0){
+                                               _t.repeat--;
+                                               _t.play(null, true);
+                                       }else if(_t.repeat == -1){
+                                               _t.play(null, true);
+                                       }else{
+                                               if(_t._startRepeatCount){
+                                                       _t.repeat = _t._startRepeatCount;
+                                                       _t._startRepeatCount = 0;
+                                               }
+                                       }
+                                       _t._percent = 0;
+                                       _t._fire("onEnd", [_t.node]);
+                                       !_t.repeat && _t._stopTimer();
+                               }
+                       }
+                       return _t; // dojo.Animation
+               },
+
+               _clearTimer: function(){
+                       // summary: Clear the play delay timer
+                       clearTimeout(this._delayTimer);
+                       delete this._delayTimer;
+               }
+
+       });
+
+       // the local timer, stubbed into all Animation instances
+       var ctr = 0,
+               timer = null,
+               runner = {
+                       run: function(){}
+               };
+
+       d.extend(d.Animation, {
+
+               _startTimer: function(){
+                       if(!this._timer){
+                               this._timer = d.connect(runner, "run", this, "_cycle");
+                               ctr++;
+                       }
+                       if(!timer){
+                               timer = setInterval(d.hitch(runner, "run"), this.rate);
+                       }
+               },
+
+               _stopTimer: function(){
+                       if(this._timer){
+                               d.disconnect(this._timer);
+                               this._timer = null;
+                               ctr--;
+                       }
+                       if(ctr <= 0){
+                               clearInterval(timer);
+                               timer = null;
+                               ctr = 0;
+                       }
+               }
+
+       });
+
+       var _makeFadeable =
+                               d.isIE ? function(node){
+                       // only set the zoom if the "tickle" value would be the same as the
+                       // default
+                       var ns = node.style;
+                       // don't set the width to auto if it didn't already cascade that way.
+                       // We don't want to f anyones designs
+                       if(!ns.width.length && d.style(node, "width") == "auto"){
+                               ns.width = "auto";
+                       }
+               } :
+                               function(){};
+
+       dojo._fade = function(/*Object*/ args){
+               //      summary:
+               //              Returns an animation that will fade the node defined by
+               //              args.node from the start to end values passed (args.start
+               //              args.end) (end is mandatory, start is optional)
+
+               args.node = d.byId(args.node);
+               var fArgs = _mixin({ properties: {} }, args),
+                       props = (fArgs.properties.opacity = {});
+
+               props.start = !("start" in fArgs) ?
+                       function(){
+                               return +d.style(fArgs.node, "opacity")||0;
+                       } : fArgs.start;
+               props.end = fArgs.end;
+
+               var anim = d.animateProperty(fArgs);
+               d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
+
+               return anim; // dojo.Animation
+       };
+
+       /*=====
+       dojo.__FadeArgs = function(node, duration, easing){
+               //      node: DOMNode|String
+               //              The node referenced in the animation
+               //      duration: Integer?
+               //              Duration of the animation in milliseconds.
+               //      easing: Function?
+               //              An easing function.
+               this.node = node;
+               this.duration = duration;
+               this.easing = easing;
+       }
+       =====*/
+
+       dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
+               // summary:
+               //              Returns an animation that will fade node defined in 'args' from
+               //              its current opacity to fully opaque.
+               return d._fade(_mixin({ end: 1 }, args)); // dojo.Animation
+       };
+
+       dojo.fadeOut = function(/*dojo.__FadeArgs*/  args){
+               // summary:
+               //              Returns an animation that will fade node defined in 'args'
+               //              from its current opacity to fully transparent.
+               return d._fade(_mixin({ end: 0 }, args)); // dojo.Animation
+       };
+
+       dojo._defaultEasing = function(/*Decimal?*/ n){
+               // summary: The default easing function for dojo.Animation(s)
+               return 0.5 + ((Math.sin((n + 1.5) * Math.PI)) / 2);
+       };
+
+       var PropLine = function(properties){
+               // PropLine is an internal class which is used to model the values of
+               // an a group of CSS properties across an animation lifecycle. In
+               // particular, the "getValue" function handles getting interpolated
+               // values between start and end for a particular CSS value.
+               this._properties = properties;
+               for(var p in properties){
+                       var prop = properties[p];
+                       if(prop.start instanceof d.Color){
+                               // create a reusable temp color object to keep intermediate results
+                               prop.tempColor = new d.Color();
+                       }
+               }
+       };
+
+       PropLine.prototype.getValue = function(r){
+               var ret = {};
+               for(var p in this._properties){
+                       var prop = this._properties[p],
+                               start = prop.start;
+                       if(start instanceof d.Color){
+                               ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
+                       }else if(!d.isArray(start)){
+                               ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units || "px" : 0);
+                       }
+               }
+               return ret;
+       };
+
+       /*=====
+       dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
+               // Properties: Object?
+               //      A hash map of style properties to Objects describing the transition,
+               //      such as the properties of dojo._Line with an additional 'units' property
+               properties: {}
+
+               //TODOC: add event callbacks
+       });
+       =====*/
+
+       dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){
+               // summary:
+               //              Returns an animation that will transition the properties of
+               //              node defined in `args` depending how they are defined in
+               //              `args.properties`
+               //
+               // description:
+               //              `dojo.animateProperty` is the foundation of most `dojo.fx`
+               //              animations. It takes an object of "properties" corresponding to
+               //              style properties, and animates them in parallel over a set
+               //              duration.
+               //
+               // example:
+               //              A simple animation that changes the width of the specified node.
+               //      |       dojo.animateProperty({
+               //      |               node: "nodeId",
+               //      |               properties: { width: 400 },
+               //      |       }).play();
+               //              Dojo figures out the start value for the width and converts the
+               //              integer specified for the width to the more expressive but
+               //              verbose form `{ width: { end: '400', units: 'px' } }` which you
+               //              can also specify directly. Defaults to 'px' if ommitted.
+               //
+               // example:
+               //              Animate width, height, and padding over 2 seconds... the
+               //              pedantic way:
+               //      |       dojo.animateProperty({ node: node, duration:2000,
+               //      |               properties: {
+               //      |                       width: { start: '200', end: '400', units:"px" },
+               //      |                       height: { start:'200', end: '400', units:"px" },
+               //      |                       paddingTop: { start:'5', end:'50', units:"px" }
+               //      |               }
+               //      |       }).play();
+               //              Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties
+               //              are written using "mixed case", as the hyphen is illegal as an object key.
+               //
+               // example:
+               //              Plug in a different easing function and register a callback for
+               //              when the animation ends. Easing functions accept values between
+               //              zero and one and return a value on that basis. In this case, an
+               //              exponential-in curve.
+               //      |       dojo.animateProperty({
+               //      |               node: "nodeId",
+               //      |               // dojo figures out the start value
+               //      |               properties: { width: { end: 400 } },
+               //      |               easing: function(n){
+               //      |                       return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
+               //      |               },
+               //      |               onEnd: function(node){
+               //      |                       // called when the animation finishes. The animation
+               //      |                       // target is passed to this function
+               //      |               }
+               //      |       }).play(500); // delay playing half a second
+               //
+               // example:
+               //              Like all `dojo.Animation`s, animateProperty returns a handle to the
+               //              Animation instance, which fires the events common to Dojo FX. Use `dojo.connect`
+               //              to access these events outside of the Animation definiton:
+               //      |       var anim = dojo.animateProperty({
+               //      |               node:"someId",
+               //      |               properties:{
+               //      |                       width:400, height:500
+               //      |               }
+               //      |       });
+               //      |       dojo.connect(anim,"onEnd", function(){
+               //      |               console.log("animation ended");
+               //      |       });
+               //      |       // play the animation now:
+               //      |       anim.play();
+               //
+               // example:
+               //              Each property can be a function whose return value is substituted along.
+               //              Additionally, each measurement (eg: start, end) can be a function. The node
+               //              reference is passed direcly to callbacks.
+               //      |       dojo.animateProperty({
+               //      |               node:"mine",
+               //      |               properties:{
+               //      |                       height:function(node){
+               //      |                               // shrink this node by 50%
+               //      |                               return dojo.position(node).h / 2
+               //      |                       },
+               //      |                       width:{
+               //      |                               start:function(node){ return 100; },
+               //      |                               end:function(node){ return 200; }
+               //      |                       }
+               //      |               }
+               //      |       }).play();
+               //
+
+               var n = args.node = d.byId(args.node);
+               if(!args.easing){ args.easing = d._defaultEasing; }
+
+               var anim = new d.Animation(args);
+               d.connect(anim, "beforeBegin", anim, function(){
+                       var pm = {};
+                       for(var p in this.properties){
+                               // Make shallow copy of properties into pm because we overwrite
+                               // some values below. In particular if start/end are functions
+                               // we don't want to overwrite them or the functions won't be
+                               // called if the animation is reused.
+                               if(p == "width" || p == "height"){
+                                       this.node.display = "block";
+                               }
+                               var prop = this.properties[p];
+                               if(d.isFunction(prop)){
+                                       prop = prop(n);
+                               }
+                               prop = pm[p] = _mixin({}, (d.isObject(prop) ? prop: { end: prop }));
+
+                               if(d.isFunction(prop.start)){
+                                       prop.start = prop.start(n);
+                               }
+                               if(d.isFunction(prop.end)){
+                                       prop.end = prop.end(n);
+                               }
+                               var isColor = (p.toLowerCase().indexOf("color") >= 0);
+                               function getStyle(node, p){
+                                       // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
+                                       var v = { height: node.offsetHeight, width: node.offsetWidth }[p];
+                                       if(v !== undefined){ return v; }
+                                       v = d.style(node, p);
+                                       return (p == "opacity") ? +v : (isColor ? v : parseFloat(v));
+                               }
+                               if(!("end" in prop)){
+                                       prop.end = getStyle(n, p);
+                               }else if(!("start" in prop)){
+                                       prop.start = getStyle(n, p);
+                               }
+
+                               if(isColor){
+                                       prop.start = new d.Color(prop.start);
+                                       prop.end = new d.Color(prop.end);
+                               }else{
+                                       prop.start = (p == "opacity") ? +prop.start : parseFloat(prop.start);
+                               }
+                       }
+                       this.curve = new PropLine(pm);
+               });
+               d.connect(anim, "onAnimate", d.hitch(d, "style", anim.node));
+               return anim; // dojo.Animation
+       };
+
+       dojo.anim = function(   /*DOMNode|String*/      node,
+                                                       /*Object*/                      properties,
+                                                       /*Integer?*/            duration,
+                                                       /*Function?*/           easing,
+                                                       /*Function?*/           onEnd,
+                                                       /*Integer?*/            delay){
+               //      summary:
+               //              A simpler interface to `dojo.animateProperty()`, also returns
+               //              an instance of `dojo.Animation` but begins the animation
+               //              immediately, unlike nearly every other Dojo animation API.
+               //      description:
+               //              `dojo.anim` is a simpler (but somewhat less powerful) version
+               //              of `dojo.animateProperty`.  It uses defaults for many basic properties
+               //              and allows for positional parameters to be used in place of the
+               //              packed "property bag" which is used for other Dojo animation
+               //              methods.
+               //
+               //              The `dojo.Animation` object returned from `dojo.anim` will be
+               //              already playing when it is returned from this function, so
+               //              calling play() on it again is (usually) a no-op.
+               //      node:
+               //              a DOM node or the id of a node to animate CSS properties on
+               //      duration:
+               //              The number of milliseconds over which the animation
+               //              should run. Defaults to the global animation default duration
+               //              (350ms).
+               //      easing:
+               //              An easing function over which to calculate acceleration
+               //              and deceleration of the animation through its duration.
+               //              A default easing algorithm is provided, but you may
+               //              plug in any you wish. A large selection of easing algorithms
+               //              are available in `dojo.fx.easing`.
+               //      onEnd:
+               //              A function to be called when the animation finishes
+               //              running.
+               //      delay:
+               //              The number of milliseconds to delay beginning the
+               //              animation by. The default is 0.
+               //      example:
+               //              Fade out a node
+               //      |       dojo.anim("id", { opacity: 0 });
+               //      example:
+               //              Fade out a node over a full second
+               //      |       dojo.anim("id", { opacity: 0 }, 1000);
+               return d.animateProperty({ // dojo.Animation
+                       node: node,
+                       duration: duration || d.Animation.prototype.duration,
+                       properties: properties,
+                       easing: easing,
+                       onEnd: onEnd
+               }).play(delay || 0);
+       };
 })();
+
 }