]> git.wh0rd.org Git - tt-rss.git/blob - lib/dojo/_base/fx.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dojo / _base / fx.js.uncompressed.js
1 define("dojo/_base/fx", ["./kernel", "./lang", "../Evented", "./Color", "./connect", "./sniff", "../dom", "../dom-style"], function(dojo, lang, Evented, Color, connect, has, dom, style){
2         // module:
3         //              dojo/_base/fx
4         // summary:
5         //              This module defines the base dojo.fx implementation.
6         // notes:
7         //              Animation loosely package based on Dan Pupius' work, contributed under CLA; see
8         //              http://pupius.co.uk/js/Toolkit.Drawing.js
9
10         var _mixin = lang.mixin;
11
12         dojo._Line = function(/*int*/ start, /*int*/ end){
13                 //      summary:
14                 //              dojo._Line is the object used to generate values from a start value
15                 //              to an end value
16                 //      start: int
17                 //              Beginning value for range
18                 //      end: int
19                 //              Ending value for range
20                 this.start = start;
21                 this.end = end;
22         };
23
24         dojo._Line.prototype.getValue = function(/*float*/ n){
25                 //      summary: Returns the point on the line
26                 //      n: a floating point number greater than 0 and less than 1
27                 return ((this.end - this.start) * n) + this.start; // Decimal
28         };
29
30         dojo.Animation = function(args){
31                 //      summary:
32                 //              A generic animation class that fires callbacks into its handlers
33                 //              object at various states.
34                 //      description:
35                 //              A generic animation class that fires callbacks into its handlers
36                 //              object at various states. Nearly all dojo animation functions
37                 //              return an instance of this method, usually without calling the
38                 //              .play() method beforehand. Therefore, you will likely need to
39                 //              call .play() on instances of `dojo.Animation` when one is
40                 //              returned.
41                 // args: Object
42                 //              The 'magic argument', mixing all the properties into this
43                 //              animation instance.
44
45                 _mixin(this, args);
46                 if(lang.isArray(this.curve)){
47                         this.curve = new dojo._Line(this.curve[0], this.curve[1]);
48                 }
49
50         };
51         dojo.Animation.prototype = new Evented();
52         // Alias to drop come 2.0:
53         dojo._Animation = dojo.Animation;
54
55         lang.extend(dojo.Animation, {
56                 // duration: Integer
57                 //              The time in milliseonds the animation will take to run
58                 duration: 350,
59
60         /*=====
61                 // curve: dojo._Line|Array
62                 //              A two element array of start and end values, or a `dojo._Line` instance to be
63                 //              used in the Animation.
64                 curve: null,
65
66                 // easing: Function?
67                 //              A Function to adjust the acceleration (or deceleration) of the progress
68                 //              across a dojo._Line
69                 easing: null,
70         =====*/
71
72                 // repeat: Integer?
73                 //              The number of times to loop the animation
74                 repeat: 0,
75
76                 // rate: Integer?
77                 //              the time in milliseconds to wait before advancing to next frame
78                 //              (used as a fps timer: 1000/rate = fps)
79                 rate: 20 /* 50 fps */,
80
81         /*=====
82                 // delay: Integer?
83                 //              The time in milliseconds to wait before starting animation after it
84                 //              has been .play()'ed
85                 delay: null,
86
87                 // beforeBegin: Event?
88                 //              Synthetic event fired before a dojo.Animation begins playing (synchronous)
89                 beforeBegin: null,
90
91                 // onBegin: Event?
92                 //              Synthetic event fired as a dojo.Animation begins playing (useful?)
93                 onBegin: null,
94
95                 // onAnimate: Event?
96                 //              Synthetic event fired at each interval of a `dojo.Animation`
97                 onAnimate: null,
98
99                 // onEnd: Event?
100                 //              Synthetic event fired after the final frame of a `dojo.Animation`
101                 onEnd: null,
102
103                 // onPlay: Event?
104                 //              Synthetic event fired any time a `dojo.Animation` is play()'ed
105                 onPlay: null,
106
107                 // onPause: Event?
108                 //              Synthetic event fired when a `dojo.Animation` is paused
109                 onPause: null,
110
111                 // onStop: Event
112                 //              Synthetic event fires when a `dojo.Animation` is stopped
113                 onStop: null,
114
115         =====*/
116
117                 _percent: 0,
118                 _startRepeatCount: 0,
119
120                 _getStep: function(){
121                         var _p = this._percent,
122                                 _e = this.easing
123                         ;
124                         return _e ? _e(_p) : _p;
125                 },
126                 _fire: function(/*Event*/ evt, /*Array?*/ args){
127                         //      summary:
128                         //              Convenience function.  Fire event "evt" and pass it the
129                         //              arguments specified in "args".
130                         //      description:
131                         //              Convenience function.  Fire event "evt" and pass it the
132                         //              arguments specified in "args".
133                         //              Fires the callback in the scope of the `dojo.Animation`
134                         //              instance.
135                         //      evt:
136                         //              The event to fire.
137                         //      args:
138                         //              The arguments to pass to the event.
139                         var a = args||[];
140                         if(this[evt]){
141                                 if(dojo.config.debugAtAllCosts){
142                                         this[evt].apply(this, a);
143                                 }else{
144                                         try{
145                                                 this[evt].apply(this, a);
146                                         }catch(e){
147                                                 // squelch and log because we shouldn't allow exceptions in
148                                                 // synthetic event handlers to cause the internal timer to run
149                                                 // amuck, potentially pegging the CPU. I'm not a fan of this
150                                                 // squelch, but hopefully logging will make it clear what's
151                                                 // going on
152                                                 console.error("exception in animation handler for:", evt);
153                                                 console.error(e);
154                                         }
155                                 }
156                         }
157                         return this; // dojo.Animation
158                 },
159
160                 play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
161                         // summary:
162                         //              Start the animation.
163                         // delay:
164                         //              How many milliseconds to delay before starting.
165                         // gotoStart:
166                         //              If true, starts the animation from the beginning; otherwise,
167                         //              starts it from its current position.
168                         // returns: dojo.Animation
169                         //              The instance to allow chaining.
170
171                         var _t = this;
172                         if(_t._delayTimer){ _t._clearTimer(); }
173                         if(gotoStart){
174                                 _t._stopTimer();
175                                 _t._active = _t._paused = false;
176                                 _t._percent = 0;
177                         }else if(_t._active && !_t._paused){
178                                 return _t;
179                         }
180
181                         _t._fire("beforeBegin", [_t.node]);
182
183                         var de = delay || _t.delay,
184                                 _p = lang.hitch(_t, "_play", gotoStart);
185
186                         if(de > 0){
187                                 _t._delayTimer = setTimeout(_p, de);
188                                 return _t;
189                         }
190                         _p();
191                         return _t;      // dojo.Animation
192                 },
193
194                 _play: function(gotoStart){
195                         var _t = this;
196                         if(_t._delayTimer){ _t._clearTimer(); }
197                         _t._startTime = new Date().valueOf();
198                         if(_t._paused){
199                                 _t._startTime -= _t.duration * _t._percent;
200                         }
201
202                         _t._active = true;
203                         _t._paused = false;
204                         var value = _t.curve.getValue(_t._getStep());
205                         if(!_t._percent){
206                                 if(!_t._startRepeatCount){
207                                         _t._startRepeatCount = _t.repeat;
208                                 }
209                                 _t._fire("onBegin", [value]);
210                         }
211
212                         _t._fire("onPlay", [value]);
213
214                         _t._cycle();
215                         return _t; // dojo.Animation
216                 },
217
218                 pause: function(){
219                         // summary: Pauses a running animation.
220                         var _t = this;
221                         if(_t._delayTimer){ _t._clearTimer(); }
222                         _t._stopTimer();
223                         if(!_t._active){ return _t; /*dojo.Animation*/ }
224                         _t._paused = true;
225                         _t._fire("onPause", [_t.curve.getValue(_t._getStep())]);
226                         return _t; // dojo.Animation
227                 },
228
229                 gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
230                         //      summary:
231                         //              Sets the progress of the animation.
232                         //      percent:
233                         //              A percentage in decimal notation (between and including 0.0 and 1.0).
234                         //      andPlay:
235                         //              If true, play the animation after setting the progress.
236                         var _t = this;
237                         _t._stopTimer();
238                         _t._active = _t._paused = true;
239                         _t._percent = percent;
240                         if(andPlay){ _t.play(); }
241                         return _t; // dojo.Animation
242                 },
243
244                 stop: function(/*boolean?*/ gotoEnd){
245                         // summary: Stops a running animation.
246                         // gotoEnd: If true, the animation will end.
247                         var _t = this;
248                         if(_t._delayTimer){ _t._clearTimer(); }
249                         if(!_t._timer){ return _t; /* dojo.Animation */ }
250                         _t._stopTimer();
251                         if(gotoEnd){
252                                 _t._percent = 1;
253                         }
254                         _t._fire("onStop", [_t.curve.getValue(_t._getStep())]);
255                         _t._active = _t._paused = false;
256                         return _t; // dojo.Animation
257                 },
258
259                 status: function(){
260                         // summary:
261                         //              Returns a string token representation of the status of
262                         //              the animation, one of: "paused", "playing", "stopped"
263                         if(this._active){
264                                 return this._paused ? "paused" : "playing"; // String
265                         }
266                         return "stopped"; // String
267                 },
268
269                 _cycle: function(){
270                         var _t = this;
271                         if(_t._active){
272                                 var curr = new Date().valueOf();
273                                 var step = (curr - _t._startTime) / (_t.duration);
274
275                                 if(step >= 1){
276                                         step = 1;
277                                 }
278                                 _t._percent = step;
279
280                                 // Perform easing
281                                 if(_t.easing){
282                                         step = _t.easing(step);
283                                 }
284
285                                 _t._fire("onAnimate", [_t.curve.getValue(step)]);
286
287                                 if(_t._percent < 1){
288                                         _t._startTimer();
289                                 }else{
290                                         _t._active = false;
291
292                                         if(_t.repeat > 0){
293                                                 _t.repeat--;
294                                                 _t.play(null, true);
295                                         }else if(_t.repeat == -1){
296                                                 _t.play(null, true);
297                                         }else{
298                                                 if(_t._startRepeatCount){
299                                                         _t.repeat = _t._startRepeatCount;
300                                                         _t._startRepeatCount = 0;
301                                                 }
302                                         }
303                                         _t._percent = 0;
304                                         _t._fire("onEnd", [_t.node]);
305                                         !_t.repeat && _t._stopTimer();
306                                 }
307                         }
308                         return _t; // dojo.Animation
309                 },
310
311                 _clearTimer: function(){
312                         // summary: Clear the play delay timer
313                         clearTimeout(this._delayTimer);
314                         delete this._delayTimer;
315                 }
316
317         });
318
319         // the local timer, stubbed into all Animation instances
320         var ctr = 0,
321                 timer = null,
322                 runner = {
323                         run: function(){}
324                 };
325
326         lang.extend(dojo.Animation, {
327
328                 _startTimer: function(){
329                         if(!this._timer){
330                                 this._timer = connect.connect(runner, "run", this, "_cycle");
331                                 ctr++;
332                         }
333                         if(!timer){
334                                 timer = setInterval(lang.hitch(runner, "run"), this.rate);
335                         }
336                 },
337
338                 _stopTimer: function(){
339                         if(this._timer){
340                                 connect.disconnect(this._timer);
341                                 this._timer = null;
342                                 ctr--;
343                         }
344                         if(ctr <= 0){
345                                 clearInterval(timer);
346                                 timer = null;
347                                 ctr = 0;
348                         }
349                 }
350
351         });
352
353         var _makeFadeable =
354                                 has("ie") ? function(node){
355                         // only set the zoom if the "tickle" value would be the same as the
356                         // default
357                         var ns = node.style;
358                         // don't set the width to auto if it didn't already cascade that way.
359                         // We don't want to f anyones designs
360                         if(!ns.width.length && style.get(node, "width") == "auto"){
361                                 ns.width = "auto";
362                         }
363                 } :
364                                 function(){};
365
366         dojo._fade = function(/*Object*/ args){
367                 //      summary:
368                 //              Returns an animation that will fade the node defined by
369                 //              args.node from the start to end values passed (args.start
370                 //              args.end) (end is mandatory, start is optional)
371
372                 args.node = dom.byId(args.node);
373                 var fArgs = _mixin({ properties: {} }, args),
374                         props = (fArgs.properties.opacity = {});
375
376                 props.start = !("start" in fArgs) ?
377                         function(){
378                                 return +style.get(fArgs.node, "opacity")||0;
379                         } : fArgs.start;
380                 props.end = fArgs.end;
381
382                 var anim = dojo.animateProperty(fArgs);
383                 connect.connect(anim, "beforeBegin", lang.partial(_makeFadeable, fArgs.node));
384
385                 return anim; // dojo.Animation
386         };
387
388         /*=====
389         dojo.__FadeArgs = function(node, duration, easing){
390                 //      node: DOMNode|String
391                 //              The node referenced in the animation
392                 //      duration: Integer?
393                 //              Duration of the animation in milliseconds.
394                 //      easing: Function?
395                 //              An easing function.
396                 this.node = node;
397                 this.duration = duration;
398                 this.easing = easing;
399         }
400         =====*/
401
402         dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
403                 // summary:
404                 //              Returns an animation that will fade node defined in 'args' from
405                 //              its current opacity to fully opaque.
406                 return dojo._fade(_mixin({ end: 1 }, args)); // dojo.Animation
407         };
408
409         dojo.fadeOut = function(/*dojo.__FadeArgs*/ args){
410                 // summary:
411                 //              Returns an animation that will fade node defined in 'args'
412                 //              from its current opacity to fully transparent.
413                 return dojo._fade(_mixin({ end: 0 }, args)); // dojo.Animation
414         };
415
416         dojo._defaultEasing = function(/*Decimal?*/ n){
417                 // summary: The default easing function for dojo.Animation(s)
418                 return 0.5 + ((Math.sin((n + 1.5) * Math.PI)) / 2);     // Decimal
419         };
420
421         var PropLine = function(properties){
422                 // PropLine is an internal class which is used to model the values of
423                 // an a group of CSS properties across an animation lifecycle. In
424                 // particular, the "getValue" function handles getting interpolated
425                 // values between start and end for a particular CSS value.
426                 this._properties = properties;
427                 for(var p in properties){
428                         var prop = properties[p];
429                         if(prop.start instanceof Color){
430                                 // create a reusable temp color object to keep intermediate results
431                                 prop.tempColor = new Color();
432                         }
433                 }
434         };
435
436         PropLine.prototype.getValue = function(r){
437                 var ret = {};
438                 for(var p in this._properties){
439                         var prop = this._properties[p],
440                                 start = prop.start;
441                         if(start instanceof Color){
442                                 ret[p] = Color.blendColors(start, prop.end, r, prop.tempColor).toCss();
443                         }else if(!lang.isArray(start)){
444                                 ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units || "px" : 0);
445                         }
446                 }
447                 return ret;
448         };
449
450         /*=====
451         dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
452                 // Properties: Object?
453                 //      A hash map of style properties to Objects describing the transition,
454                 //      such as the properties of dojo._Line with an additional 'units' property
455                 properties: {}
456
457                 //TODOC: add event callbacks
458         });
459         =====*/
460
461         dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){
462                 // summary:
463                 //              Returns an animation that will transition the properties of
464                 //              node defined in `args` depending how they are defined in
465                 //              `args.properties`
466                 //
467                 // description:
468                 //              `dojo.animateProperty` is the foundation of most `dojo.fx`
469                 //              animations. It takes an object of "properties" corresponding to
470                 //              style properties, and animates them in parallel over a set
471                 //              duration.
472                 //
473                 // example:
474                 //              A simple animation that changes the width of the specified node.
475                 //      |       dojo.animateProperty({
476                 //      |               node: "nodeId",
477                 //      |               properties: { width: 400 },
478                 //      |       }).play();
479                 //              Dojo figures out the start value for the width and converts the
480                 //              integer specified for the width to the more expressive but
481                 //              verbose form `{ width: { end: '400', units: 'px' } }` which you
482                 //              can also specify directly. Defaults to 'px' if ommitted.
483                 //
484                 // example:
485                 //              Animate width, height, and padding over 2 seconds... the
486                 //              pedantic way:
487                 //      |       dojo.animateProperty({ node: node, duration:2000,
488                 //      |               properties: {
489                 //      |                       width: { start: '200', end: '400', units:"px" },
490                 //      |                       height: { start:'200', end: '400', units:"px" },
491                 //      |                       paddingTop: { start:'5', end:'50', units:"px" }
492                 //      |               }
493                 //      |       }).play();
494                 //              Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties
495                 //              are written using "mixed case", as the hyphen is illegal as an object key.
496                 //
497                 // example:
498                 //              Plug in a different easing function and register a callback for
499                 //              when the animation ends. Easing functions accept values between
500                 //              zero and one and return a value on that basis. In this case, an
501                 //              exponential-in curve.
502                 //      |       dojo.animateProperty({
503                 //      |               node: "nodeId",
504                 //      |               // dojo figures out the start value
505                 //      |               properties: { width: { end: 400 } },
506                 //      |               easing: function(n){
507                 //      |                       return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
508                 //      |               },
509                 //      |               onEnd: function(node){
510                 //      |                       // called when the animation finishes. The animation
511                 //      |                       // target is passed to this function
512                 //      |               }
513                 //      |       }).play(500); // delay playing half a second
514                 //
515                 // example:
516                 //              Like all `dojo.Animation`s, animateProperty returns a handle to the
517                 //              Animation instance, which fires the events common to Dojo FX. Use `dojo.connect`
518                 //              to access these events outside of the Animation definiton:
519                 //      |       var anim = dojo.animateProperty({
520                 //      |               node:"someId",
521                 //      |               properties:{
522                 //      |                       width:400, height:500
523                 //      |               }
524                 //      |       });
525                 //      |       dojo.connect(anim,"onEnd", function(){
526                 //      |               console.log("animation ended");
527                 //      |       });
528                 //      |       // play the animation now:
529                 //      |       anim.play();
530                 //
531                 // example:
532                 //              Each property can be a function whose return value is substituted along.
533                 //              Additionally, each measurement (eg: start, end) can be a function. The node
534                 //              reference is passed direcly to callbacks.
535                 //      |       dojo.animateProperty({
536                 //      |               node:"mine",
537                 //      |               properties:{
538                 //      |                       height:function(node){
539                 //      |                               // shrink this node by 50%
540                 //      |                               return dojo.position(node).h / 2
541                 //      |                       },
542                 //      |                       width:{
543                 //      |                               start:function(node){ return 100; },
544                 //      |                               end:function(node){ return 200; }
545                 //      |                       }
546                 //      |               }
547                 //      |       }).play();
548                 //
549
550                 var n = args.node = dom.byId(args.node);
551                 if(!args.easing){ args.easing = dojo._defaultEasing; }
552
553                 var anim = new dojo.Animation(args);
554                 connect.connect(anim, "beforeBegin", anim, function(){
555                         var pm = {};
556                         for(var p in this.properties){
557                                 // Make shallow copy of properties into pm because we overwrite
558                                 // some values below. In particular if start/end are functions
559                                 // we don't want to overwrite them or the functions won't be
560                                 // called if the animation is reused.
561                                 if(p == "width" || p == "height"){
562                                         this.node.display = "block";
563                                 }
564                                 var prop = this.properties[p];
565                                 if(lang.isFunction(prop)){
566                                         prop = prop(n);
567                                 }
568                                 prop = pm[p] = _mixin({}, (lang.isObject(prop) ? prop: { end: prop }));
569
570                                 if(lang.isFunction(prop.start)){
571                                         prop.start = prop.start(n);
572                                 }
573                                 if(lang.isFunction(prop.end)){
574                                         prop.end = prop.end(n);
575                                 }
576                                 var isColor = (p.toLowerCase().indexOf("color") >= 0);
577                                 function getStyle(node, p){
578                                         // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
579                                         var v = { height: node.offsetHeight, width: node.offsetWidth }[p];
580                                         if(v !== undefined){ return v; }
581                                         v = style.get(node, p);
582                                         return (p == "opacity") ? +v : (isColor ? v : parseFloat(v));
583                                 }
584                                 if(!("end" in prop)){
585                                         prop.end = getStyle(n, p);
586                                 }else if(!("start" in prop)){
587                                         prop.start = getStyle(n, p);
588                                 }
589
590                                 if(isColor){
591                                         prop.start = new Color(prop.start);
592                                         prop.end = new Color(prop.end);
593                                 }else{
594                                         prop.start = (p == "opacity") ? +prop.start : parseFloat(prop.start);
595                                 }
596                         }
597                         this.curve = new PropLine(pm);
598                 });
599                 connect.connect(anim, "onAnimate", lang.hitch(style, "set", anim.node));
600                 return anim; // dojo.Animation
601         };
602
603         dojo.anim = function(   /*DOMNode|String*/      node,
604                                                         /*Object*/                      properties,
605                                                         /*Integer?*/            duration,
606                                                         /*Function?*/           easing,
607                                                         /*Function?*/           onEnd,
608                                                         /*Integer?*/            delay){
609                 //      summary:
610                 //              A simpler interface to `dojo.animateProperty()`, also returns
611                 //              an instance of `dojo.Animation` but begins the animation
612                 //              immediately, unlike nearly every other Dojo animation API.
613                 //      description:
614                 //              `dojo.anim` is a simpler (but somewhat less powerful) version
615                 //              of `dojo.animateProperty`.  It uses defaults for many basic properties
616                 //              and allows for positional parameters to be used in place of the
617                 //              packed "property bag" which is used for other Dojo animation
618                 //              methods.
619                 //
620                 //              The `dojo.Animation` object returned from `dojo.anim` will be
621                 //              already playing when it is returned from this function, so
622                 //              calling play() on it again is (usually) a no-op.
623                 //      node:
624                 //              a DOM node or the id of a node to animate CSS properties on
625                 //      duration:
626                 //              The number of milliseconds over which the animation
627                 //              should run. Defaults to the global animation default duration
628                 //              (350ms).
629                 //      easing:
630                 //              An easing function over which to calculate acceleration
631                 //              and deceleration of the animation through its duration.
632                 //              A default easing algorithm is provided, but you may
633                 //              plug in any you wish. A large selection of easing algorithms
634                 //              are available in `dojo.fx.easing`.
635                 //      onEnd:
636                 //              A function to be called when the animation finishes
637                 //              running.
638                 //      delay:
639                 //              The number of milliseconds to delay beginning the
640                 //              animation by. The default is 0.
641                 //      example:
642                 //              Fade out a node
643                 //      |       dojo.anim("id", { opacity: 0 });
644                 //      example:
645                 //              Fade out a node over a full second
646                 //      |       dojo.anim("id", { opacity: 0 }, 1000);
647                 return dojo.animateProperty({ // dojo.Animation
648                         node: node,
649                         duration: duration || dojo.Animation.prototype.duration,
650                         properties: properties,
651                         easing: easing,
652                         onEnd: onEnd
653                 }).play(delay || 0);
654         };
655
656         return {
657                 _Line: dojo._Line,
658                 Animation: dojo.Animation,
659                 _fade: dojo._fade,
660                 fadeIn: dojo.fadeIn,
661                 fadeOut: dojo.fadeOut,
662                 _defaultEasing: dojo._defaultEasing,
663                 animateProperty: dojo.animateProperty,
664                 anim: dojo.anim
665         };
666 });