dojo.provide("dojox.fx.style"); dojo.experimental("dojox.fx.style"); // // summary: dojox.fx CSS Class _Animations: // // description: a set of functions to animate properties based on // normalized CSS class definitions. // // provides: addClass, removeClass, and toggleClass // dojo.require("dojo.fx"); // FIXME: should the call signatures match dojo.addClass/removeClass/toggleClass and extend // by having a third (or fourth) param to mix in additional _Animation args for advanced // usage (delay: curve: repeat: easing: etc ... ) (function(){ var d = dojo; var _getStyleSnapshot = function(/* Object */cache){ // summary: // uses a dojo.getComputedStyle(node) cache reference and // iterates through the 'documented/supported animate-able' // properties. // // returns: Array // an array of raw, calculcated values (no keys), to be normalized/compared // elsewhere return d.map(dojox.fx._allowedProperties,function(style){ return cache[style]; // String }); // Array }; var _getCalculatedStyleChanges = function(/*dojox.fx._arg.StyleArgs*/ args, /*Boolean*/addClass){ // summary: Calculate the difference in style properties between two states // description: // calculate and normalize(?) the differences between two states // of a node (args.node) by quickly adding or removing a class, and // iterateing over the results of dojox.fx._getStyleSnapshot() // // addClass: // true to calculate what adding a class would do, // false to calculate what removing the class would do var node = args.node = d.byId(args.node); var cs = d.getComputedStyle(node); // take our snapShots var _before = _getStyleSnapshot(cs); d[(addClass ? "addClass" : "removeClass")](node, args.cssClass); var _after = _getStyleSnapshot(cs); d[(addClass ? "removeClass" : "addClass")](node, args.cssClass); var calculated = {}, i = 0; d.forEach(dojox.fx._allowedProperties,function(prop){ if(_before[i] != _after[i]){ // FIXME: the static unit: px is not good, either. need to parse unit from computed style? calculated[prop] = parseInt(_after[i]) /* start: parseInt(_before[i]), unit: 'px' */ ; } i++; }); return calculated; }; d.mixin(dojox.fx,{ addClass: function(/* dojox.fx._arg.StyleArgs */ args){ // summary: Animate the effects of adding a class to a node // description: // Creates an animation that will animate // the properties of a node to the properties // defined in a standard CSS .class definition. // (calculating the differences itself) // // example: // | // | .bar { line-height: 12px; } // | .foo { line-height: 40px; } // |
// | Multi
line
text // |
// | // | // animate to line-height:40px // | dojo.fx.addClass({ node:"test", cssClass:"foo" }).play(); // var node = args.node = d.byId(args.node); var pushClass = (function(n){ // summary: onEnd we want to add the class to the node // (as dojo.addClass naturally would) in case our // class parsing misses anything the browser would // otherwise interpret. this may cause some flicker, // and will only apply the class so children can inherit // after the animation is done (potentially more flicker) return function(){ d.addClass(n, args.cssClass); n.style.cssText = _beforeStyle; } })(node); // _getCalculatedStleChanges is the core of our style/class animations var mixedProperties = _getCalculatedStyleChanges(args,true); var _beforeStyle = node.style.cssText; var _anim = d.animateProperty(d.mixin({ properties: mixedProperties }, args)); d.connect(_anim, "onEnd", _anim,pushClass); return _anim; // dojo._Animation }, removeClass: function(/*dojox.fx._arg.StyleArgs*/ args){ // summary: Animate the effects of removing a class from a node // description: // Creates an animation that will animate the properties of a // node (args.node) to the properties calculated after removing // a standard CSS className from a that node. // // calls dojo.removeClass(args.cssClass) onEnd of animation // // standard dojo._Animation object rules apply. // // example: // | // animate the removal of "foo" from a node with id="bar" // | dojox.fx.removeClass({ // | node: "bar", // | cssClass: "foo" // | }).play(); var node = (args.node = dojo.byId(args.node)); var pullClass = (function(n){ // summary: onEnd we want to remove the class from the node // (as dojo.removeClass naturally would) in case our class // parsing misses anything the browser would otherwise // interpret. this may cause some flicker, and will only // apply the class so children can inherit after the // animation is done (potentially more flicker) // return function(){ d.removeClass(n, args.cssClass); n.style.cssText = _beforeStyle; } })(node); var mixedProperties = _getCalculatedStyleChanges(args, false); var _beforeStyle = node.style.cssText; var _anim = d.animateProperty(d.mixin({ properties: mixedProperties }, args)); d.connect(_anim, "onEnd", _anim, pullClass); return _anim; // dojo._Animation }, toggleClass: function(/*DomNode|String*/node, /*String*/cssClass, /*Boolean?*/condition){ // summary: // Animate the effects of Toggling a class on a Node // // description: // creates an animation that will animate the effect of // toggling a class on or off of a node. // Adds a class to node if not present, or removes if present. // Pass a boolean condition if you want to explicitly add or remove. // node: // The domNode (or string of the id) to toggle // cssClass: // String of the classname to add to the node // condition: // If passed, true means to add the class, false means to remove. // // example: // | // add the class "sampleClass" to a node id="theNode" // | dojox.fx.toggleClass("theNode","sampleClass",true).play(); // example: // | // toggle the class "sampleClass" on the node id="theNode" // | dojox.fx.toggleClass("theNode","sampleClass").play(); if(typeof condition == "undefined"){ condition = !d.hasClass(node, cssClass); } return dojox.fx[(condition ? "addClass" : "removeClass")]({ node: node, cssClass:cssClass }); // dojo._Animation // TODO: support 4th param animMixin to allow passing of easing and duration and other _Animtion options }, _allowedProperties: [ // summary: Our pseudo map of properties we will check for. // description: // it should be much more intuitive. a way to normalize and // "predict" intent, or even something more clever ... // open to suggestions. // no-brainers: "width", "height", // only if position = absolute || relative? "left", "top", // "right", "bottom", // these need to be filtered through dojo.colors? // "background", // normalize to: /* "backgroundImage", */ // "backgroundPosition", // FIXME: to be effective, this needs "#px #px"? "backgroundColor", "color", // "border", //"borderBottomColor", "borderBottomWidth", //"borderTopColor", "borderTopWidth", //"borderLeftColor", "borderLeftWidth", //"borderRightColor", "borderRightWidth", // "padding", // normalize to: "paddingLeft", "paddingRight", "paddingTop", "paddingBottom", // "margin", // normalize to: "marginLeft", "marginTop", "marginRight", "marginBottom", // unit import/delicate?: "lineHeight", "letterSpacing", "fontSize" ] }); })();