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); }); }); } |
