]> git.wh0rd.org - tt-rss.git/blob - lib/dojo/fx.js
upgrade Dojo to 1.6.1
[tt-rss.git] / lib / dojo / fx.js
1 /*
2 Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
5 */
6
7
8 if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9 dojo._hasResource["dojo.fx"] = true;
10 dojo.provide("dojo.fx");
11 dojo.require("dojo.fx.Toggler");
12
13
14 /*=====
15 dojo.fx = {
16 // summary: Effects library on top of Base animations
17 };
18 =====*/
19 (function(){
20
21 var d = dojo,
22 _baseObj = {
23 _fire: function(evt, args){
24 if(this[evt]){
25 this[evt].apply(this, args||[]);
26 }
27 return this;
28 }
29 };
30
31 var _chain = function(animations){
32 this._index = -1;
33 this._animations = animations||[];
34 this._current = this._onAnimateCtx = this._onEndCtx = null;
35
36 this.duration = 0;
37 d.forEach(this._animations, function(a){
38 this.duration += a.duration;
39 if(a.delay){ this.duration += a.delay; }
40 }, this);
41 };
42 d.extend(_chain, {
43 _onAnimate: function(){
44 this._fire("onAnimate", arguments);
45 },
46 _onEnd: function(){
47 d.disconnect(this._onAnimateCtx);
48 d.disconnect(this._onEndCtx);
49 this._onAnimateCtx = this._onEndCtx = null;
50 if(this._index + 1 == this._animations.length){
51 this._fire("onEnd");
52 }else{
53 // switch animations
54 this._current = this._animations[++this._index];
55 this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
56 this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
57 this._current.play(0, true);
58 }
59 },
60 play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
61 if(!this._current){ this._current = this._animations[this._index = 0]; }
62 if(!gotoStart && this._current.status() == "playing"){ return this; }
63 var beforeBegin = d.connect(this._current, "beforeBegin", this, function(){
64 this._fire("beforeBegin");
65 }),
66 onBegin = d.connect(this._current, "onBegin", this, function(arg){
67 this._fire("onBegin", arguments);
68 }),
69 onPlay = d.connect(this._current, "onPlay", this, function(arg){
70 this._fire("onPlay", arguments);
71 d.disconnect(beforeBegin);
72 d.disconnect(onBegin);
73 d.disconnect(onPlay);
74 });
75 if(this._onAnimateCtx){
76 d.disconnect(this._onAnimateCtx);
77 }
78 this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
79 if(this._onEndCtx){
80 d.disconnect(this._onEndCtx);
81 }
82 this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
83 this._current.play.apply(this._current, arguments);
84 return this;
85 },
86 pause: function(){
87 if(this._current){
88 var e = d.connect(this._current, "onPause", this, function(arg){
89 this._fire("onPause", arguments);
90 d.disconnect(e);
91 });
92 this._current.pause();
93 }
94 return this;
95 },
96 gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
97 this.pause();
98 var offset = this.duration * percent;
99 this._current = null;
100 d.some(this._animations, function(a){
101 if(a.duration <= offset){
102 this._current = a;
103 return true;
104 }
105 offset -= a.duration;
106 return false;
107 });
108 if(this._current){
109 this._current.gotoPercent(offset / this._current.duration, andPlay);
110 }
111 return this;
112 },
113 stop: function(/*boolean?*/ gotoEnd){
114 if(this._current){
115 if(gotoEnd){
116 for(; this._index + 1 < this._animations.length; ++this._index){
117 this._animations[this._index].stop(true);
118 }
119 this._current = this._animations[this._index];
120 }
121 var e = d.connect(this._current, "onStop", this, function(arg){
122 this._fire("onStop", arguments);
123 d.disconnect(e);
124 });
125 this._current.stop();
126 }
127 return this;
128 },
129 status: function(){
130 return this._current ? this._current.status() : "stopped";
131 },
132 destroy: function(){
133 if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); }
134 if(this._onEndCtx){ d.disconnect(this._onEndCtx); }
135 }
136 });
137 d.extend(_chain, _baseObj);
138
139 dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
140 // summary:
141 // Chain a list of `dojo.Animation`s to run in sequence
142 //
143 // description:
144 // Return a `dojo.Animation` which will play all passed
145 // `dojo.Animation` instances in sequence, firing its own
146 // synthesized events simulating a single animation. (eg:
147 // onEnd of this animation means the end of the chain,
148 // not the individual animations within)
149 //
150 // example:
151 // Once `node` is faded out, fade in `otherNode`
152 // | dojo.fx.chain([
153 // | dojo.fadeIn({ node:node }),
154 // | dojo.fadeOut({ node:otherNode })
155 // | ]).play();
156 //
157 return new _chain(animations) // dojo.Animation
158 };
159
160 var _combine = function(animations){
161 this._animations = animations||[];
162 this._connects = [];
163 this._finished = 0;
164
165 this.duration = 0;
166 d.forEach(animations, function(a){
167 var duration = a.duration;
168 if(a.delay){ duration += a.delay; }
169 if(this.duration < duration){ this.duration = duration; }
170 this._connects.push(d.connect(a, "onEnd", this, "_onEnd"));
171 }, this);
172
173 this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
174 var self = this;
175 d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
176 function(evt){
177 self._connects.push(d.connect(self._pseudoAnimation, evt,
178 function(){ self._fire(evt, arguments); }
179 ));
180 }
181 );
182 };
183 d.extend(_combine, {
184 _doAction: function(action, args){
185 d.forEach(this._animations, function(a){
186 a[action].apply(a, args);
187 });
188 return this;
189 },
190 _onEnd: function(){
191 if(++this._finished > this._animations.length){
192 this._fire("onEnd");
193 }
194 },
195 _call: function(action, args){
196 var t = this._pseudoAnimation;
197 t[action].apply(t, args);
198 },
199 play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
200 this._finished = 0;
201 this._doAction("play", arguments);
202 this._call("play", arguments);
203 return this;
204 },
205 pause: function(){
206 this._doAction("pause", arguments);
207 this._call("pause", arguments);
208 return this;
209 },
210 gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
211 var ms = this.duration * percent;
212 d.forEach(this._animations, function(a){
213 a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
214 });
215 this._call("gotoPercent", arguments);
216 return this;
217 },
218 stop: function(/*boolean?*/ gotoEnd){
219 this._doAction("stop", arguments);
220 this._call("stop", arguments);
221 return this;
222 },
223 status: function(){
224 return this._pseudoAnimation.status();
225 },
226 destroy: function(){
227 d.forEach(this._connects, dojo.disconnect);
228 }
229 });
230 d.extend(_combine, _baseObj);
231
232 dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
233 // summary:
234 // Combine a list of `dojo.Animation`s to run in parallel
235 //
236 // description:
237 // Combine an array of `dojo.Animation`s to run in parallel,
238 // providing a new `dojo.Animation` instance encompasing each
239 // animation, firing standard animation events.
240 //
241 // example:
242 // Fade out `node` while fading in `otherNode` simultaneously
243 // | dojo.fx.combine([
244 // | dojo.fadeIn({ node:node }),
245 // | dojo.fadeOut({ node:otherNode })
246 // | ]).play();
247 //
248 // example:
249 // When the longest animation ends, execute a function:
250 // | var anim = dojo.fx.combine([
251 // | dojo.fadeIn({ node: n, duration:700 }),
252 // | dojo.fadeOut({ node: otherNode, duration: 300 })
253 // | ]);
254 // | dojo.connect(anim, "onEnd", function(){
255 // | // overall animation is done.
256 // | });
257 // | anim.play(); // play the animation
258 //
259 return new _combine(animations); // dojo.Animation
260 };
261
262 dojo.fx.wipeIn = function(/*Object*/ args){
263 // summary:
264 // Expand a node to it's natural height.
265 //
266 // description:
267 // Returns an animation that will expand the
268 // node defined in 'args' object from it's current height to
269 // it's natural height (with no scrollbar).
270 // Node must have no margin/border/padding.
271 //
272 // args: Object
273 // A hash-map of standard `dojo.Animation` constructor properties
274 // (such as easing: node: duration: and so on)
275 //
276 // example:
277 // | dojo.fx.wipeIn({
278 // | node:"someId"
279 // | }).play()
280 var node = args.node = d.byId(args.node), s = node.style, o;
281
282 var anim = d.animateProperty(d.mixin({
283 properties: {
284 height: {
285 // wrapped in functions so we wait till the last second to query (in case value has changed)
286 start: function(){
287 // start at current [computed] height, but use 1px rather than 0
288 // because 0 causes IE to display the whole panel
289 o = s.overflow;
290 s.overflow = "hidden";
291 if(s.visibility == "hidden" || s.display == "none"){
292 s.height = "1px";
293 s.display = "";
294 s.visibility = "";
295 return 1;
296 }else{
297 var height = d.style(node, "height");
298 return Math.max(height, 1);
299 }
300 },
301 end: function(){
302 return node.scrollHeight;
303 }
304 }
305 }
306 }, args));
307
308 d.connect(anim, "onEnd", function(){
309 s.height = "auto";
310 s.overflow = o;
311 });
312
313 return anim; // dojo.Animation
314 };
315
316 dojo.fx.wipeOut = function(/*Object*/ args){
317 // summary:
318 // Shrink a node to nothing and hide it.
319 //
320 // description:
321 // Returns an animation that will shrink node defined in "args"
322 // from it's current height to 1px, and then hide it.
323 //
324 // args: Object
325 // A hash-map of standard `dojo.Animation` constructor properties
326 // (such as easing: node: duration: and so on)
327 //
328 // example:
329 // | dojo.fx.wipeOut({ node:"someId" }).play()
330
331 var node = args.node = d.byId(args.node), s = node.style, o;
332
333 var anim = d.animateProperty(d.mixin({
334 properties: {
335 height: {
336 end: 1 // 0 causes IE to display the whole panel
337 }
338 }
339 }, args));
340
341 d.connect(anim, "beforeBegin", function(){
342 o = s.overflow;
343 s.overflow = "hidden";
344 s.display = "";
345 });
346 d.connect(anim, "onEnd", function(){
347 s.overflow = o;
348 s.height = "auto";
349 s.display = "none";
350 });
351
352 return anim; // dojo.Animation
353 };
354
355 dojo.fx.slideTo = function(/*Object*/ args){
356 // summary:
357 // Slide a node to a new top/left position
358 //
359 // description:
360 // Returns an animation that will slide "node"
361 // defined in args Object from its current position to
362 // the position defined by (args.left, args.top).
363 //
364 // args: Object
365 // A hash-map of standard `dojo.Animation` constructor properties
366 // (such as easing: node: duration: and so on). Special args members
367 // are `top` and `left`, which indicate the new position to slide to.
368 //
369 // example:
370 // | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
371
372 var node = args.node = d.byId(args.node),
373 top = null, left = null;
374
375 var init = (function(n){
376 return function(){
377 var cs = d.getComputedStyle(n);
378 var pos = cs.position;
379 top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
380 left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
381 if(pos != 'absolute' && pos != 'relative'){
382 var ret = d.position(n, true);
383 top = ret.y;
384 left = ret.x;
385 n.style.position="absolute";
386 n.style.top=top+"px";
387 n.style.left=left+"px";
388 }
389 };
390 })(node);
391 init();
392
393 var anim = d.animateProperty(d.mixin({
394 properties: {
395 top: args.top || 0,
396 left: args.left || 0
397 }
398 }, args));
399 d.connect(anim, "beforeBegin", anim, init);
400
401 return anim; // dojo.Animation
402 };
403
404 })();
405
406 }