diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Angular.js | 6 | ||||
| -rwxr-xr-x | src/AngularPublic.js | 3 | ||||
| -rw-r--r-- | src/loader.js | 28 | ||||
| -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 | ||||
| -rw-r--r-- | src/ngAnimate/animate.js | 714 | ||||
| -rw-r--r-- | src/ngMock/angular-mocks.js | 37 | ||||
| -rw-r--r-- | src/ngRoute/directive/ngView.js | 22 | 
15 files changed, 1034 insertions, 678 deletions
| diff --git a/src/Angular.js b/src/Angular.js index 4e050a0c..68768d34 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -1053,13 +1053,13 @@ function bootstrap(element, modules) {      }]);      modules.unshift('ng');      var injector = createInjector(modules); -    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animator', -       function(scope, element, compile, injector, animator) { +    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate', +       function(scope, element, compile, injector, animate) {          scope.$apply(function() {            element.data('$injector', injector);            compile(element)(scope);          }); -        animator.enabled(true); +        animate.enabled(true);        }]      );      return injector; diff --git a/src/AngularPublic.js b/src/AngularPublic.js index 7745cce9..b225fc85 100755 --- a/src/AngularPublic.js +++ b/src/AngularPublic.js @@ -106,8 +106,7 @@ function publishExternalAPI(angular){          directive(ngEventDirectives);        $provide.provider({          $anchorScroll: $AnchorScrollProvider, -        $animation: $AnimationProvider, -        $animator: $AnimatorProvider, +        $animate: $AnimateProvider,          $browser: $BrowserProvider,          $cacheFactory: $CacheFactoryProvider,          $controller: $ControllerProvider, diff --git a/src/loader.js b/src/loader.js index 712ff0f7..b28ccee2 100644 --- a/src/loader.js +++ b/src/loader.js @@ -173,24 +173,30 @@ function setupModuleLoader(window) {             * @param {Function} animationFactory Factory function for creating new instance of an animation.             * @description             * -           * Defines an animation hook that can be later used with {@link ng.directive:ngAnimate ngAnimate} -           * alongside {@link ng.directive:ngAnimate#Description common ng directives} as well as custom directives. +           * **NOTE**: animations are take effect only if the **ngAnimate** module is loaded. +           * +           * +           * Defines an animation hook that can be later used with {@link ngAnimate.$animate $animate} service and +           * directives that use this service. +           *             * <pre> -           * module.animation('animation-name', function($inject1, $inject2) { +           * module.animation('.animation-name', function($inject1, $inject2) {             *   return { -           *     //this gets called in preparation to setup an animation -           *     setup : function(element) { ... }, -           * -           *     //this gets called once the animation is run -           *     start : function(element, done, memo) { ... } +           *     eventName : function(element, done) { +           *       //code to run the animation +           *       //once complete, then run done() +           *       return function cancellationFunction(element) { +           *         //code to cancel the animation +           *       } +           *     }             *   }             * })             * </pre>             * -           * See {@link ng.$animationProvider#register $animationProvider.register()} and -           * {@link ng.directive:ngAnimate ngAnimate} for more information. +           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and +           * {@link ngAnimate ngAnimate module} for more information.             */ -          animation: invokeLater('$animationProvider', 'register'), +          animation: invokeLater('$animateProvider', 'register'),            /**             * @ngdoc method 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);              });            });          } diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js new file mode 100644 index 00000000..ab7a19b0 --- /dev/null +++ b/src/ngAnimate/animate.js @@ -0,0 +1,714 @@ +/** + * @ngdoc overview + * @name ngAnimate + * @description + * + * ngAnimate + * ========= + * + * The ngAnimate module is an optional module that comes packed with AngularJS that can be included within an AngularJS + * application to provide support for CSS and JavaScript animation hooks. + * + * To make use of animations with AngularJS, the `angular-animate.js` JavaScript file must be included into your application + * and the `ngAnimate` module must be included as a dependency. + * + * <pre> + * angular.module('App', ['ngAnimate']); + * </pre> + * + * Then, to see animations in action, all that is required is to define the appropriate CSS classes + * or to register a JavaScript animation via the $animation service. The directives that support animation automatically are: + * `ngRepeat`, `ngInclude`, `ngSwitch`, `ngShow`, `ngHide` and `ngView`. Custom directives can take advantage of animation + * by using the `$animate` service. + * + * Below is a more detailed breakdown of the supported animation events provided by pre-existing 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                                      | + * | {@link ng.directive:ngShow#animations ngClass}            | add and remove                                     | + * + * You can find out more information about animations upon visiting each directive page. + * + * Below is an example of how to apply animations to a directive that supports animation hooks: + * + * <pre> + * <style type="text/css"> + * .slide.ng-enter > div, + * .slide.ng-leave > div { + *   -webkit-transition:0.5s linear all; + *   -moz-transition:0.5s linear all; + *   -o-transition:0.5s linear all; + *   transition:0.5s linear all; + * } + *  + * .slide > .ng-enter { }        /* starting animations for enter */ + * .slide > .ng-enter-active { } /* terminal animations for enter */ + * .slide > .ng-leave { }        /* starting animations for leave */ + * .slide > .ng-leave-active { } /* terminal animations for leave */ + * </style> + * + * <!-- + * the animate service will automatically add .ng-enter and .ng-leave to the element + * to trigger the CSS animations + * --> + * <ANY class="slide" ng-include="..."></ANY> + * </pre> + * + * Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's + * animation has completed. + * + * <h2>CSS-defined Animations</h2> + * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes + * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported + * and can be used to play along with this naming structure. + * + * The following code below demonstrates how to perform animations using **CSS transitions** with Angular: + * + * <pre> + * <style type="text/css"> + * /* + *  The animate class is apart of the element and the ng-enter class + *  is attached to the element once the enter animation event is triggered + * */ + * .reveal-animation.ng-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 + * */ + * .reveal-animation.ng-enter.ng-enter-active { + *  /* The animation code itself */ + *  opacity: 1; + * } + * </style> + * + * <div class="view-container"> + *   <div ng-view class="reveal-animation"></div> + * </div> + * </pre> + * + * The following code below demonstrates how to perform animations using **CSS animations** with Angular: + * + * <pre> + * <style type="text/css"> + * .reveal-animation.ng-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 class="view-container"> + *   <div ng-view class="reveal-animation"></div> + * </div> + * </pre> + * + * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing. + * + * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add + * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically + * detect the CSS code 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 its final state. This final state is when the DOM element + * has no CSS transition/animation classes applied to 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 on browsers that do not + * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module. + * + * <pre> + * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application. + * var ngModule = angular.module('YourApp', []); + * ngModule.animation('.my-crazy-animation', function() { + *   return { + *     enter: function(element, done) { + *       //run the animation + *       //!annotate Cancel Animation|This function (if provided) will perform the cancellation of the animation when another is triggered + *       return function(element, done) { + *         //cancel the animation + *       } + *     } + *     leave: function(element, done) { }, + *     move: function(element, done) { }, + *     show: function(element, done) { }, + *     hide: function(element, done) { }, + *     addClass: function(element, className, done) { }, + *     removeClass: function(element, className, done) { }, + *   } + * }); + * </pre> + * + * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run + * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits + * the element's CSS class attribute value and then run the matching animation event function (if found). + * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function + * be executed. It should be also noted that only simple or compound class selectors are allowed. + * + * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned. + * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run, + * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation + * or transition code that is defined via a stylesheet). + * + */ + +angular.module('ngAnimate', ['ng']) + +  /** +   * @ngdoc object +   * @name ngAnimate.$animateProvider +   * @description +   * +   * The $AnimationProvider provider allows developers to register and access custom JavaScript animations directly inside +   * of a module. When an animation is triggered, the $animate service will query the $animation function to find any +   * animations that match the provided name value. +   * +   * Please visit the {@link ngAnimate ngAnimate} module overview page learn more about how to use animations in your application. +   * +   */ +  .config(['$provide', '$animateProvider', function($provide, $animateProvider) { +    var selectors = $animateProvider.$$selectors; + +    var NG_ANIMATE_STATE = '$$ngAnimateState'; +    var rootAnimateState = {running:true}; + +    $provide.decorator('$animate', ['$delegate', '$injector', '$window', '$sniffer', '$rootElement', +      function($delegate, $injector, $window, $sniffer, $rootElement) { +         +      var noop = angular.noop; +      var forEach = angular.forEach; + +      $rootElement.data(NG_ANIMATE_STATE, rootAnimateState); + +       function lookup(name) { +        if (name) { +          var classes = name.substr(1).split('.'), +              classMap = {}; + +          for (var i = 0, ii = classes.length; i < ii; i++) { +            classMap[classes[i]] = true; +          } + +          var matches = []; +          for (var i = 0, ii = selectors.length; i < ii; i++) { +            var selectorFactory = selectors[i]; +            var found = true; +            for(var j = 0, jj = selectorFactory.selectors.length; j < jj; j++) { +              var klass = selectorFactory.selectors[j]; +              if(klass.length > 0) { +                found = found && classMap[klass]; +              } +            } +            if(found) { +              matches.push($injector.get(selectorFactory.name)); +            } +          } +          return matches; +        } +      }; + +      /** +       * @ngdoc object +       * @name ngAnimate.$animate +       * @requires $window, $sniffer, $rootElement +       * @function +       * +       * @description +       * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) +       * as well as during addClass and removeClass operations. When any of these operations are run, the $animate service +       * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object) +       * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run. +       * +       * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives +       * will work out of the box without any extra configuration. +       * +       * Please visit the {@link ngAnimate ngAnimate} module overview page learn more about how to use animations in your application. +       * +       */ +      return { +        /** +         * @ngdoc function +         * @name ngAnimate.$animate#enter +         * @methodOf ngAnimate.$animate +         * @function +         * +         * @description +         * Appends the element to the parent element that resides in the document and then runs the enter animation. Once +         * the animation is started, the following CSS classes will be present on the element for the duration of the animation: +         * <pre> +         * .ng-enter +         * .ng-enter-active +         * </pre> +         * +         * Once the animation is complete then the done callback, if provided, will be also fired. +         * +         * @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 +         * @param {function()=} done callback function that will be called once the animation is complete +        */ +        enter : function(element, parent, after, done) { +          $delegate.enter(element, parent, after); +          performAnimation('enter', 'ng-enter', element, parent, after, done); +        }, + +        /** +         * @ngdoc function +         * @name ngAnimate.$animate#leave +         * @methodOf ngAnimate.$animate +         * @function +         * +         * @description +         * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once +         * the animation is started, the following CSS classes will be added for the duration of the animation: +         * <pre> +         * .ng-leave +         * .ng-leave-active +         * </pre> +         * +         * Once the animation is complete then the done callback, if provided, will be also fired. +         * +         * @param {jQuery/jqLite element} element the element that will be the focus of the leave animation +         * @param {function()=} done callback function that will be called once the animation is complete +        */ +        leave : function(element, done) { +          performAnimation('leave', 'ng-leave', element, null, null, function() { +            $delegate.leave(element, done); +          }); +        }, + +        /** +         * @ngdoc function +         * @name ngAnimate.$animate#move +         * @methodOf ngAnimate.$animate +         * @function +         * +         * @description +         * Fires the move DOM operation. Just before the animation starts, the animate service 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. Once +         * the animation is started, the following CSS classes will be added for the duration of the animation: +         * <pre> +         * .ng-move +         * .ng-move-active +         * </pre> +         * +         * Once the animation is complete then the done callback, if provided, will be also fired. +         * +         * @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 +         * @param {function()=} done callback function that will be called once the animation is complete +        */ +        move : function(element, parent, after, done) { +          $delegate.move(element, parent, after); +          performAnimation('move', 'ng-move', element, null, null, done); +        }, + +        /** +         * @ngdoc function +         * @name ngAnimate.$animate#show +         * @methodOf ngAnimate.$animate +         * @function +         * +         * @description +         * Reveals the element by removing the `ng-hide` class thus performing an animation in the process. During +         * this animation the CSS classes present on the element will be: +         * +         * <pre> +         * .ng-hide //already on the element if hidden +         * .ng-hide-remove +         * .ng-hide-remove-active +         * </pre> +         * +         * Once the animation is complete then all three CSS classes will be removed from the element. +         * The done callback, if provided, will be also fired once the animation is complete. +         * +         * @param {jQuery/jqLite element} element the element that will be rendered visible or hidden +         * @param {function()=} done callback function that will be called once the animation is complete +        */ +        show : function(element, done) { +          performAnimation('show', 'ng-hide-remove', element, null, null, function() { +            $delegate.show(element, done); +          }); +        }, + +        /** +         * @ngdoc function +         * @name ngAnimate.$animate#hide +         * @methodOf ngAnimate.$animate +         * +         * @description +         * Sets the element to hidden by adding the `ng-hide` class it. However, before the class is applied +         * the following CSS classes will be added temporarily to trigger any animation code: +         * +         * <pre> +         * .ng-hide-add +         * .ng-hide-add-active +         * </pre> +         * +         * Once the animation is complete then both CSS classes will be removed and `ng-hide` will be added to the element. +         * The done callback, if provided, will be also fired once the animation is complete. +         * +         * @param {jQuery/jqLite element} element the element that will be rendered visible or hidden +         * @param {function()=} done callback function that will be called once the animation is complete +        */ +        hide : function(element, done) { +          performAnimation('hide', 'ng-hide-add', element, null, null, function() { +            $delegate.hide(element, done); +          }); +        }, + +        /** +         * @ngdoc function +         * @name ngAnimate.$animate#addClass +         * @methodOf ngAnimate.$animate +         * +         * @description +         * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class. +         * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide +         * the animate service the setup and active CSS classes in order to trigger the animation. +         * +         * For example, upon execution of: +         * +         * <pre> +         * $animate.addClass(element, 'super'); +         * </pre> +         * +         * The generated CSS class values present on element will look like: +         * <pre> +         * .super-add +         * .super-add-active +         * </pre> +         * +         * And upon completion, the generated animation CSS classes will be removed from the element, but the className +         * value will be attached to the element. In this case, based on the previous example, the resulting CSS class for the element +         * will look like so: +         * +         * <pre> +         * .super +         * </pre> +         * +         * Once this is complete, then the done callback, if provided, will be fired. +         * +         * @param {jQuery/jqLite element} element the element that will be animated +         * @param {string} className the CSS class that will be animated and then attached to the element +         * @param {function()=} done callback function that will be called once the animation is complete +        */ +        addClass : function(element, className, done) { +          performAnimation('addClass', className, element, null, null, function() { +            $delegate.addClass(element, className, done); +          }); +        }, + +        /** +         * @ngdoc function +         * @name ngAnimate.$animate#removeClass +         * @methodOf ngAnimate.$animate +         * +         * @description +         * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value +         * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in +         * order to provide the animate service the setup and active CSS classes in order to trigger the animation. +         * +         * For example, upon the execution of: +         * +         * <pre> +         * $animate.removeClass(element, 'super'); +         * </pre> +         * +         * The CSS class values present on element during the animation will look like: +         * +         * <pre> +         * .super //this was here from before +         * .super-remove +         * .super-remove-active +         * </pre> +         * +         * And upon completion, the generated animation CSS classes will be removed from the element as well as the +         * className value that was provided (in this case {@type super} will be removed). Once that is complete, then, if provided, +         * the done callback will be fired. +         * +         * @param {jQuery/jqLite element} element the element that will be animated +         * @param {string} className the CSS class that will be animated and then removed from the element +         * @param {function()=} done callback function that will be called once the animation is complete +        */ +        removeClass : function(element, className, done) { +          performAnimation('removeClass', className, element, null, null, function() { +            $delegate.removeClass(element, className, done); +          }); +        }, + +        /** +         * @ngdoc function +         * @name ngAnimate.$animate#enabled +         * @methodOf ngAnimate.$animate +         * @function +         * +         * @param {boolean=} If provided then set the animation on or off. +         * @return {boolean} Current animation state. +         * +         * @description +         * Globally enables/disables animations. +         * +        */ +        enabled : function(value) { +          if (arguments.length) { +            rootAnimateState.running = !value; +          } +          return !rootAnimateState.running; +        } +      }; + +      /* +        all animations call this shared animation triggering function internally. +        The event variable refers to the JavaScript animation event that will be triggered +        and the className value is the name of the animation that will be applied within the +        CSS code. Element, parent and after are provided DOM elements for the animation +        and the onComplete callback will be fired once the animation is fully complete. +      */ +      function performAnimation(event, className, element, parent, after, onComplete) { +        if(nothingToAnimate(className, element)) { +          (onComplete || noop)(); +        } else { +          var classes = ((element.attr('class') || '') + ' ' + className), +              animationLookup = (' ' + classes).replace(/\s+/g,'.'), +              animations = []; +          forEach(lookup(animationLookup), function(animation, index) { +            animations.push({ +              start : animation[event], +              done : false +            }); +          }); + +          if (!parent) { +            parent = after ? after.parent() : element.parent(); +          } +          var disabledAnimation = { running : true }; + +          //skip the animation if animations are disabled, a parent is already being animated +          //or the element is not currently attached to the document body. +          if ((parent.inheritedData(NG_ANIMATE_STATE) || disabledAnimation).running) { +            //avoid calling done() since there is no need to remove any +            //data or className values since this happens earlier than that +            (onComplete || noop)(); +            return; +          } + +          var animationData = element.data(NG_ANIMATE_STATE) || {}; + +          //if an animation is currently running on the element then lets take the steps +          //to cancel that animation and fire any required callbacks +          if(animationData.running) { +            cancelAnimations(animationData.animations); +            animationData.done(); +          } + +          element.data(NG_ANIMATE_STATE, { +            running:true, +            animations:animations, +            done:done +          }); + +          if(event == 'addClass') { +            className = suffixClasses(className, '-add'); +          } else if(event == 'removeClass') { +            className = suffixClasses(className, '-remove'); +          } + +          element.addClass(className); + +          forEach(animations, function(animation, index) { +            var fn = function() { +              progress(index); +            }; + +            if(animation.start) { +              if(event == 'addClass' || event == 'removeClass') { +                animation.cancel = animation.start(element, className, fn); +              } else { +                animation.cancel = animation.start(element, fn); +              } +            } else { +              fn(); +            } +          }); +        } + +        function nothingToAnimate(className, element) { +          return !(className && className.length > 0 && element.length > 0); +        } + +        function cancelAnimations(animations) { +          forEach(animations, function(animation) { +            (animation.cancel || noop)(element); +          }); +        } + +        function suffixClasses(classes, suffix) { +          var className = ''; +          classes = angular.isArray(classes) ? classes : classes.split(/\s+/); +          forEach(classes, function(klass, i) { +            if(klass && klass.length > 0) { +              className += (i > 0 ? ' ' : '') + klass + suffix; +            } +          }); +          return className; +        } + +        function progress(index) { +          animations[index].done = true; +          for(var i=0;i<animations.length;i++) { +            if(!animations[i].done) return; +          } +          done(); +        }; + +        function done() { +          if(!done.hasBeenRun) { +            done.hasBeenRun = true; +            element.removeClass(className); +            element.removeData(NG_ANIMATE_STATE); +            (onComplete || noop)(); +          } +        } +      } +    }]); +  }]) + +  .animation('', ['$window','$sniffer', function($window, $sniffer) { +    return { +      enter : function(element, done) { +        return animate(element, 'ng-enter', done); +      }, +      leave : function(element, done) { +        return animate(element, 'ng-leave', done); +      }, +      move : function(element, done) { +        return animate(element, 'ng-move', done); +      }, +      show : function(element, done) { +        return animate(element, 'ng-hide-remove', done); +      }, +      hide : function(element, done) { +        return animate(element, 'ng-hide-add', done); +      }, +      addClass : function(element, className, done) { +        return animate(element, className, done); +      }, +      removeClass : function(element, className, done) { +        return animate(element, className, done); +      } +    }; + +    function animate(element, className, done) { +      if (!($sniffer.transitions || $sniffer.animations)) { +        done(); +      } else { +        var activeClassName = ''; +        $window.setTimeout(startAnimation, 1); + +        //this acts as the cancellation function in case +        //a new animation is triggered while another animation +        //is still going on (otherwise the active className +        //would still hang around until the timer is complete). +        return onComplete; +      } + +      function parseMaxTime(str) { +        var total = 0, values = angular.isString(str) ? str.split(/\s*,\s*/) : []; +        forEach(values, function(value) { +          total = Math.max(parseFloat(value) || 0, total); +        }); +        return total; +      } + +      function startAnimation() { +        var duration = 0; +        forEach(className.split(' '), function(klass, i) { +          activeClassName += (i > 0 ? ' ' : '') + klass + '-active'; +        }); + +        element.addClass(activeClassName); + +        //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'; + +        //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(onComplete, duration * 1000); +      } + +      function onComplete() { +        element.removeClass(activeClassName); +        done(); +      }; +    }; +  }]); diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index e05e7a28..bfb601fd 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -627,6 +627,43 @@ angular.mock.$LogProvider = function() {    angular.mock.TzDate.prototype = Date.prototype;  })(); +angular.mock.animate = angular.module('mock.animate', ['ng']) + +  .config(['$provide', function($provide) { + +    $provide.decorator('$animate', function($delegate) { +      var animate = { +        queue : [], +        enabled : $delegate.enabled, +        process : function(name) { +          var tick = animate.queue.shift(); +          expect(tick.method).toBe(name); +          tick.fn(); +          return tick; +        } +      }; + +      forEach(['enter','leave','move','show','hide','addClass','removeClass'], function(method) { +        animate[method] = function() { +          var params = arguments; +          animate.queue.push({ +            method : method, +            params : params, +            element : angular.isElement(params[0]) && params[0], +            parent  : angular.isElement(params[1]) && params[1], +            after   : angular.isElement(params[2]) && params[2], +            fn : function() { +              $delegate[method].apply($delegate, params); +            } +          }); +        }; +      }); + +      return animate; +    }); + +  }]); +  /**   * @ngdoc function   * @name angular.mock.createMockWindow diff --git a/src/ngRoute/directive/ngView.js b/src/ngRoute/directive/ngView.js index 935ba05d..3074df49 100644 --- a/src/ngRoute/directive/ngView.js +++ b/src/ngRoute/directive/ngView.js @@ -14,9 +14,6 @@ ngRouteModule.directive('ngView', ngViewFactory);   * Every time the current route changes, the included view changes with it according to the   * configuration of the `$route` service.   * - * Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter** - * and **leave** effects. - *   * @animations   * enter - happens just after the ngView contents are changed (when the new view DOM element is inserted into the DOM)   * leave - happens just after the current ngView contents change and just before the former contents are removed from the DOM @@ -35,8 +32,8 @@ ngRouteModule.directive('ngView', ngViewFactory);            <div              ng-view -            class="example-animate-container" -            ng-animate="{enter: 'example-enter', leave: 'example-leave'}"></div> +            class="example-$animate-container" +            ng-$animate="{enter: 'example-enter', leave: 'example-leave'}"></div>            <hr />            <pre>$location.path() = {{main.$location.path()}}</pre> @@ -71,12 +68,12 @@ ngRouteModule.directive('ngView', ngViewFactory);            transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;          } -        .example-animate-container { +        .example-$animate-container {            position:relative;            height:100px;          } -        .example-animate-container > * { +        .example-$animate-container > * {            display:block;            width:100%;            border-left:1px solid black; @@ -162,15 +159,14 @@ ngRouteModule.directive('ngView', ngViewFactory);   * @description   * Emitted every time the ngView content is reloaded.   */ -ngViewFactory.$inject = ['$route', '$anchorScroll', '$compile', '$controller', '$animator']; -function ngViewFactory(   $route,   $anchorScroll,   $compile,   $controller,   $animator) { +ngViewFactory.$inject = ['$route', '$anchorScroll', '$compile', '$controller', '$animate']; +function ngViewFactory(   $route,   $anchorScroll,   $compile,   $controller,   $animate) {    return {      restrict: 'ECA',      terminal: true,      link: function(scope, element, attr) {        var lastScope, -          onloadExp = attr.onload || '', -          animate = $animator(scope, attr); +          onloadExp = attr.onload || '';        scope.$on('$routeChangeSuccess', update);        update(); @@ -184,7 +180,7 @@ function ngViewFactory(   $route,   $anchorScroll,   $compile,   $controller,        }        function clearContent() { -        animate.leave(element.contents(), element); +        $animate.leave(element.contents());          destroyLastScope();        } @@ -195,7 +191,7 @@ function ngViewFactory(   $route,   $anchorScroll,   $compile,   $controller,          if (template) {            clearContent();            var enterElements = jqLite('<div></div>').html(template).contents(); -          animate.enter(enterElements, element); +          $animate.enter(enterElements, element);            var link = $compile(enterElements),                current = $route.current, | 
