Plato on Github
Report Home
dojo/fx.js
Maintainability
70.34
Lines of code
437
Difficulty
84.47
Estimated Errors
3.95
Function weight
By Complexity
By SLOC
define([ "./_base/lang", "./Evented", "./_base/kernel", "./_base/array", "./aspect", "./_base/fx", "./dom", "./dom-style", "./dom-geometry", "./ready", "require" // for context sensitive loading of Toggler ], function(lang, Evented, dojo, arrayUtil, aspect, baseFx, dom, domStyle, geom, ready, require){ // module: // dojo/fx // For back-compat, remove in 2.0. if(!dojo.isAsync){ ready(0, function(){ var requires = ["./fx/Toggler"]; require(requires); // use indirection so modules not rolled into a build }); } var coreFx = dojo.fx = { // summary: // Effects library on top of Base animations }; var _baseObj = { _fire: function(evt, args){ if(this[evt]){ this[evt].apply(this, args||[]); } return this; } }; var _chain = function(animations){ this._index = -1; this._animations = animations||[]; this._current = this._onAnimateCtx = this._onEndCtx = null; this.duration = 0; arrayUtil.forEach(this._animations, function(a){ this.duration += a.duration; if(a.delay){ this.duration += a.delay; } }, this); }; _chain.prototype = new Evented(); lang.extend(_chain, { _onAnimate: function(){ this._fire("onAnimate", arguments); }, _onEnd: function(){ this._onAnimateCtx.remove(); this._onEndCtx.remove(); this._onAnimateCtx = this._onEndCtx = null; if(this._index + 1 == this._animations.length){ this._fire("onEnd"); }else{ // switch animations this._current = this._animations[++this._index]; this._onAnimateCtx = aspect.after(this._current, "onAnimate", lang.hitch(this, "_onAnimate"), true); this._onEndCtx = aspect.after(this._current, "onEnd", lang.hitch(this, "_onEnd"), true); this._current.play(0, true); } }, play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ if(!this._current){ this._current = this._animations[this._index = 0]; } if(!gotoStart && this._current.status() == "playing"){ return this; } var beforeBegin = aspect.after(this._current, "beforeBegin", lang.hitch(this, function(){ this._fire("beforeBegin"); }), true), onBegin = aspect.after(this._current, "onBegin", lang.hitch(this, function(arg){ this._fire("onBegin", arguments); }), true), onPlay = aspect.after(this._current, "onPlay", lang.hitch(this, function(arg){ this._fire("onPlay", arguments); beforeBegin.remove(); onBegin.remove(); onPlay.remove(); })); if(this._onAnimateCtx){ this._onAnimateCtx.remove(); } this._onAnimateCtx = aspect.after(this._current, "onAnimate", lang.hitch(this, "_onAnimate"), true); if(this._onEndCtx){ this._onEndCtx.remove(); } this._onEndCtx = aspect.after(this._current, "onEnd", lang.hitch(this, "_onEnd"), true); this._current.play.apply(this._current, arguments); return this; }, pause: function(){ if(this._current){ var e = aspect.after(this._current, "onPause", lang.hitch(this, function(arg){ this._fire("onPause", arguments); e.remove(); }), true); this._current.pause(); } return this; }, gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){ this.pause(); var offset = this.duration * percent; this._current = null; arrayUtil.some(this._animations, function(a, index){ if(offset <= a.duration){ this._current = a; this._index = index; return true; } offset -= a.duration; return false; }, this); if(this._current){ this._current.gotoPercent(offset / this._current.duration); } if (andPlay) { this.play(); } return this; }, stop: function(/*boolean?*/ gotoEnd){ if(this._current){ if(gotoEnd){ for(; this._index + 1 < this._animations.length; ++this._index){ this._animations[this._index].stop(true); } this._current = this._animations[this._index]; } var e = aspect.after(this._current, "onStop", lang.hitch(this, function(arg){ this._fire("onStop", arguments); e.remove(); }), true); this._current.stop(); } return this; }, status: function(){ return this._current ? this._current.status() : "stopped"; }, destroy: function(){ this.stop(); if(this._onAnimateCtx){ this._onAnimateCtx.remove(); } if(this._onEndCtx){ this._onEndCtx.remove(); } } }); lang.extend(_chain, _baseObj); coreFx.chain = function(/*dojo/_base/fx.Animation[]*/ animations){ // summary: // Chain a list of `dojo/_base/fx.Animation`s to run in sequence // // description: // Return a `dojo/_base/fx.Animation` which will play all passed // `dojo/_base/fx.Animation` instances in sequence, firing its own // synthesized events simulating a single animation. (eg: // onEnd of this animation means the end of the chain, // not the individual animations within) // // example: // Once `node` is faded out, fade in `otherNode` // | require(["dojo/fx"], function(fx){ // | fx.chain([ // | fx.fadeIn({ node:node }), // | fx.fadeOut({ node:otherNode }) // | ]).play(); // | }); // return new _chain(animations); // dojo/_base/fx.Animation }; var _combine = function(animations){ this._animations = animations||[]; this._connects = []; this._finished = 0; this.duration = 0; arrayUtil.forEach(animations, function(a){ var duration = a.duration; if(a.delay){ duration += a.delay; } if(this.duration < duration){ this.duration = duration; } this._connects.push(aspect.after(a, "onEnd", lang.hitch(this, "_onEnd"), true)); }, this); this._pseudoAnimation = new baseFx.Animation({curve: [0, 1], duration: this.duration}); var self = this; arrayUtil.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"], function(evt){ self._connects.push(aspect.after(self._pseudoAnimation, evt, function(){ self._fire(evt, arguments); }, true)); } ); }; lang.extend(_combine, { _doAction: function(action, args){ arrayUtil.forEach(this._animations, function(a){ a[action].apply(a, args); }); return this; }, _onEnd: function(){ if(++this._finished > this._animations.length){ this._fire("onEnd"); } }, _call: function(action, args){ var t = this._pseudoAnimation; t[action].apply(t, args); }, play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ this._finished = 0; this._doAction("play", arguments); this._call("play", arguments); return this; }, pause: function(){ this._doAction("pause", arguments); this._call("pause", arguments); return this; }, gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){ var ms = this.duration * percent; arrayUtil.forEach(this._animations, function(a){ a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay); }); this._call("gotoPercent", arguments); return this; }, stop: function(/*boolean?*/ gotoEnd){ this._doAction("stop", arguments); this._call("stop", arguments); return this; }, status: function(){ return this._pseudoAnimation.status(); }, destroy: function(){ this.stop(); arrayUtil.forEach(this._connects, function(handle){ handle.remove(); }); } }); lang.extend(_combine, _baseObj); coreFx.combine = function(/*dojo/_base/fx.Animation[]*/ animations){ // summary: // Combine a list of `dojo/_base/fx.Animation`s to run in parallel // // description: // Combine an array of `dojo/_base/fx.Animation`s to run in parallel, // providing a new `dojo/_base/fx.Animation` instance encompasing each // animation, firing standard animation events. // // example: // Fade out `node` while fading in `otherNode` simultaneously // | require(["dojo/fx"], function(fx){ // | fx.combine([ // | fx.fadeIn({ node:node }), // | fx.fadeOut({ node:otherNode }) // | ]).play(); // | }); // // example: // When the longest animation ends, execute a function: // | require(["dojo/fx"], function(fx){ // | var anim = fx.combine([ // | fx.fadeIn({ node: n, duration:700 }), // | fx.fadeOut({ node: otherNode, duration: 300 }) // | ]); // | aspect.after(anim, "onEnd", function(){ // | // overall animation is done. // | }, true); // | anim.play(); // play the animation // | }); // return new _combine(animations); // dojo/_base/fx.Animation }; coreFx.wipeIn = function(/*Object*/ args){ // summary: // Expand a node to it's natural height. // // description: // Returns an animation that will expand the // node defined in 'args' object from it's current height to // it's natural height (with no scrollbar). // Node must have no margin/border/padding. // // args: Object // A hash-map of standard `dojo/_base/fx.Animation` constructor properties // (such as easing: node: duration: and so on) // // example: // | require(["dojo/fx"], function(fx){ // | fx.wipeIn({ // | node:"someId" // | }).play() // | }); var node = args.node = dom.byId(args.node), s = node.style, o; var anim = baseFx.animateProperty(lang.mixin({ properties: { height: { // wrapped in functions so we wait till the last second to query (in case value has changed) start: function(){ // start at current [computed] height, but use 1px rather than 0 // because 0 causes IE to display the whole panel o = s.overflow; s.overflow = "hidden"; if(s.visibility == "hidden" || s.display == "none"){ s.height = "1px"; s.display = ""; s.visibility = ""; return 1; }else{ var height = domStyle.get(node, "height"); return Math.max(height, 1); } }, end: function(){ return node.scrollHeight; } } } }, args)); var fini = function(){ s.height = "auto"; s.overflow = o; }; aspect.after(anim, "onStop", fini, true); aspect.after(anim, "onEnd", fini, true); return anim; // dojo/_base/fx.Animation }; coreFx.wipeOut = function(/*Object*/ args){ // summary: // Shrink a node to nothing and hide it. // // description: // Returns an animation that will shrink node defined in "args" // from it's current height to 1px, and then hide it. // // args: Object // A hash-map of standard `dojo/_base/fx.Animation` constructor properties // (such as easing: node: duration: and so on) // // example: // | require(["dojo/fx"], function(fx){ // | fx.wipeOut({ node:"someId" }).play() // | }); var node = args.node = dom.byId(args.node), s = node.style, o; var anim = baseFx.animateProperty(lang.mixin({ properties: { height: { end: 1 // 0 causes IE to display the whole panel } } }, args)); aspect.after(anim, "beforeBegin", function(){ o = s.overflow; s.overflow = "hidden"; s.display = ""; }, true); var fini = function(){ s.overflow = o; s.height = "auto"; s.display = "none"; }; aspect.after(anim, "onStop", fini, true); aspect.after(anim, "onEnd", fini, true); return anim; // dojo/_base/fx.Animation }; coreFx.slideTo = function(/*Object*/ args){ // summary: // Slide a node to a new top/left position // // description: // Returns an animation that will slide "node" // defined in args Object from its current position to // the position defined by (args.left, args.top). // // args: Object // A hash-map of standard `dojo/_base/fx.Animation` constructor properties // (such as easing: node: duration: and so on). Special args members // are `top` and `left`, which indicate the new position to slide to. // // example: // | .slideTo({ node: node, left:"40", top:"50", units:"px" }).play() var node = args.node = dom.byId(args.node), top = null, left = null; var init = (function(n){ return function(){ var cs = domStyle.getComputedStyle(n); var pos = cs.position; top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0); left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0); if(pos != 'absolute' && pos != 'relative'){ var ret = geom.position(n, true); top = ret.y; left = ret.x; n.style.position="absolute"; n.style.top=top+"px"; n.style.left=left+"px"; } }; })(node); init(); var anim = baseFx.animateProperty(lang.mixin({ properties: { top: args.top || 0, left: args.left || 0 } }, args)); aspect.after(anim, "beforeBegin", init, true); return anim; // dojo/_base/fx.Animation }; return coreFx; });