1 if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojo.fx"] = true;
3 dojo.provide("dojo.fx");
4 dojo.provide("dojo.fx.Toggler");
8 // summary: Effects library on top of Base animations
14 _fire: function(evt, args){
16 this[evt].apply(this, args||[]);
22 var _chain = function(animations){
24 this._animations = animations||[];
25 this._current = this._onAnimateCtx = this._onEndCtx = null;
28 dojo.forEach(this._animations, function(a){
29 this.duration += a.duration;
30 if(a.delay){ this.duration += a.delay; }
34 _onAnimate: function(){
35 this._fire("onAnimate", arguments);
38 dojo.disconnect(this._onAnimateCtx);
39 dojo.disconnect(this._onEndCtx);
40 this._onAnimateCtx = this._onEndCtx = null;
41 if(this._index + 1 == this._animations.length){
45 this._current = this._animations[++this._index];
46 this._onAnimateCtx = dojo.connect(this._current, "onAnimate", this, "_onAnimate");
47 this._onEndCtx = dojo.connect(this._current, "onEnd", this, "_onEnd");
48 this._current.play(0, true);
51 play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
52 if(!this._current){ this._current = this._animations[this._index = 0]; }
53 if(!gotoStart && this._current.status() == "playing"){ return this; }
54 var beforeBegin = dojo.connect(this._current, "beforeBegin", this, function(){
55 this._fire("beforeBegin");
57 onBegin = dojo.connect(this._current, "onBegin", this, function(arg){
58 this._fire("onBegin", arguments);
60 onPlay = dojo.connect(this._current, "onPlay", this, function(arg){
61 this._fire("onPlay", arguments);
62 dojo.disconnect(beforeBegin);
63 dojo.disconnect(onBegin);
64 dojo.disconnect(onPlay);
66 if(this._onAnimateCtx){
67 dojo.disconnect(this._onAnimateCtx);
69 this._onAnimateCtx = dojo.connect(this._current, "onAnimate", this, "_onAnimate");
71 dojo.disconnect(this._onEndCtx);
73 this._onEndCtx = dojo.connect(this._current, "onEnd", this, "_onEnd");
74 this._current.play.apply(this._current, arguments);
79 var e = dojo.connect(this._current, "onPause", this, function(arg){
80 this._fire("onPause", arguments);
83 this._current.pause();
87 gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
89 var offset = this.duration * percent;
91 dojo.some(this._animations, function(a){
92 if(a.duration <= offset){
100 this._current.gotoPercent(offset / _current.duration, andPlay);
104 stop: function(/*boolean?*/ gotoEnd){
107 for(; this._index + 1 < this._animations.length; ++this._index){
108 this._animations[this._index].stop(true);
110 this._current = this._animations[this._index];
112 var e = dojo.connect(this._current, "onStop", this, function(arg){
113 this._fire("onStop", arguments);
116 this._current.stop();
121 return this._current ? this._current.status() : "stopped";
124 if(this._onAnimateCtx){ dojo.disconnect(this._onAnimateCtx); }
125 if(this._onEndCtx){ dojo.disconnect(this._onEndCtx); }
128 dojo.extend(_chain, _baseObj);
130 dojo.fx.chain = function(/*dojo._Animation[]*/ animations){
131 // summary: Chain a list of dojo._Animation s to run in sequence
134 // | dojo.fadeIn({ node:node }),
135 // | dojo.fadeOut({ node:otherNode })
138 return new _chain(animations) // dojo._Animation
141 var _combine = function(animations){
142 this._animations = animations||[];
147 dojo.forEach(animations, function(a){
148 var duration = a.duration;
149 if(a.delay){ duration += a.delay; }
150 if(this.duration < duration){ this.duration = duration; }
151 this._connects.push(dojo.connect(a, "onEnd", this, "_onEnd"));
154 this._pseudoAnimation = new dojo._Animation({curve: [0, 1], duration: this.duration});
155 dojo.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop"],
157 this._connects.push(dojo.connect(this._pseudoAnimation, evt, dojo.hitch(this, "_fire", evt)));
162 dojo.extend(_combine, {
163 _doAction: function(action, args){
164 dojo.forEach(this._animations, function(a){
165 a[action].apply(a, args);
170 if(++this._finished == this._animations.length){
174 _call: function(action, args){
175 var t = this._pseudoAnimation;
176 t[action].apply(t, args);
178 play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
180 this._doAction("play", arguments);
181 this._call("play", arguments);
185 this._doAction("pause", arguments);
186 this._call("pause", arguments);
189 gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
190 var ms = this.duration * percent;
191 dojo.forEach(this._animations, function(a){
192 a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
194 this._call("gotoProcent", arguments);
197 stop: function(/*boolean?*/ gotoEnd){
198 this._doAction("stop", arguments);
199 this._call("stop", arguments);
203 return this._pseudoAnimation.status();
206 dojo.forEach(this._connects, dojo.disconnect);
209 dojo.extend(_combine, _baseObj);
211 dojo.fx.combine = function(/*dojo._Animation[]*/ animations){
212 // summary: Combine a list of dojo._Animation s to run in parallel
214 // | dojo.fx.combine([
215 // | dojo.fadeIn({ node:node }),
216 // | dojo.fadeOut({ node:otherNode })
218 return new _combine(animations); // dojo._Animation
222 dojo.declare("dojo.fx.Toggler", null, {
224 // class constructor for an animation toggler. It accepts a packed
225 // set of arguments about what type of animation to use in each
226 // direction, duration, etc.
229 // | var t = new dojo.fx.Toggler({
231 // | showDuration: 500,
232 // | // hideDuration will default to "200"
233 // | showFunc: dojo.wipeIn,
234 // | // hideFunc will default to "fadeOut"
236 // | t.show(100); // delay showing for 100ms
237 // | // ...time passes...
240 // FIXME: need a policy for where the toggler should "be" the next
241 // time show/hide are called if we're stopped somewhere in the
244 constructor: function(args){
247 dojo.mixin(_t, args);
249 _t._showArgs = dojo.mixin({}, args);
250 _t._showArgs.node = _t.node;
251 _t._showArgs.duration = _t.showDuration;
252 _t.showAnim = _t.showFunc(_t._showArgs);
254 _t._hideArgs = dojo.mixin({}, args);
255 _t._hideArgs.node = _t.node;
256 _t._hideArgs.duration = _t.hideDuration;
257 _t.hideAnim = _t.hideFunc(_t._hideArgs);
259 dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true));
260 dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true));
264 // the node to toggle
267 // showFunc: Function
268 // The function that returns the dojo._Animation to show the node
269 showFunc: dojo.fadeIn,
271 // hideFunc: Function
272 // The function that returns the dojo._Animation to hide the node
273 hideFunc: dojo.fadeOut,
276 // Time in milliseconds to run the show Animation
280 // Time in milliseconds to run the hide Animation
294 show: function(delay){
295 // summary: Toggle the node to showing
296 return this.showAnim.play(delay || 0);
299 hide: function(delay){
300 // summary: Toggle the node to hidden
301 return this.hideAnim.play(delay || 0);
305 dojo.fx.wipeIn = function(/*Object*/ args){
307 // Returns an animation that will expand the
308 // node defined in 'args' object from it's current height to
309 // it's natural height (with no scrollbar).
310 // Node must have no margin/border/padding.
311 args.node = dojo.byId(args.node);
312 var node = args.node, s = node.style;
314 var anim = dojo.animateProperty(dojo.mixin({
317 // wrapped in functions so we wait till the last second to query (in case value has changed)
319 // start at current [computed] height, but use 1px rather than 0
320 // because 0 causes IE to display the whole panel
322 if(s.visibility=="hidden"||s.display=="none"){
328 var height = dojo.style(node, "height");
329 return Math.max(height, 1);
333 return node.scrollHeight;
339 dojo.connect(anim, "onEnd", function(){
343 return anim; // dojo._Animation
346 dojo.fx.wipeOut = function(/*Object*/ args){
348 // Returns an animation that will shrink node defined in "args"
349 // from it's current height to 1px, and then hide it.
350 var node = args.node = dojo.byId(args.node);
353 var anim = dojo.animateProperty(dojo.mixin({
356 end: 1 // 0 causes IE to display the whole panel
361 dojo.connect(anim, "beforeBegin", function(){
362 s.overflow = "hidden";
365 dojo.connect(anim, "onEnd", function(){
370 return anim; // dojo._Animation
373 dojo.fx.slideTo = function(/*Object?*/ args){
375 // Returns an animation that will slide "node"
376 // defined in args Object from its current position to
377 // the position defined by (args.left, args.top).
379 // | dojo.fx.slideTo({ node: node, left:"40", top:"50", unit:"px" }).play()
381 var node = (args.node = dojo.byId(args.node));
386 var init = (function(n){
388 var cs = dojo.getComputedStyle(n);
389 var pos = cs.position;
390 top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
391 left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
392 if(pos != 'absolute' && pos != 'relative'){
393 var ret = dojo.coords(n, true);
396 n.style.position="absolute";
397 n.style.top=top+"px";
398 n.style.left=left+"px";
404 var anim = dojo.animateProperty(dojo.mixin({
406 top: { end: args.top||0 },
407 left: { end: args.left||0 }
410 dojo.connect(anim, "beforeBegin", anim, init);
412 return anim; // dojo._Animation