]> git.wh0rd.org - tt-rss.git/blob - lib/dojo/_base/fx.js.uncompressed.js
make precache_headlines_idle() start slower
[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 });