fix(ngAnimate): prevent animation on initial page load

This commit is contained in:
Misko Hevery 2013-04-11 22:39:15 -07:00
parent 3c3247fe17
commit 570463a465
8 changed files with 262 additions and 228 deletions

View file

@ -40,9 +40,7 @@
* *
* The `event1` and `event2` attributes refer to the animation events specific to the directive that has been assigned. * The `event1` and `event2` attributes refer to the animation events specific to the directive that has been assigned.
* *
* Keep in mind that, by default, **all** initial animations will be skipped until the first digest cycle has fully * Keep in mind that if an animation is running, no child element of such animation can also be animated.
* passed. This helps prevent any unexpected animations from occurring while the application or directive is initializing. To
* override this behavior, you may pass "animateFirst: true" into the ngAnimate attribute expression.
* *
* <h2>CSS-defined Animations</h2> * <h2>CSS-defined Animations</h2>
* By default, ngAnimate attaches two CSS3 classes per animation event to the DOM element to achieve the animation. * By default, ngAnimate attaches two CSS3 classes per animation event to the DOM element to achieve the animation.
@ -126,217 +124,211 @@
*/ */
var $AnimatorProvider = function() { var $AnimatorProvider = function() {
var globalAnimationEnabled = true; var NG_ANIMATE_CONTROLLER = '$ngAnimateController';
var rootAnimateController = {running:true};
this.$get = ['$animation', '$window', '$sniffer', '$rootScope', function($animation, $window, $sniffer, $rootScope) { this.$get = ['$animation', '$window', '$sniffer', '$rootElement', '$rootScope',
/** function($animation, $window, $sniffer, $rootElement, $rootScope) {
* @ngdoc function $rootElement.data(NG_ANIMATE_CONTROLLER, rootAnimateController);
* @name ng.$animator var unregister = $rootScope.$watch(function() {
* @function unregister();
* if (rootAnimateController.running) {
* @description $window.setTimeout(function() {
* The $animator.create service provides the DOM manipulation API which is decorated with animations. rootAnimateController.running = false;
* }, 0);
* @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 ngAnimateAttr = attrs.ngAnimate;
// avoid running animations on start
var animationEnabled = false;
var ngAnimateValue = ngAnimateAttr && scope.$eval(ngAnimateAttr);
if (!animationEnabled) {
if(isObject(ngAnimateValue) && ngAnimateValue['animateFirst']) {
animationEnabled = true;
} else {
var enableSubsequent = function() {
removeWatch();
scope.$evalAsync(function() {
animationEnabled = true;
});
};
var removeWatch = noop;
if (scope.$$phase) {
enableSubsequent();
} else {
removeWatch = scope.$watch(enableSubsequent);
}
}
} }
var animator = {}; });
/** /**
* @ngdoc function * @ngdoc function
* @name ng.animator#enter * @name ng.$animator
* @methodOf ng.$animator * @function
* @function *
* * @description
* @description * The $animator.create service provides the DOM manipulation API which is decorated with animations.
* Injects the element object into the DOM (inside of the parent element) and then runs the enter animation. *
* * @param {Scope} scope the scope for the ng-animate.
* @param {jQuery/jqLite element} element the element that will be the focus of the enter animation * @param {Attributes} attr the attributes object which contains the ngAnimate key / value pair. (The attributes are
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the enter animation * passed into the linking function of the directive using the `$animator`.)
* @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 * @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods.
*/ */
animator.enter = animateActionFactory('enter', insert, noop); var AnimatorService = function(scope, attrs) {
var ngAnimateAttr = attrs.ngAnimate;
/** var ngAnimateValue = ngAnimateAttr && scope.$eval(ngAnimateAttr);
* @ngdoc function var animator = {};
* @name ng.animator#leave
* @methodOf ng.$animator /**
* @function * @ngdoc function
* * @name ng.animator#enter
* @description * @methodOf ng.$animator
* Runs the leave animation operation and, upon completion, removes the element from the DOM. * @function
* *
* @param {jQuery/jqLite element} element the element that will be the focus of the leave animation * @description
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the leave animation * Injects the element object into the DOM (inside of the parent element) and then runs the enter animation.
*/ *
animator.leave = animateActionFactory('leave', noop, remove); * @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
* @ngdoc function */
* @name ng.animator#move animator.enter = animateActionFactory('enter', insert, noop);
* @methodOf ng.$animator
* @function /**
* * @ngdoc function
* @description * @name ng.animator#leave
* Fires the move DOM operation. Just before the animation starts, the animator will either append it into the parent container or * @methodOf ng.$animator
* add the element directly after the after element if present. Then the move animation will be run. * @function
* *
* @param {jQuery/jqLite element} element the element that will be the focus of the move animation * @description
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the move animation * Runs the leave animation operation and, upon completion, removes the element from the DOM.
* @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 {jQuery/jqLite element} element the element that will be the focus of the leave animation
animator.move = animateActionFactory('move', move, noop); * @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#show /**
* @methodOf ng.$animator * @ngdoc function
* @function * @name ng.animator#move
* * @methodOf ng.$animator
* @description * @function
* Reveals the element by setting the CSS property `display` to `block` and then starts the show animation directly after. *
* * @description
* @param {jQuery/jqLite element} element the element that will be rendered visible or hidden * 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.
animator.show = animateActionFactory('show', show, noop); *
* @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
* @ngdoc function * @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
* @name ng.animator#hide */
* @methodOf ng.$animator animator.move = animateActionFactory('move', move, noop);
*
* @description /**
* Starts the hide animation first and sets the CSS `display` property to `none` upon completion. * @ngdoc function
* * @name ng.animator#show
* @param {jQuery/jqLite element} element the element that will be rendered visible or hidden * @methodOf ng.$animator
*/ * @function
animator.hide = animateActionFactory('hide', noop, hide); *
return animator; * @description
* Reveals the element by setting the CSS property `display` to `block` and then starts the show animation directly after.
function animateActionFactory(type, beforeFn, afterFn) { *
var className = ngAnimateAttr * @param {jQuery/jqLite element} element the element that will be rendered visible or hidden
? isObject(ngAnimateValue) ? ngAnimateValue[type] : ngAnimateValue + '-' + type */
: ''; animator.show = animateActionFactory('show', show, noop);
var animationPolyfill = $animation(className);
/**
var polyfillSetup = animationPolyfill && animationPolyfill.setup; * @ngdoc function
var polyfillStart = animationPolyfill && animationPolyfill.start; * @name ng.animator#hide
* @methodOf ng.$animator
if (!className) { *
return function(element, parent, after) { * @description
beforeFn(element, parent, after); * Starts the hide animation first and sets the CSS `display` property to `none` upon completion.
afterFn(element, parent, after); *
} * @param {jQuery/jqLite element} element the element that will be rendered visible or hidden
} else { */
var setupClass = className + '-setup'; animator.hide = animateActionFactory('hide', noop, hide);
var startClass = className + '-start'; return animator;
return function(element, parent, after) { function animateActionFactory(type, beforeFn, afterFn) {
if (!animationEnabled || !globalAnimationEnabled || var className = ngAnimateAttr
(!$sniffer.supportsTransitions && !polyfillSetup && !polyfillStart)) { ? isObject(ngAnimateValue) ? ngAnimateValue[type] : ngAnimateValue + '-' + type
: '';
var animationPolyfill = $animation(className);
var polyfillSetup = animationPolyfill && animationPolyfill.setup;
var polyfillStart = animationPolyfill && animationPolyfill.start;
if (!className) {
return function(element, parent, after) {
beforeFn(element, parent, after); beforeFn(element, parent, after);
afterFn(element, parent, after); afterFn(element, parent, after);
return;
} }
} else {
element.addClass(setupClass); var setupClass = className + '-setup';
beforeFn(element, parent, after); var startClass = className + '-start';
if (element.length == 0) return done();
return function(element, parent, after) {
var memento = (polyfillSetup || noop)(element); if (!parent) {
parent = after ? after.parent() : element.parent();
// $window.setTimeout(beginAnimation, 0); this was causing the element not to animate }
// keep at 1 for animation dom rerender if ((!$sniffer.supportsTransitions && !polyfillSetup && !polyfillStart) ||
$window.setTimeout(beginAnimation, 1); (parent.inheritedData(NG_ANIMATE_CONTROLLER) || noop).running) {
beforeFn(element, parent, after);
function beginAnimation() { afterFn(element, parent, after);
element.addClass(startClass); return;
if (polyfillStart) {
polyfillStart(element, done, memento);
} else if (isFunction($window.getComputedStyle)) {
var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition';
var w3cTransitionProp = 'transition'; //one day all browsers will have this
var durationKey = 'Duration';
var duration = 0;
//we want all the styles defined before and after
forEach(element, function(element) {
var globalStyles = $window.getComputedStyle(element) || {};
duration = Math.max(
parseFloat(globalStyles[w3cTransitionProp + durationKey]) ||
parseFloat(globalStyles[vendorTransitionProp + durationKey]) ||
0,
duration);
});
$window.setTimeout(done, duration * 1000);
} else {
done();
} }
}
function done() { element.data(NG_ANIMATE_CONTROLLER, {running:true});
afterFn(element, parent, after); element.addClass(setupClass);
element.removeClass(setupClass); beforeFn(element, parent, after);
element.removeClass(startClass); 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 beginAnimation() {
element.addClass(startClass);
if (polyfillStart) {
polyfillStart(element, done, memento);
} else if (isFunction($window.getComputedStyle)) {
var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition';
var w3cTransitionProp = 'transition'; //one day all browsers will have this
var durationKey = 'Duration';
var duration = 0;
//we want all the styles defined before and after
forEach(element, function(element) {
var globalStyles = $window.getComputedStyle(element) || {};
duration = Math.max(
parseFloat(globalStyles[w3cTransitionProp + durationKey]) ||
parseFloat(globalStyles[vendorTransitionProp + durationKey]) ||
0,
duration);
});
$window.setTimeout(done, duration * 1000);
} else {
done();
}
}
function done() {
afterFn(element, parent, after);
element.removeClass(setupClass);
element.removeClass(startClass);
element.removeData(NG_ANIMATE_CONTROLLER);
}
} }
} }
} }
}
function show(element) {
function show(element) { element.css('display', '');
element.css('display', '');
}
function hide(element) {
element.css('display', 'none');
}
function insert(element, parent, after) {
if (after) {
after.after(element);
} else {
parent.append(element);
} }
}
function hide(element) {
function remove(element) { element.css('display', 'none');
element.remove(); }
}
function insert(element, parent, after) {
function move(element, parent, after) { if (after) {
// Do not remove element before insert. Removing will cause data associated with the after.after(element);
// element to be dropped. Insert will implicitly do the remove. } else {
insert(element, parent, after); parent.append(element);
} }
}; }
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 * @ngdoc function
@ -353,9 +345,9 @@ var $AnimatorProvider = function() {
*/ */
AnimatorService.enabled = function(value) { AnimatorService.enabled = function(value) {
if (arguments.length) { if (arguments.length) {
globalAnimationEnabled = !!value; rootAnimateController.running = !value;
} }
return globalAnimationEnabled; return !rootAnimateController.running;
}; };
return AnimatorService; return AnimatorService;

View file

@ -2,11 +2,12 @@
describe("$animator", function() { describe("$animator", function() {
var body, element; var body, element, $rootElement;
function html(html) { function html(html) {
body.html(html); body.append($rootElement);
element = body.children().eq(0); $rootElement.html(html);
element = $rootElement.children().eq(0);
return element; return element;
} }
@ -21,7 +22,18 @@ describe("$animator", function() {
describe("enable / disable", function() { describe("enable / disable", function() {
it("should disable and enable the animations", inject(function($animator) { beforeEach(function() {
module(function($animationProvider, $provide) {
$provide.value('$window', angular.mock.createMockWindow());
});
});
it("should disable and enable the animations", inject(function($animator, $rootScope, $window) {
expect($animator.enabled()).toBe(false);
$rootScope.$digest();
$window.setTimeout.expect(0).process();
expect($animator.enabled()).toBe(true); expect($animator.enabled()).toBe(true);
expect($animator.enabled(0)).toBe(false); expect($animator.enabled(0)).toBe(false);
@ -40,9 +52,10 @@ describe("$animator", function() {
module(function($animationProvider, $provide) { module(function($animationProvider, $provide) {
$provide.value('$window', window = angular.mock.createMockWindow()); $provide.value('$window', window = angular.mock.createMockWindow());
}) })
inject(function($animator, $compile, $rootScope) { inject(function($animator, $compile, $rootScope, _$rootElement_) {
animator = $animator($rootScope, {}); animator = $animator($rootScope, {});
element = $compile('<div></div>')($rootScope); element = $compile('<div></div>')($rootScope);
$rootElement = _$rootElement_;
}) })
}); });
@ -131,7 +144,10 @@ describe("$animator", function() {
animator = $animator($rootScope, { animator = $animator($rootScope, {
ngAnimate : '{enter: \'custom\'}' ngAnimate : '{enter: \'custom\'}'
}); });
$rootScope.$digest(); // re-enable the animations; $rootScope.$digest(); // re-enable the animations;
window.setTimeout.expect(0).process();
expect(element.contents().length).toBe(0); expect(element.contents().length).toBe(0);
animator.enter(child, element); animator.enter(child, element);
window.setTimeout.expect(1).process(); window.setTimeout.expect(1).process();
@ -141,7 +157,10 @@ describe("$animator", function() {
animator = $animator($rootScope, { animator = $animator($rootScope, {
ngAnimate : '{leave: \'custom\'}' ngAnimate : '{leave: \'custom\'}'
}); });
$rootScope.$digest();
$rootScope.$digest(); // re-enable the animations;
window.setTimeout.expect(0).process();
element.append(child); element.append(child);
expect(element.contents().length).toBe(1); expect(element.contents().length).toBe(1);
animator.leave(child, element); animator.leave(child, element);
@ -150,6 +169,7 @@ describe("$animator", function() {
})); }));
it("should animate the move animation event", inject(function($animator, $compile, $rootScope) { it("should animate the move animation event", inject(function($animator, $compile, $rootScope) {
$animator.enabled(true);
animator = $animator($rootScope, { animator = $animator($rootScope, {
ngAnimate : '{move: \'custom\'}' ngAnimate : '{move: \'custom\'}'
}); });
@ -165,6 +185,7 @@ describe("$animator", function() {
})); }));
it("should animate the show animation event", inject(function($animator, $rootScope) { it("should animate the show animation event", inject(function($animator, $rootScope) {
$animator.enabled(true);
animator = $animator($rootScope, { animator = $animator($rootScope, {
ngAnimate : '{show: \'custom\'}' ngAnimate : '{show: \'custom\'}'
}); });
@ -178,6 +199,7 @@ describe("$animator", function() {
})); }));
it("should animate the hide animation event", inject(function($animator, $rootScope) { it("should animate the hide animation event", inject(function($animator, $rootScope) {
$animator.enabled(true);
animator = $animator($rootScope, { animator = $animator($rootScope, {
ngAnimate : '{hide: \'custom\'}' ngAnimate : '{hide: \'custom\'}'
}); });
@ -192,6 +214,7 @@ describe("$animator", function() {
it("should assign the ngAnimate string to all events if a string is given", it("should assign the ngAnimate string to all events if a string is given",
inject(function($animator, $sniffer, $rootScope) { inject(function($animator, $sniffer, $rootScope) {
$animator.enabled(true);
if (!$sniffer.supportsTransitions) return; if (!$sniffer.supportsTransitions) return;
animator = $animator($rootScope, { animator = $animator($rootScope, {
ngAnimate : '"custom"' ngAnimate : '"custom"'
@ -237,6 +260,7 @@ describe("$animator", function() {
})); }));
it("should run polyfillSetup and return the memento", inject(function($animator, $rootScope) { it("should run polyfillSetup and return the memento", inject(function($animator, $rootScope) {
$animator.enabled(true);
animator = $animator($rootScope, { animator = $animator($rootScope, {
ngAnimate : '{show: \'setup-memo\'}' ngAnimate : '{show: \'setup-memo\'}'
}); });
@ -248,6 +272,8 @@ describe("$animator", function() {
})); }));
it("should not run if animations are disabled", inject(function($animator, $rootScope) { it("should not run if animations are disabled", inject(function($animator, $rootScope) {
$animator.enabled(true);
$rootScope.$digest(); // clear initial animation suppression
$animator.enabled(false); $animator.enabled(false);
animator = $animator($rootScope, { animator = $animator($rootScope, {
@ -274,8 +300,10 @@ describe("$animator", function() {
beforeEach(function() { beforeEach(function() {
module(function($animationProvider, $provide) { module(function($animationProvider, $provide) {
$provide.value('$window', window = angular.mock.createMockWindow()); $provide.value('$window', window = angular.mock.createMockWindow());
return function($sniffer) { return function($sniffer, _$rootElement_, $animator) {
vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; vendorPrefix = '-' + $sniffer.vendorPrefix + '-';
$rootElement = _$rootElement_;
$animator.enabled(true);
}; };
}) })
}); });
@ -288,8 +316,6 @@ describe("$animator", function() {
ngAnimate : '{show: \'inline-show\'}' ngAnimate : '{show: \'inline-show\'}'
}); });
$rootScope.$digest(); // skip no-animate on first digest.
element.css('display','none'); element.css('display','none');
expect(element.css('display')).toBe('none'); expect(element.css('display')).toBe('none');
animator.show(element); animator.show(element);

View file

@ -303,8 +303,9 @@ describe('ngInclude ngAnimate', function() {
beforeEach(module(function($animationProvider, $provide) { beforeEach(module(function($animationProvider, $provide) {
$provide.value('$window', window = angular.mock.createMockWindow()); $provide.value('$window', window = angular.mock.createMockWindow());
return function($sniffer) { return function($sniffer, $animator) {
vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; vendorPrefix = '-' + $sniffer.vendorPrefix + '-';
$animator.enabled(true);
}; };
})); }));

View file

@ -554,8 +554,9 @@ describe('ngRepeat ngAnimate', function() {
beforeEach(module(function($animationProvider, $provide) { beforeEach(module(function($animationProvider, $provide) {
$provide.value('$window', window = angular.mock.createMockWindow()); $provide.value('$window', window = angular.mock.createMockWindow());
return function($sniffer) { return function($sniffer, $animator) {
vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; vendorPrefix = '-' + $sniffer.vendorPrefix + '-';
$animator.enabled(true);
}; };
})); }));

View file

@ -45,11 +45,12 @@ describe('ngShow / ngHide', function() {
describe('ngShow / ngHide - ngAnimate', function() { describe('ngShow / ngHide - ngAnimate', function() {
var window; var window;
var vendorPrefix; var vendorPrefix;
var body, element; var body, element, $rootElement;
function html(html) { function html(html) {
body.html(html); body.append($rootElement);
element = body.children().eq(0); $rootElement.html(html);
element = $rootElement.children().eq(0);
return element; return element;
} }
@ -61,12 +62,15 @@ describe('ngShow / ngHide - ngAnimate', function() {
afterEach(function(){ afterEach(function(){
dealoc(body); dealoc(body);
dealoc(element); dealoc(element);
body.removeAttr('ng-animation-running');
}); });
beforeEach(module(function($animationProvider, $provide) { beforeEach(module(function($animationProvider, $provide) {
$provide.value('$window', window = angular.mock.createMockWindow()); $provide.value('$window', window = angular.mock.createMockWindow());
return function($sniffer) { return function($sniffer, _$rootElement_, $animator) {
vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; vendorPrefix = '-' + $sniffer.vendorPrefix + '-';
$rootElement = _$rootElement_;
$animator.enabled(true);
}; };
})); }));
@ -111,11 +115,14 @@ describe('ngShow / ngHide - ngAnimate', function() {
expect(element.attr('class')).not.toContain('custom-hide-setup'); expect(element.attr('class')).not.toContain('custom-hide-setup');
})); }));
it('should skip the initial show state on the first digest', function() { it('should skip animation if parent animation running', function() {
var fired = false; var fired = false;
inject(function($compile, $rootScope, $sniffer) { inject(function($animator, $compile, $rootScope, $sniffer) {
$animator.enabled(true);
$rootScope.$digest();
$rootScope.val = true; $rootScope.val = true;
var element = $compile(html('<div ng-show="val" ng-animate="\'animation\'">123</div>'))($rootScope); var element = $compile(html('<div ng-show="val" ng-animate="\'animation\'">123</div>'))($rootScope);
$rootElement.controller('ngAnimate').running = true;
element.css('display','none'); element.css('display','none');
expect(element.css('display')).toBe('none'); expect(element.css('display')).toBe('none');
@ -123,6 +130,7 @@ describe('ngShow / ngHide - ngAnimate', function() {
expect(element[0].style.display).toBe(''); expect(element[0].style.display).toBe('');
expect(fired).toBe(false); expect(fired).toBe(false);
$rootElement.controller('ngAnimate').running = false;
$rootScope.val = false; $rootScope.val = false;
$rootScope.$digest(); $rootScope.$digest();
if ($sniffer.supportsTransitions) { if ($sniffer.supportsTransitions) {
@ -178,7 +186,7 @@ describe('ngShow / ngHide - ngAnimate', function() {
expect(element.attr('class')).not.toContain('custom-show-setup'); expect(element.attr('class')).not.toContain('custom-show-setup');
})); }));
it('should skip the initial hide state on the first digest', function() { it('should disable animation when parent animation is running', function() {
var fired = false; var fired = false;
module(function($animationProvider) { module(function($animationProvider) {
$animationProvider.register('destructive-animation', function() { $animationProvider.register('destructive-animation', function() {
@ -193,6 +201,7 @@ describe('ngShow / ngHide - ngAnimate', function() {
inject(function($compile, $rootScope) { inject(function($compile, $rootScope) {
$rootScope.val = false; $rootScope.val = false;
var element = $compile(html('<div ng-hide="val" ng-animate="{ hide:\'destructive-animation\' }">123</div>'))($rootScope); var element = $compile(html('<div ng-hide="val" ng-animate="{ hide:\'destructive-animation\' }">123</div>'))($rootScope);
$rootElement.controller('ngAnimate').running = true;
element.css('display','block'); element.css('display','block');
expect(element.css('display')).toBe('block'); expect(element.css('display')).toBe('block');

View file

@ -236,8 +236,9 @@ describe('ngSwitch ngAnimate', function() {
beforeEach(module(function($animationProvider, $provide) { beforeEach(module(function($animationProvider, $provide) {
$provide.value('$window', window = angular.mock.createMockWindow()); $provide.value('$window', window = angular.mock.createMockWindow());
return function($sniffer) { return function($sniffer, $animator) {
vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; vendorPrefix = '-' + $sniffer.vendorPrefix + '-';
$animator.enabled(true);
}; };
})); }));

View file

@ -4,8 +4,9 @@ describe('ngView', function() {
var element; var element;
beforeEach(module(function() { beforeEach(module(function() {
return function($rootScope, $compile) { return function($rootScope, $compile, $animator) {
element = $compile('<ng:view onload="load()"></ng:view>')($rootScope); element = $compile('<ng:view onload="load()"></ng:view>')($rootScope);
$animator.enabled(true);
}; };
})); }));
@ -510,8 +511,9 @@ describe('ngAnimate', function() {
beforeEach(module(function($provide, $routeProvider) { beforeEach(module(function($provide, $routeProvider) {
$provide.value('$window', window = angular.mock.createMockWindow()); $provide.value('$window', window = angular.mock.createMockWindow());
$routeProvider.when('/foo', {controller: noop, templateUrl: '/foo.html'}); $routeProvider.when('/foo', {controller: noop, templateUrl: '/foo.html'});
return function($templateCache) { return function($templateCache, $animator) {
$templateCache.put('/foo.html', [200, '<div>data</div>', {}]); $templateCache.put('/foo.html', [200, '<div>data</div>', {}]);
$animator.enabled(true);
} }
})); }));
@ -579,8 +581,8 @@ describe('ngAnimate', function() {
element = $compile(html( element = $compile(html(
'<div ' + '<div ' +
'ng-view ' + 'ng-view ' +
'ng-animate="{enter: \'customEnter\', animateFirst: false}">' + 'ng-animate="{enter: \'customEnter\'}">' +
'</div>' '</div>'
))($rootScope); ))($rootScope);
$location.path('/foo'); $location.path('/foo');

View file

@ -24,15 +24,17 @@ beforeEach(function() {
// reset to jQuery or default to us. // reset to jQuery or default to us.
bindJQuery(); bindJQuery();
jqLite(document.body).html(''); jqLite(document.body).html('').removeData();
}); });
afterEach(function() { afterEach(function() {
if (this.$injector) { if (this.$injector) {
var $rootScope = this.$injector.get('$rootScope'); var $rootScope = this.$injector.get('$rootScope');
var $rootElement = this.$injector.get('$rootElement');
var $log = this.$injector.get('$log'); var $log = this.$injector.get('$log');
// release the injector // release the injector
dealoc($rootScope); dealoc($rootScope);
dealoc($rootElement);
// check $log mock // check $log mock
$log.assertEmpty && $log.assertEmpty(); $log.assertEmpty && $log.assertEmpty();