diff options
Diffstat (limited to 'src/ng')
| -rw-r--r-- | src/ng/animate.js | 112 | ||||
| -rw-r--r-- | src/ng/animation.js | 61 | ||||
| -rw-r--r-- | src/ng/animator.js | 446 | ||||
| -rw-r--r-- | src/ng/directive/ngClass.js | 118 | ||||
| -rwxr-xr-x | src/ng/directive/ngIf.js | 27 | ||||
| -rw-r--r-- | src/ng/directive/ngInclude.js | 14 | ||||
| -rw-r--r-- | src/ng/directive/ngRepeat.js | 34 | ||||
| -rw-r--r-- | src/ng/directive/ngShowHide.js | 64 | ||||
| -rw-r--r-- | src/ng/directive/ngSwitch.js | 26 | 
9 files changed, 253 insertions, 649 deletions
| diff --git a/src/ng/animate.js b/src/ng/animate.js new file mode 100644 index 00000000..7e515594 --- /dev/null +++ b/src/ng/animate.js @@ -0,0 +1,112 @@ +'use strict'; + +/** + * @ngdoc object + * @name ng.$animateProvider + * + * @description + * Default implementation of $animate that doesn't perform any animations, instead just synchronously performs DOM + * updates and calls done() callbacks. + * + * In order to enable animations the ngAnimate module has to be loaded. + * + * To see the functional implementation check out src/ngAnimate/animate.js + */ +var $AnimateProvider = ['$provide', function($provide) { + +  this.$$selectors = []; + + +  /** +   * @ngdoc function +   * @name ng.$animateProvider#register +   * @methodOf ng.$animateProvider +   * +   * @description +   * Registers a new injectable animation factory function. The factory function produces the animation object which +   * contains callback functions for each event that is expected to be animated. +   * +   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction` must be called once the +   *   element animation is complete. If a function is returned then the animation service will use this function to +   *   cancel the animation whenever a cancel event is triggered. +   * +   * +   *<pre> +   *   return { +     *     eventFn : function(element, done) { +     *       //code to run the animation +     *       //once complete, then run done() +     *       return function cancellationFunction() { +     *         //code to cancel the animation +     *       } +     *     } +     *   } +   *</pre> +   * +   * @param {string} name The name of the animation. +   * @param {function} factory The factory function that will be executed to return the animation object. +   */ +  this.register = function(name, factory) { +    var classes = name.substr(1).split('.'); +    name += '-animation'; +    this.$$selectors.push({ +      selectors : classes, +      name : name +    }); +    $provide.factory(name, factory); +  }; + +  this.$get = function() { +    return { +      enter : function(element, parent, after, done) { +        var afterNode = after && after[after.length - 1]; +        var parentNode = parent && parent[0] || afterNode && afterNode.parentNode; +        // IE does not like undefined so we have to pass null. +        var afterNextSibling = (afterNode && afterNode.nextSibling) || null; +        forEach(element, function(node) { +          parentNode.insertBefore(node, afterNextSibling); +        }); +        (done || noop)(); +      }, + +      leave : function(element, done) { +        element.remove(); +        (done || noop)(); +      }, + +      move : function(element, parent, after, done) { +        // Do not remove element before insert. Removing will cause data associated with the +        // element to be dropped. Insert will implicitly do the remove. +        this.enter(element, parent, after, done); +      }, + +      show : function(element, done) { +        element.removeClass('ng-hide'); +        (done || noop)(); +      }, + +      hide : function(element, done) { +        element.addClass('ng-hide'); +        (done || noop)(); +      }, + +      addClass : function(element, className, done) { +        className = isString(className) ? +                      className : +                      isArray(className) ? className.join(' ') : ''; +        element.addClass(className); +        (done || noop)(); +      }, + +      removeClass : function(element, className, done) { +        className = isString(className) ? +                      className : +                      isArray(className) ? className.join(' ') : ''; +        element.removeClass(className); +        (done || noop)(); +      }, + +      enabled : noop +    }; +  }; +}]; diff --git a/src/ng/animation.js b/src/ng/animation.js deleted file mode 100644 index faed84ca..00000000 --- a/src/ng/animation.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @ngdoc object - * @name ng.$animationProvider - * @description - * - * The $AnimationProvider provider allows developers to register and access custom JavaScript animations directly inside - * of a module. - * - */ -$AnimationProvider.$inject = ['$provide']; -function $AnimationProvider($provide) { -  var suffix = 'Animation'; - -  /** -   * @ngdoc function -   * @name ng.$animation#register -   * @methodOf ng.$animationProvider -   * -   * @description -   * Registers a new injectable animation factory function. The factory function produces the animation object which -   * has these two properties: -   * -   *   * `setup`: `function(Element):*` A function which receives the starting state of the element. The purpose -   *   of this function is to get the element ready for animation. Optionally the function returns an memento which -   *   is passed to the `start` function. -   *   * `start`: `function(Element, doneFunction, *)` The element to animate, the `doneFunction` to be called on -   *   element animation completion, and an optional memento from the `setup` function. -   * -   * @param {string} name The name of the animation. -   * @param {function} factory The factory function that will be executed to return the animation object. -   *  -   */ -  this.register = function(name, factory) { -    $provide.factory(camelCase(name) + suffix, factory); -  }; - -  this.$get = ['$injector', function($injector) { -    /** -     * @ngdoc function -     * @name ng.$animation -     * @function -     * -     * @description -     * The $animation service is used to retrieve any defined animation functions. When executed, the $animation service -     * will return a object that contains the setup and start functions that were defined for the animation. -     * -     * @param {String} name Name of the animation function to retrieve. Animation functions are registered and stored -     *        inside of the AngularJS DI so a call to $animate('custom') is the same as injecting `customAnimation` -     *        via dependency injection. -     * @return {Object} the animation object which contains the `setup` and `start` functions that perform the animation. -     */ -    return function $animation(name) { -      if (name) { -        var animationName = camelCase(name) + suffix; -        if ($injector.has(animationName)) { -          return $injector.get(animationName); -        } -      } -    }; -  }]; -} diff --git a/src/ng/animator.js b/src/ng/animator.js deleted file mode 100644 index a9ea5743..00000000 --- a/src/ng/animator.js +++ /dev/null @@ -1,446 +0,0 @@ -'use strict'; - -// NOTE: this is a pseudo directive. - -/** - * @ngdoc directive - * @name ng.directive:ngAnimate - * - * @description - * The `ngAnimate` directive works as an attribute that is attached alongside pre-existing directives. - * It effects how the directive will perform DOM manipulation. This allows for complex animations to take place - * without burdening the directive which uses the animation with animation details. The built in directives - * `ngRepeat`, `ngInclude`, `ngSwitch`, `ngShow`, `ngHide` and `ngView` already accept `ngAnimate` directive. - * Custom directives can take advantage of animation through {@link ng.$animator $animator service}. - * - * Below is a more detailed breakdown of the supported callback events provided by pre-exisitng ng directives: - * - * | Directive                                                 | Supported Animations                               | - * |---------------------------------------------------------- |----------------------------------------------------| - * | {@link ng.directive:ngRepeat#animations ngRepeat}         | enter, leave and move                              | - * | {@link ngRoute.directive:ngView#animations ngView}        | enter and leave                                    | - * | {@link ng.directive:ngInclude#animations ngInclude}       | enter and leave                                    | - * | {@link ng.directive:ngSwitch#animations ngSwitch}         | enter and leave                                    | - * | {@link ng.directive:ngIf#animations ngIf}                 | enter and leave                                    | - * | {@link ng.directive:ngShow#animations ngShow & ngHide}    | show and hide                                      | - * - * You can find out more information about animations upon visiting each directive page. - * - * Below is an example of a directive that makes use of the ngAnimate attribute: - * - * <pre> - * <!-- you can also use data-ng-animate, ng:animate or x-ng-animate as well --> - * <ANY ng-directive ng-animate="{event1: 'animation-name', event2: 'animation-name-2'}"></ANY> - * - * <!-- you can also use a short hand --> - * //!annotate="animation" ngAnimate|This *expands* to `{ enter: 'animation-enter', leave: 'animation-leave', ...}`</strong> - * <ANY ng-directive ng-animate=" 'animation' "></ANY> - * - * <!-- keep in mind that ng-animate can take expressions --> - * //!annotate="computeCurrentAnimation\(\)" Scope Function|This will be called each time the scope changes... - * <ANY ng-directive ng-animate=" computeCurrentAnimation() "></ANY> - * </pre> - * - * The `event1` and `event2` attributes refer to the animation events specific to the directive that has been assigned. - * - * Keep in mind that if an animation is running, no child element of such animation can also be animated. - * - * <h2>CSS-defined Animations</h2> - * By default, ngAnimate attaches two CSS classes per animation event to the DOM element to achieve the animation. - * It is up to you, the developer, to ensure that the animations take place using cross-browser CSS3 transitions as - * well as CSS animations. - * - * The following code below demonstrates how to perform animations using **CSS transitions** with ngAnimate: - * - * <pre> - * <style type="text/css"> - * /* - *  The animate-enter CSS class is the event name that you - *  have provided within the ngAnimate attribute. - * */ - * .animate-enter { - *  -webkit-transition: 1s linear all; /* Safari/Chrome */ - *  -moz-transition: 1s linear all; /* Firefox */ - *  -o-transition: 1s linear all; /* Opera */ - *  transition: 1s linear all; /* IE10+ and Future Browsers */ - * - *  /* The animation preparation code */ - *  opacity: 0; - * } - * - * /* - *  Keep in mind that you want to combine both CSS - *  classes together to avoid any CSS-specificity - *  conflicts - * */ - * .animate-enter.animate-enter-active { - *  /* The animation code itself */ - *  opacity: 1; - * } - * </style> - * - * <div ng-directive ng-animate="{enter: 'animate-enter'}"></div> - * </pre> - * - * The following code below demonstrates how to perform animations using **CSS animations** with ngAnimate: - * - * <pre> - * <style type="text/css"> - * .animate-enter { - *   -webkit-animation: enter_sequence 1s linear; /* Safari/Chrome */ - *   -moz-animation: enter_sequence 1s linear; /* Firefox */ - *   -o-animation: enter_sequence 1s linear; /* Opera */ - *   animation: enter_sequence 1s linear; /* IE10+ and Future Browsers */ - * } - * @-webkit-keyframes enter_sequence { - *   from { opacity:0; } - *   to { opacity:1; } - * } - * @-moz-keyframes enter_sequence { - *   from { opacity:0; } - *   to { opacity:1; } - * } - * @-o-keyframes enter_sequence { - *   from { opacity:0; } - *   to { opacity:1; } - * } - * @keyframes enter_sequence { - *   from { opacity:0; } - *   to { opacity:1; } - * } - * </style> - * - * <div ng-directive ng-animate="{enter: 'animate-enter'}"></div> - * </pre> - * - * ngAnimate will first examine any CSS animation code and then fallback to using CSS transitions. - * - * Upon DOM mutation, the event class is added first, then the browser is allowed to reflow the content and then, - * the active class is added to trigger the animation. The ngAnimate directive will automatically extract the duration - * of the animation to determine when the animation ends. Once the animation is over then both CSS classes will be - * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end - * immediately resulting in a DOM element that is at it's final state. This final state is when the DOM element - * has no CSS transition/animation classes surrounding it. - * - * <h2>JavaScript-defined Animations</h2> - * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations to browsers that do not - * yet support them, then you can make use of JavaScript animations defined inside of your AngularJS module. - * - * <pre> - * var ngModule = angular.module('YourApp', []); - * ngModule.animation('animate-enter', function() { - *   return { - *     setup : function(element) { - *       //prepare the element for animation - *       element.css({ 'opacity': 0 }); - *       var memo = "..."; //this value is passed to the start function - *       return memo; - *     }, - *     start : function(element, done, memo) { - *       //start the animation - *       element.animate({ - *         'opacity' : 1 - *       }, function() { - *         //call when the animation is complete - *         done() - *       }); - *     } - *   } - * }); - * </pre> - * - * As you can see, the JavaScript code follows a similar template to the CSS3 animations. Once defined, the animation - * can be used in the same way with the ngAnimate attribute. Keep in mind that, when using JavaScript-enabled - * animations, ngAnimate will also add in the same CSS classes that CSS-enabled animations do (even if you're not using - * CSS animations) to animated the element, but it will not attempt to find any CSS3 transition or animation duration/delay values. - * It will instead close off the animation once the provided done function is executed. So it's important that you - * make sure your animations remember to fire off the done function once the animations are complete. - * - * @param {expression} ngAnimate Used to configure the DOM manipulation animations. - * - */ - -var $AnimatorProvider = function() { -  var NG_ANIMATE_CONTROLLER = '$ngAnimateController'; -  var rootAnimateController = {running:true}; - -  this.$get = ['$animation', '$window', '$sniffer', '$rootElement', '$rootScope', -      function($animation, $window, $sniffer, $rootElement, $rootScope) { -    $rootElement.data(NG_ANIMATE_CONTROLLER, rootAnimateController); - -    /** -     * @ngdoc function -     * @name ng.$animator -     * @function -     * -     * @description -     * The $animator.create service provides the DOM manipulation API which is decorated with animations. -     * -     * @param {Scope} scope the scope for the ng-animate. -     * @param {Attributes} attr the attributes object which contains the ngAnimate key / value pair. (The attributes are -     *        passed into the linking function of the directive using the `$animator`.) -     * @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods. -     */ -     var AnimatorService = function(scope, attrs) { -        var animator = {}; - -        /** -         * @ngdoc function -         * @name ng.animator#enter -         * @methodOf ng.$animator -         * @function -         * -         * @description -         * Injects the element object into the DOM (inside of the parent element) and then runs the enter animation. -         * -         * @param {jQuery/jqLite element} element the element that will be the focus of the enter animation -         * @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the enter animation -         * @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the enter animation -        */ -        animator.enter = animateActionFactory('enter', insert, noop); - -        /** -         * @ngdoc function -         * @name ng.animator#leave -         * @methodOf ng.$animator -         * @function -         * -         * @description -         * Runs the leave animation operation and, upon completion, removes the element from the DOM. -         * -         * @param {jQuery/jqLite element} element the element that will be the focus of the leave animation -         * @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the leave animation -        */ -        animator.leave = animateActionFactory('leave', noop, remove); - -        /** -         * @ngdoc function -         * @name ng.animator#move -         * @methodOf ng.$animator -         * @function -         * -         * @description -         * Fires the move DOM operation. Just before the animation starts, the animator will either append it into the parent container or -         * add the element directly after the after element if present. Then the move animation will be run. -         * -         * @param {jQuery/jqLite element} element the element that will be the focus of the move animation -         * @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the move animation -         * @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the move animation -        */ -        animator.move = animateActionFactory('move', move, noop); - -        /** -         * @ngdoc function -         * @name ng.animator#show -         * @methodOf ng.$animator -         * @function -         * -         * @description -         * Reveals the element by setting the CSS property `display` to `block` and then starts the show animation directly after. -         * -         * @param {jQuery/jqLite element} element the element that will be rendered visible or hidden -        */ -        animator.show = animateActionFactory('show', show, noop); - -        /** -         * @ngdoc function -         * @name ng.animator#hide -         * @methodOf ng.$animator -         * -         * @description -         * Starts the hide animation first and sets the CSS `display` property to `none` upon completion. -         * -         * @param {jQuery/jqLite element} element the element that will be rendered visible or hidden -        */ -        animator.hide = animateActionFactory('hide', noop, hide); - -        /** -         * @ngdoc function -         * @name ng.animator#animate -         * @methodOf ng.$animator -         * -         * @description -         * Triggers a custom animation event to be executed on the given element -         * -         * @param {string} event the name of the custom event -         * @param {jQuery/jqLite element} element the element that will be animated -        */ -        animator.animate = function(event, element) { -          animateActionFactory(event, noop, noop)(element); -        } -        return animator; - -        function animateActionFactory(type, beforeFn, afterFn) { -          return function(element, parent, after) { -            var ngAnimateValue = scope.$eval(attrs.ngAnimate); -            var className = ngAnimateValue -                ? isObject(ngAnimateValue) ? ngAnimateValue[type] : ngAnimateValue + '-' + type -                : ''; -            var animationPolyfill = $animation(className); -            var polyfillSetup = animationPolyfill && animationPolyfill.setup; -            var polyfillStart = animationPolyfill && animationPolyfill.start; -            var polyfillCancel = animationPolyfill && animationPolyfill.cancel; - -            if (!className) { -              beforeFn(element, parent, after); -              afterFn(element, parent, after); -            } else { -              var activeClassName = className + '-active'; - -              if (!parent) { -                parent = after ? after.parent() : element.parent(); -              } -              var disabledAnimation = { running : true }; -              if ((!$sniffer.transitions && !polyfillSetup && !polyfillStart) || -                  (parent.inheritedData(NG_ANIMATE_CONTROLLER) || disabledAnimation).running) { -                beforeFn(element, parent, after); -                afterFn(element, parent, after); -                return; -              } - -              var animationData = element.data(NG_ANIMATE_CONTROLLER) || {}; -              if(animationData.running) { -                (polyfillCancel || noop)(element); -                animationData.done(); -              } - -              element.data(NG_ANIMATE_CONTROLLER, {running:true, done:done}); -              element.addClass(className); -              beforeFn(element, parent, after); -              if (element.length == 0) return done(); - -              var memento = (polyfillSetup || noop)(element); - -              // $window.setTimeout(beginAnimation, 0); this was causing the element not to animate -              // keep at 1 for animation dom rerender -              $window.setTimeout(beginAnimation, 1); -            } - -            function parseMaxTime(str) { -              var total = 0, values = isString(str) ? str.split(/\s*,\s*/) : []; -              forEach(values, function(value) { -                total = Math.max(parseFloat(value) || 0, total); -              }); -              return total; -            } - -            function beginAnimation() { -              element.addClass(activeClassName); -              if (polyfillStart) { -                polyfillStart(element, done, memento); -              } else if (isFunction($window.getComputedStyle)) { -                //one day all browsers will have these properties -                var w3cAnimationProp = 'animation'; -                var w3cTransitionProp = 'transition'; - -                //but some still use vendor-prefixed styles -                var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation'; -                var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; - -                var durationKey = 'Duration', -                    delayKey = 'Delay', -                    animationIterationCountKey = 'IterationCount', -                    duration = 0; - -                //we want all the styles defined before and after -                var ELEMENT_NODE = 1; -                forEach(element, function(element) { -                  if (element.nodeType == ELEMENT_NODE) { -                    var elementStyles = $window.getComputedStyle(element) || {}; - -                    var transitionDelay     = Math.max(parseMaxTime(elementStyles[w3cTransitionProp     + delayKey]), -                                                       parseMaxTime(elementStyles[vendorTransitionProp  + delayKey])); - -                    var animationDelay      = Math.max(parseMaxTime(elementStyles[w3cAnimationProp      + delayKey]), -                                                       parseMaxTime(elementStyles[vendorAnimationProp   + delayKey])); - -                    var transitionDuration  = Math.max(parseMaxTime(elementStyles[w3cTransitionProp     + durationKey]), -                                                       parseMaxTime(elementStyles[vendorTransitionProp  + durationKey])); - -                    var animationDuration   = Math.max(parseMaxTime(elementStyles[w3cAnimationProp      + durationKey]), -                                                       parseMaxTime(elementStyles[vendorAnimationProp   + durationKey])); - -                    if(animationDuration > 0) { -                      animationDuration *= Math.max(parseInt(elementStyles[w3cAnimationProp    + animationIterationCountKey]) || 0, -                                                   parseInt(elementStyles[vendorAnimationProp + animationIterationCountKey]) || 0, -                                                   1); -                    } - -                    duration = Math.max(animationDelay  + animationDuration, -                                        transitionDelay + transitionDuration, -                                        duration); -                  } -                }); -                $window.setTimeout(done, duration * 1000); -              } else { -                done(); -              } -            } - -            function done() { -              if(!done.run) { -                done.run = true; -                afterFn(element, parent, after); -                element.removeClass(className); -                element.removeClass(activeClassName); -                element.removeData(NG_ANIMATE_CONTROLLER); -              } -            } -          }; -        } - -        function show(element) { -          element.css('display', ''); -        } - -        function hide(element) { -          element.css('display', 'none'); -        } - -        function insert(element, parent, after) { -          var afterNode = after && after[after.length - 1]; -          var parentNode = parent && parent[0] || afterNode && afterNode.parentNode; -          var afterNextSibling = afterNode && afterNode.nextSibling; -          forEach(element, function(node) { -            if (afterNextSibling) { -              parentNode.insertBefore(node, afterNextSibling); -            } else { -              parentNode.appendChild(node); -            } -          }); -        } - -        function remove(element) { -          element.remove(); -        } - -        function move(element, parent, after) { -          // Do not remove element before insert. Removing will cause data associated with the -          // element to be dropped. Insert will implicitly do the remove. -          insert(element, parent, after); -        } -      }; - -    /** -     * @ngdoc function -     * @name ng.animator#enabled -     * @methodOf ng.$animator -     * @function -     * -     * @param {Boolean=} If provided then set the animation on or off. -     * @return {Boolean} Current animation state. -     * -     * @description -     * Globally enables/disables animations. -     * -    */ -    AnimatorService.enabled = function(value) { -      if (arguments.length) { -        rootAnimateController.running = !value; -      } -      return !rootAnimateController.running; -    }; - -    return AnimatorService; -  }]; -}; diff --git a/src/ng/directive/ngClass.js b/src/ng/directive/ngClass.js index 75e35a1e..a5b2acb6 100644 --- a/src/ng/directive/ngClass.js +++ b/src/ng/directive/ngClass.js @@ -2,59 +2,72 @@  function classDirective(name, selector) {    name = 'ngClass' + name; -  return ngDirective(function(scope, element, attr) { -    var oldVal = undefined; - -    scope.$watch(attr[name], ngClassWatchAction, true); - -    attr.$observe('class', function(value) { -      var ngClass = scope.$eval(attr[name]); -      ngClassWatchAction(ngClass, ngClass); -    }); +  return ['$animate', function($animate) { +    return { +      restrict: 'AC', +      link: function(scope, element, attr) { +        var oldVal = undefined; + +        scope.$watch(attr[name], ngClassWatchAction, true); + +        attr.$observe('class', function(value) { +          var ngClass = scope.$eval(attr[name]); +          ngClassWatchAction(ngClass, ngClass); +        }); + + +        if (name !== 'ngClass') { +          scope.$watch('$index', function($index, old$index) { +            var mod = $index & 1; +            if (mod !== old$index & 1) { +              if (mod === selector) { +                addClass(scope.$eval(attr[name])); +              } else { +                removeClass(scope.$eval(attr[name])); +              } +            } +          }); +        } -    if (name !== 'ngClass') { -      scope.$watch('$index', function($index, old$index) { -        var mod = $index & 1; -        if (mod !== old$index & 1) { -          if (mod === selector) { -            addClass(scope.$eval(attr[name])); -          } else { -            removeClass(scope.$eval(attr[name])); +        function ngClassWatchAction(newVal) { +          if (selector === true || scope.$index % 2 === selector) { +            if (oldVal && !equals(newVal,oldVal)) { +              removeClass(oldVal); +            } +            addClass(newVal);            } +          oldVal = copy(newVal);          } -      }); -    } -    function ngClassWatchAction(newVal) { -      if (selector === true || scope.$index % 2 === selector) { -        if (oldVal && !equals(newVal,oldVal)) { -          removeClass(oldVal); +        function removeClass(classVal) { +          $animate.removeClass(element, flattenClasses(classVal));          } -        addClass(newVal); -      } -      oldVal = copy(newVal); -    } -    function removeClass(classVal) { -      if (isObject(classVal) && !isArray(classVal)) { -        classVal = map(classVal, function(v, k) { if (v) return k }); -      } -      element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal); -    } +        function addClass(classVal) { +          $animate.addClass(element, flattenClasses(classVal)); +        } +        function flattenClasses(classVal) { +          if(isArray(classVal)) { +            return classVal.join(' '); +          } else if (isObject(classVal)) { +            var classes = [], i = 0; +            forEach(classVal, function(v, k) { +              if (v) { +                classes.push(k); +              } +            }); +            return classes.join(' '); +          } -    function addClass(classVal) { -      if (isObject(classVal) && !isArray(classVal)) { -        classVal = map(classVal, function(v, k) { if (v) return k }); +          return classVal; +        };        } -      if (classVal) { -        element.addClass(isArray(classVal) ? classVal.join(' ') : classVal); -      } -    } -  }); +    }; +  }];  }  /** @@ -70,6 +83,10 @@ function classDirective(name, selector) {   * When the expression changes, the previously added classes are removed and only then the   * new classes are added.   * + * @animations + * add - happens just before the class is applied to the element + * remove - happens just before the class is removed from the element + *   * @element ANY   * @param {expression} ngClass {@link guide/expression Expression} to eval. The result   *   of the evaluation can be a string representing space delimited class @@ -78,7 +95,7 @@ function classDirective(name, selector) {   *   element.   *   * @example -   <example> +   <example animations="true">       <file name="index.html">        <input type="button" value="set" ng-click="myVar='my-class'">        <input type="button" value="clear" ng-click="myVar=''"> @@ -86,8 +103,23 @@ function classDirective(name, selector) {        <span ng-class="myVar">Sample Text</span>       </file>       <file name="style.css"> -       .my-class { +       .my-class-add, +       .my-class-remove { +         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; +         -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; +         -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; +         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; +       } + +       .my-class, +       .my-class-add.my-class-add-active {           color: red; +         font-size:3em; +       } + +       .my-class-remove.my-class-remove-active { +         font-size:1.0em; +         color:black;         }       </file>       <file name="scenario.js"> diff --git a/src/ng/directive/ngIf.js b/src/ng/directive/ngIf.js index c8166ee5..9d99d859 100755 --- a/src/ng/directive/ngIf.js +++ b/src/ng/directive/ngIf.js @@ -30,7 +30,7 @@   * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element   * the added class will be lost because the original compiled state is used to regenerate the element.   * - * Additionally, you can provide animations via the ngAnimate attribute to animate the **enter** + * Additionally, you can provide animations via the ngAnimate module to animate the **enter**   * and **leave** effects.   *   * @animations @@ -47,36 +47,32 @@      <file name="index.html">        Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>        Show when checked: -      <span ng-if="checked" ng-animate="'example'"> +      <span ng-if="checked" class="example-if">          I'm removed when the checkbox is unchecked.        </span>      </file>      <file name="animations.css"> -      .example-leave, .example-enter { +      .example-if.ng-enter, +      .example-if.ng-leave {          -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;          -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; -        -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;          -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;        } -      .example-enter { +      .example-if.ng-enter, +      .example-if.ng-leave.ng-leave-active {          opacity:0;        } -      .example-enter.example-enter-active { -        opacity:1; -      } -      .example-leave { +      .example-if.ng-enter.ng-enter-active, +      .example-if.ng-leave {          opacity:1;        } -      .example-leave.example-leave-active { -        opacity:0; -      }      </file>    </example>   */ -var ngIfDirective = ['$animator', function($animator) { +var ngIfDirective = ['$animate', function($animate) {    return {      transclude: 'element',      priority: 1000, @@ -84,11 +80,10 @@ var ngIfDirective = ['$animator', function($animator) {      restrict: 'A',      compile: function (element, attr, transclude) {        return function ($scope, $element, $attr) { -        var animate = $animator($scope, $attr);          var childElement, childScope;          $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {            if (childElement) { -            animate.leave(childElement); +            $animate.leave(childElement);              childElement = undefined;            }            if (childScope) { @@ -99,7 +94,7 @@ var ngIfDirective = ['$animator', function($animator) {              childScope = $scope.$new();              transclude(childScope, function (clone) {                childElement = clone; -              animate.enter(clone, $element.parent(), $element); +              $animate.enter(clone, $element.parent(), $element);              });            }          }); diff --git a/src/ng/directive/ngInclude.js b/src/ng/directive/ngInclude.js index 72b5af08..d5ed1fc5 100644 --- a/src/ng/directive/ngInclude.js +++ b/src/ng/directive/ngInclude.js @@ -23,9 +23,6 @@   *      (e.g.  ngInclude won't work for cross-domain requests on all browsers and for `file://`   *      access on some browsers)   * - * Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter** - * and **leave** effects. - *   * @animations   * enter - happens just after the ngInclude contents change and a new DOM element is created and injected into the ngInclude container   * leave - happens just after the ngInclude contents change and just before the former contents are removed from the DOM @@ -143,8 +140,8 @@   * @description   * Emitted every time the ngInclude content is reloaded.   */ -var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animator', '$sce', -                  function($http,   $templateCache,   $anchorScroll,   $compile,   $animator,   $sce) { +var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animate', '$sce', +                  function($http,   $templateCache,   $anchorScroll,   $compile,   $animate,   $sce) {    return {      restrict: 'ECA',      terminal: true, @@ -154,7 +151,6 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'            autoScrollExp = attr.autoscroll;        return function(scope, element, attr) { -        var animate = $animator(scope, attr);          var changeCounter = 0,              childScope; @@ -163,7 +159,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'              childScope.$destroy();              childScope = null;            } -          animate.leave(element.contents(), element); +          $animate.leave(element.contents());          };          scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) { @@ -175,11 +171,11 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'                if (childScope) childScope.$destroy();                childScope = scope.$new(); -              animate.leave(element.contents(), element); +              $animate.leave(element.contents());                var contents = jqLite('<div/>').html(response).contents(); -              animate.enter(contents, element); +              $animate.enter(contents, element);                $compile(contents)(childScope);                if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { diff --git a/src/ng/directive/ngRepeat.js b/src/ng/directive/ngRepeat.js index e0b2cb38..8f12b7c2 100644 --- a/src/ng/directive/ngRepeat.js +++ b/src/ng/directive/ngRepeat.js @@ -20,9 +20,6 @@   * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |   * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |   * - * Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter**, - * **leave** and **move** effects. - *   *   * # Special repeat start and end points   * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending @@ -131,46 +128,40 @@          I have {{friends.length}} friends. They are:          <input type="search" ng-model="q" placeholder="filter friends..." />          <ul> -          <li ng-repeat="friend in friends | filter:q" -              ng-animate="{enter: 'example-repeat-enter', -                          leave: 'example-repeat-leave', -                          move: 'example-repeat-move'}"> +          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">              [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.            </li>          </ul>        </div>      </file>      <file name="animations.css"> -      .example-repeat-enter, -      .example-repeat-leave, -      .example-repeat-move { +      .animate-repeat {          -webkit-transition:all linear 0.5s;          -moz-transition:all linear 0.5s; -        -ms-transition:all linear 0.5s;          -o-transition:all linear 0.5s;          transition:all linear 0.5s;        } -      .example-repeat-enter { +      .animate-repeat.ng-enter {          line-height:0;          opacity:0;        } -      .example-repeat-enter.example-repeat-enter-active { +      .animate-repeat.ng-enter.ng-enter-active {          line-height:20px;          opacity:1;        } -      .example-repeat-leave { +      .animate-repeat.ng-leave {          opacity:1;          line-height:20px;        } -      .example-repeat-leave.example-repeat-leave-active { +      .animate-repeat.ng-leave.ng-leave-active {          opacity:0;          line-height:0;        } -      .example-repeat-move { } -      .example-repeat-move.example-repeat-move-active { } +      .animate-repeat.ng-move { } +      .animate-repeat.ng-move.ng-move-active { }      </file>      <file name="scenario.js">         it('should render initial data set', function() { @@ -195,7 +186,7 @@        </file>      </example>   */ -var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) { +var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {    var NG_REMOVED = '$$NG_REMOVED';    var ngRepeatMinErr = minErr('ngRepeat');    return { @@ -204,7 +195,6 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {      terminal: true,      compile: function(element, attr, linker) {        return function($scope, $element, $attr){ -        var animate = $animator($scope, $attr);          var expression = $attr.ngRepeat;          var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),            trackByExp, trackByExpGetter, trackByIdFn, trackByIdArrayFn, trackByIdObjFn, lhs, rhs, valueIdentifier, keyIdentifier, @@ -316,7 +306,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {            for (key in lastBlockMap) {              if (lastBlockMap.hasOwnProperty(key)) {                block = lastBlockMap[key]; -              animate.leave(block.elements); +              $animate.leave(block.elements);                forEach(block.elements, function(element) { element[NG_REMOVED] = true});                block.scope.$destroy();              } @@ -342,7 +332,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {                  // do nothing                } else {                  // existing item which got moved -                animate.move(block.elements, null, jqLite(previousNode)); +                $animate.move(block.elements, null, jqLite(previousNode));                }                previousNode = block.endNode;              } else { @@ -360,7 +350,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {              if (!block.startNode) {                linker(childScope, function(clone) { -                animate.enter(clone, null, jqLite(previousNode)); +                $animate.enter(clone, null, jqLite(previousNode));                  previousNode = clone;                  block.scope = childScope;                  block.startNode = clone[0]; diff --git a/src/ng/directive/ngShowHide.js b/src/ng/directive/ngShowHide.js index 7ef7008c..bdbcf463 100644 --- a/src/ng/directive/ngShowHide.js +++ b/src/ng/directive/ngShowHide.js @@ -12,8 +12,6 @@   * With ngHide this is the reverse whereas true values cause the element itself to become   * hidden.   * - * Additionally, you can also provide animations via the ngAnimate attribute to animate the **show** - * and **hide** effects.   *   * @animations   * show - happens after the ngShow expression evaluates to a truthy value and the contents are set to visible @@ -29,36 +27,37 @@        Click me: <input type="checkbox" ng-model="checked"><br/>        <div>          Show: -        <span class="check-element" -              ng-show="checked" -              ng-animate="{show: 'example-show', hide: 'example-hide'}"> +        <span class="check-element example-show-hide" ng-show="checked">            <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.          </span>        </div>        <div>          Hide: -        <span class="check-element" -              ng-hide="checked" -              ng-animate="{show: 'example-show', hide: 'example-hide'}"> +        <span class="check-element example-show-hide" ng-hide="checked">            <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.          </span>        </div>      </file>      <file name="animations.css"> -      .example-show, .example-hide { +      .example-show-hide {          -webkit-transition:all linear 0.5s;          -moz-transition:all linear 0.5s;          -ms-transition:all linear 0.5s;          -o-transition:all linear 0.5s;          transition:all linear 0.5s; +        display:block; +      } +      .example-show-hide.ng-hide { +        display:none;        } -      .example-show { +      .example-show-hide.ng-hide-remove { +        display:block;          line-height:0;          opacity:0;          padding:0 10px;        } -      .example-show-active.example-show-active { +      .example-show-hide.ng-hide-remove.ng-hide-remove-active {          line-height:20px;          opacity:1;          padding:10px; @@ -66,14 +65,14 @@          background:white;        } -      .example-hide { +      .example-show-hide.ng-hide-add {          line-height:20px;          opacity:1;          padding:10px;          border:1px solid black;          background:white;        } -      .example-hide-active.example-hide-active { +      .example-show-hide.ng-hide-add.ng-hide-add-active {          line-height:0;          opacity:0;          padding:0 10px; @@ -98,12 +97,10 @@      </file>    </example>   */ -//TODO(misko): refactor to remove element from the DOM -var ngShowDirective = ['$animator', function($animator) { +var ngShowDirective = ['$animate', function($animate) {    return function(scope, element, attr) { -    var animate = $animator(scope, attr);      scope.$watch(attr.ngShow, function ngShowWatchAction(value){ -      animate[toBoolean(value) ? 'show' : 'hide'](element); +      $animate[toBoolean(value) ? 'show' : 'hide'](element);      });    };  }]; @@ -121,9 +118,6 @@ var ngShowDirective = ['$animator', function($animator) {   * With ngHide this is the reverse whereas true values cause the element itself to become   * hidden.   * - * Additionally, you can also provide animations via the ngAnimate attribute to animate the **show** - * and **hide** effects. - *   * @animations   * show - happens after the ngHide expression evaluates to a non truthy value and the contents are set to visible   * hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden @@ -138,36 +132,36 @@ var ngShowDirective = ['$animator', function($animator) {        Click me: <input type="checkbox" ng-model="checked"><br/>        <div>          Show: -        <span class="check-element" -              ng-show="checked" -              ng-animate="{show: 'example-show', hide: 'example-hide'}"> +        <span class="check-element example-show-hide" ng-show="checked">            <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.          </span>        </div>        <div>          Hide: -        <span class="check-element" -              ng-hide="checked" -              ng-animate="{show: 'example-show', hide: 'example-hide'}"> +        <span class="check-element example-show-hide" ng-hide="checked">            <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.          </span>        </div>      </file>      <file name="animations.css"> -      .example-show, .example-hide { +      .example-show-hide {          -webkit-transition:all linear 0.5s;          -moz-transition:all linear 0.5s; -        -ms-transition:all linear 0.5s;          -o-transition:all linear 0.5s;          transition:all linear 0.5s; +        display:block; +      } +      .example-show-hide.ng-hide { +        display:none;        } -      .example-show { +      .example-show-hide.ng-hide-remove { +        display:block;          line-height:0;          opacity:0;          padding:0 10px;        } -      .example-show.example-show-active { +      .example-show-hide.ng-hide-remove.ng-hide-remove-active {          line-height:20px;          opacity:1;          padding:10px; @@ -175,14 +169,14 @@ var ngShowDirective = ['$animator', function($animator) {          background:white;        } -      .example-hide { +      .example-show-hide.ng-hide-add {          line-height:20px;          opacity:1;          padding:10px;          border:1px solid black;          background:white;        } -      .example-hide.example-hide-active { +      .example-show-hide.ng-hide-add.ng-hide-add-active {          line-height:0;          opacity:0;          padding:0 10px; @@ -207,12 +201,10 @@ var ngShowDirective = ['$animator', function($animator) {      </file>    </example>   */ -//TODO(misko): refactor to remove element from the DOM -var ngHideDirective = ['$animator', function($animator) { +var ngHideDirective = ['$animate', function($animate) {    return function(scope, element, attr) { -    var animate = $animator(scope, attr);      scope.$watch(attr.ngHide, function ngHideWatchAction(value){ -      animate[toBoolean(value) ? 'hide' : 'show'](element); +      $animate[toBoolean(value) ? 'hide' : 'show'](element);      });    };  }]; diff --git a/src/ng/directive/ngSwitch.js b/src/ng/directive/ngSwitch.js index f36e651c..38a123a2 100644 --- a/src/ng/directive/ngSwitch.js +++ b/src/ng/directive/ngSwitch.js @@ -19,9 +19,6 @@   * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default   * attribute is displayed.   * - * Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter** - * and **leave** effects. - *   * @animations   * enter - happens after the ngSwtich contents change and the matched child element is placed inside the container   * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM @@ -55,9 +52,8 @@          <tt>selection={{selection}}</tt>          <hr/>          <div -          class="example-animate-container" -          ng-switch on="selection" -          ng-animate="{enter: 'example-enter', leave: 'example-leave'}"> +          class="example-animate-container animate-switch" +          ng-switch on="selection">              <div ng-switch-when="settings">Settings Div</div>              <div ng-switch-when="home">Home Span</div>              <div ng-switch-default>default</div> @@ -71,10 +67,9 @@        }      </file>      <file name="animations.css"> -      .example-leave, .example-enter { +      .animate-switch > * {          -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;          -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; -        -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;          -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; @@ -90,17 +85,17 @@          padding:10px;        } -      .example-enter { +      .animate-switch > .ng-enter {          top:-50px;        } -      .example-enter.example-enter-active { +      .animate-switch > .ng-enter.ng-enter-active {          top:0;        } -      .example-leave { +      .animate-switch > .ng-leave {          top:0;        } -      .example-leave.example-leave-active { +      .animate-switch > .ng-leave.ng-leave-active {          top:50px;        }      </file> @@ -119,7 +114,7 @@      </file>    </example>   */ -var ngSwitchDirective = ['$animator', function($animator) { +var ngSwitchDirective = ['$animate', function($animate) {    return {      restrict: 'EA',      require: 'ngSwitch', @@ -129,7 +124,6 @@ var ngSwitchDirective = ['$animator', function($animator) {       this.cases = {};      }],      link: function(scope, element, attr, ngSwitchController) { -      var animate = $animator(scope, attr);        var watchExpr = attr.ngSwitch || attr.on,            selectedTranscludes,            selectedElements, @@ -138,7 +132,7 @@ var ngSwitchDirective = ['$animator', function($animator) {        scope.$watch(watchExpr, function ngSwitchWatchAction(value) {          for (var i= 0, ii=selectedScopes.length; i<ii; i++) {            selectedScopes[i].$destroy(); -          animate.leave(selectedElements[i]); +          $animate.leave(selectedElements[i]);          }          selectedElements = []; @@ -153,7 +147,7 @@ var ngSwitchDirective = ['$animator', function($animator) {                var anchor = selectedTransclude.element;                selectedElements.push(caseElement); -              animate.enter(caseElement, anchor.parent(), anchor); +              $animate.enter(caseElement, anchor.parent(), anchor);              });            });          } | 
