feat($animate): use promises instead of callbacks for animations

The $animate service (both the service inside of ng and ngAnimate) now
makes use of promises instead of callback functions.

BREAKING CHANGE

Both the API for the cancallation method and the done callback for
$animate animations is different. Instead of using a callback function
for each of the $animate animation methods, a promise is used instead.

```js
//before
$animate.enter(element, container, null, callbackFn);

//after
$animate.enter(element, container).then(callbackFn);
```

The animation can now be cancelled via `$animate.cancel(promise)`.

```js
//before
var cancelFn = $animate.enter(element, container);
cancelFn(); //cancels the animation

//after
var promise = $animate.enter(element, container);
$animate.cancel(promise); //cancels the animation
```
This commit is contained in:
Matias Niemelä
2014-08-15 23:45:29 -04:00
parent 2f4437b3a1
commit bf0f5502b1
16 changed files with 311 additions and 267 deletions

View File

@@ -81,10 +81,20 @@ var $AnimateProvider = ['$provide', function($provide) {
return this.$$classNameFilter;
};
this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
this.$get = ['$$q', '$$asyncCallback', function($$q, $$asyncCallback) {
function async(fn) {
fn && $$asyncCallback(fn);
var currentDefer;
function asyncPromise() {
// only serve one instance of a promise in order to save CPU cycles
if (!currentDefer) {
currentDefer = $$q.defer();
currentDefer.promise.cancel = noop; //ngAnimate.$animate provides this
$$asyncCallback(function() {
currentDefer.resolve();
currentDefer = null;
});
}
return currentDefer.promise;
}
/**
@@ -112,22 +122,19 @@ var $AnimateProvider = ['$provide', function($provide) {
* @name $animate#enter
* @kind function
* @description Inserts the element into the DOM either after the `after` element or
* as the first child within the `parent` element. Once complete, the done() callback
* will be fired (if provided).
* as the first child within the `parent` element. When the function is called a promise
* is returned that will be resolved at a later time.
* @param {DOMElement} element the element which will be inserted into the DOM
* @param {DOMElement} parent the parent element which will append the element as
* a child (if the after element is not present)
* @param {DOMElement} after the sibling element which will append the element
* after itself
* @param {Function=} done callback function that will be called after the element has been
* inserted into the DOM
* @return {Promise} the animation callback promise
*/
enter : function(element, parent, after, done) {
after
? after.after(element)
: parent.prepend(element);
async(done);
return noop;
enter : function(element, parent, after) {
after ? after.after(element)
: parent.prepend(element);
return asyncPromise();
},
/**
@@ -135,16 +142,14 @@ var $AnimateProvider = ['$provide', function($provide) {
* @ngdoc method
* @name $animate#leave
* @kind function
* @description Removes the element from the DOM. Once complete, the done() callback will be
* fired (if provided).
* @description Removes the element from the DOM. When the function is called a promise
* is returned that will be resolved at a later time.
* @param {DOMElement} element the element which will be removed from the DOM
* @param {Function=} done callback function that will be called after the element has been
* removed from the DOM
* @return {Promise} the animation callback promise
*/
leave : function(element, done) {
leave : function(element) {
element.remove();
async(done);
return noop;
return asyncPromise();
},
/**
@@ -153,8 +158,8 @@ var $AnimateProvider = ['$provide', function($provide) {
* @name $animate#move
* @kind function
* @description Moves the position of the provided element within the DOM to be placed
* either after the `after` element or inside of the `parent` element. Once complete, the
* done() callback will be fired (if provided).
* either after the `after` element or inside of the `parent` element. When the function
* is called a promise is returned that will be resolved at a later time.
*
* @param {DOMElement} element the element which will be moved around within the
* DOM
@@ -162,13 +167,12 @@ var $AnimateProvider = ['$provide', function($provide) {
* inserted into (if the after element is not present)
* @param {DOMElement} after the sibling element where the element will be
* positioned next to
* @param {Function=} done the callback function (if provided) that will be fired after the
* element has been moved to its new position
* @return {Promise} the animation callback promise
*/
move : function(element, parent, after, done) {
move : function(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.
return this.enter(element, parent, after, done);
return this.enter(element, parent, after);
},
/**
@@ -176,23 +180,21 @@ var $AnimateProvider = ['$provide', function($provide) {
* @ngdoc method
* @name $animate#addClass
* @kind function
* @description Adds the provided className CSS class value to the provided element. Once
* complete, the done() callback will be fired (if provided).
* @description Adds the provided className CSS class value to the provided element.
* When the function is called a promise is returned that will be resolved at a later time.
* @param {DOMElement} element the element which will have the className value
* added to it
* @param {string} className the CSS class which will be added to the element
* @param {Function=} done the callback function (if provided) that will be fired after the
* className value has been added to the element
* @return {Promise} the animation callback promise
*/
addClass : function(element, className, done) {
addClass : function(element, className) {
className = !isString(className)
? (isArray(className) ? className.join(' ') : '')
: className;
forEach(element, function (element) {
jqLiteAddClass(element, className);
});
async(done);
return noop;
return asyncPromise();
},
/**
@@ -201,22 +203,20 @@ var $AnimateProvider = ['$provide', function($provide) {
* @name $animate#removeClass
* @kind function
* @description Removes the provided className CSS class value from the provided element.
* Once complete, the done() callback will be fired (if provided).
* When the function is called a promise is returned that will be resolved at a later time.
* @param {DOMElement} element the element which will have the className value
* removed from it
* @param {string} className the CSS class which will be removed from the element
* @param {Function=} done the callback function (if provided) that will be fired after the
* className value has been removed from the element
* @return {Promise} the animation callback promise
*/
removeClass : function(element, className, done) {
className = isString(className) ?
className :
isArray(className) ? className.join(' ') : '';
removeClass : function(element, className) {
className = !isString(className)
? (isArray(className) ? className.join(' ') : '')
: className;
forEach(element, function (element) {
jqLiteRemoveClass(element, className);
});
async(done);
return noop;
return asyncPromise();
},
/**
@@ -225,22 +225,21 @@ var $AnimateProvider = ['$provide', function($provide) {
* @name $animate#setClass
* @kind function
* @description Adds and/or removes the given CSS classes to and from the element.
* Once complete, the done() callback will be fired (if provided).
* When the function is called a promise is returned that will be resolved at a later time.
* @param {DOMElement} element the element which will have its CSS classes changed
* removed from it
* @param {string} add the CSS classes which will be added to the element
* @param {string} remove the CSS class which will be removed from the element
* @param {Function=} done the callback function (if provided) that will be fired after the
* CSS classes have been set on the element
* @return {Promise} the animation callback promise
*/
setClass : function(element, add, remove, done) {
setClass : function(element, add, remove) {
this.addClass(element, add);
this.removeClass(element, remove);
async(done);
return noop;
return asyncPromise();
},
enabled : noop
enabled : noop,
cancel : noop
};
}];
}];

View File

@@ -113,7 +113,7 @@ var ngIfDirective = ['$animate', function($animate) {
}
if(block) {
previousElements = getBlockNodes(block.clone);
$animate.leave(previousElements, function() {
$animate.leave(previousElements).then(function() {
previousElements = null;
});
block = null;

View File

@@ -198,7 +198,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate'
currentScope = null;
}
if(currentElement) {
$animate.leave(currentElement, function() {
$animate.leave(currentElement).then(function() {
previousElement = null;
});
previousElement = currentElement;
@@ -228,7 +228,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate'
// directives to non existing elements.
var clone = $transclude(newScope, function(clone) {
cleanupLastIncludeContent();
$animate.enter(clone, null, $element, afterAnimation);
$animate.enter(clone, null, $element).then(afterAnimation);
});
currentScope = newScope;

View File

@@ -155,7 +155,7 @@ var ngSwitchDirective = ['$animate', function($animate) {
var selected = getBlockNodes(selectedElements[i].clone);
selectedScopes[i].$destroy();
previousElements[i] = selected;
$animate.leave(selected, function() {
$animate.leave(selected).then(function() {
previousElements.splice(i, 1);
});
}

View File

@@ -264,7 +264,7 @@
*
* Stagger animations are currently only supported within CSS-defined animations.
*
* <h2>JavaScript-defined Animations</h2>
* ## JavaScript-defined Animations
* 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.
*
@@ -395,8 +395,9 @@ angular.module('ngAnimate', ['ng'])
return extractElementNode(elm1) == extractElementNode(elm2);
}
$provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document',
function($delegate, $injector, $sniffer, $rootElement, $$asyncCallback, $rootScope, $document) {
$provide.decorator('$animate',
['$delegate', '$$q', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document',
function($delegate, $$q, $injector, $sniffer, $rootElement, $$asyncCallback, $rootScope, $document) {
var globalAnimationCounter = 0;
$rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
@@ -431,13 +432,16 @@ angular.module('ngAnimate', ['ng'])
}
function runAnimationPostDigest(fn) {
var cancelFn;
$rootScope.$$postDigest(function() {
cancelFn = fn();
});
return function() {
var cancelFn, defer = $$q.defer();
defer.promise.$$cancelFn = function() {
cancelFn && cancelFn();
};
$rootScope.$$postDigest(function() {
cancelFn = fn(function() {
defer.resolve();
});
});
return defer.promise;
}
function resolveElementClasses(element, cache, runningAnimations) {
@@ -678,7 +682,7 @@ angular.module('ngAnimate', ['ng'])
/**
* @ngdoc service
* @name $animate
* @kind function
* @kind object
*
* @description
* The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
@@ -692,6 +696,46 @@ angular.module('ngAnimate', ['ng'])
* Requires the {@link ngAnimate `ngAnimate`} module to be installed.
*
* Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
* ## Callback Promises
* With AngularJS 1.3, each of the animation methods, on the `$animate` service, return a promise when called. The
* promise itself is then resolved once the animation has completed itself, has been cancelled or has been
* skipped due to animations being disabled. (Note that even if the animation is cancelled it will still
* call the resolve function of the animation.)
*
* ```js
* $animate.enter(element, container).then(function() {
* //...this is called once the animation is complete...
* });
* ```
*
* Also note that, due to the nature of the callback promise, if any Angular-specific code (like changing the scope,
* location of the page, etc...) is executed within the callback promise then be sure to wrap the code using
* `$scope.$apply(...)`;
*
* ```js
* $animate.leave(element).then(function() {
* $scope.$apply(function() {
* $location.path('/new-page');
* });
* });
* ```
*
* An animation can also be cancelled by calling the `$animate.cancel(promise)` method with the provided
* promise that was returned when the animation was started.
*
* ```js
* var promise = $animate.addClass(element, 'super-long-animation').then(function() {
* //this will still be called even if cancelled
* });
*
* element.on('click', function() {
* //tooo lazy to wait for the animation to end
* $animate.cancel(promise);
* });
* ```
*
* (Keep in mind that the promise cancellation is unique to `$animate` since promises in
* general cannot be cancelled.)
*
*/
return {
@@ -720,23 +764,22 @@ angular.module('ngAnimate', ['ng'])
* | 10. the .ng-enter-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-enter ng-enter-active" |
* | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-enter ng-enter-active" |
* | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
* | 13. The doneCallback() callback is fired (if provided) | class="my-animation" |
* | 13. The returned promise is resolved. | class="my-animation" |
*
* @param {DOMElement} element the element that will be the focus of the enter animation
* @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation
* @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
* @return {function} the animation cancellation function
* @return {Promise} the animation callback promise
*/
enter : function(element, parentElement, afterElement, doneCallback) {
enter : function(element, parentElement, afterElement) {
element = angular.element(element);
parentElement = prepareElement(parentElement);
afterElement = prepareElement(afterElement);
classBasedAnimationsBlocked(element, true);
$delegate.enter(element, parentElement, afterElement);
return runAnimationPostDigest(function() {
return performAnimation('enter', 'ng-enter', stripCommentsFromElement(element), parentElement, afterElement, noop, doneCallback);
return runAnimationPostDigest(function(done) {
return performAnimation('enter', 'ng-enter', stripCommentsFromElement(element), parentElement, afterElement, noop, done);
});
},
@@ -765,22 +808,21 @@ angular.module('ngAnimate', ['ng'])
* | 10. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-leave ng-leave-active" |
* | 11. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
* | 12. The element is removed from the DOM | ... |
* | 13. The doneCallback() callback is fired (if provided) | ... |
* | 13. The returned promise is resolved. | ... |
*
* @param {DOMElement} element the element that will be the focus of the leave animation
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
* @return {function} the animation cancellation function
* @return {Promise} the animation callback promise
*/
leave : function(element, doneCallback) {
leave : function(element) {
element = angular.element(element);
cancelChildAnimations(element);
classBasedAnimationsBlocked(element, true);
this.enabled(false, element);
return runAnimationPostDigest(function() {
return runAnimationPostDigest(function(done) {
return performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
$delegate.leave(element);
}, doneCallback);
}, done);
});
},
@@ -810,15 +852,14 @@ angular.module('ngAnimate', ['ng'])
* | 10. the .ng-move-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-move ng-move-active" |
* | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-move ng-move-active" |
* | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
* | 13. The doneCallback() callback is fired (if provided) | class="my-animation" |
* | 13. The returned promise is resolved. | class="my-animation" |
*
* @param {DOMElement} element the element that will be the focus of the move animation
* @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation
* @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
* @return {function} the animation cancellation function
* @return {Promise} the animation callback promise
*/
move : function(element, parentElement, afterElement, doneCallback) {
move : function(element, parentElement, afterElement) {
element = angular.element(element);
parentElement = prepareElement(parentElement);
afterElement = prepareElement(afterElement);
@@ -826,8 +867,8 @@ angular.module('ngAnimate', ['ng'])
cancelChildAnimations(element);
classBasedAnimationsBlocked(element, true);
$delegate.move(element, parentElement, afterElement);
return runAnimationPostDigest(function() {
return performAnimation('move', 'ng-move', stripCommentsFromElement(element), parentElement, afterElement, noop, doneCallback);
return runAnimationPostDigest(function(done) {
return performAnimation('move', 'ng-move', stripCommentsFromElement(element), parentElement, afterElement, noop, done);
});
},
@@ -854,15 +895,14 @@ angular.module('ngAnimate', ['ng'])
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation super super-add super-add-active" |
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
* | 9. The super class is kept on the element | class="my-animation super" |
* | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" |
* | 10. The returned promise is resolved. | class="my-animation super" |
*
* @param {DOMElement} element the element that will be animated
* @param {string} className the CSS class that will be added to the element and then animated
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
* @return {function} the animation cancellation function
* @return {Promise} the animation callback promise
*/
addClass : function(element, className, doneCallback) {
return this.setClass(element, className, [], doneCallback);
addClass : function(element, className) {
return this.setClass(element, className, []);
},
/**
@@ -887,16 +927,15 @@ angular.module('ngAnimate', ['ng'])
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" |
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate super-remove super-remove-active" |
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
* | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
* | 9. The returned promise is resolved. | class="my-animation" |
*
*
* @param {DOMElement} 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()=} doneCallback the callback function that will be called once the animation is complete
* @return {function} the animation cancellation function
* @return {Promise} the animation callback promise
*/
removeClass : function(element, className, doneCallback) {
return this.setClass(element, [], className, doneCallback);
removeClass : function(element, className) {
return this.setClass(element, [], className);
},
/**
@@ -916,68 +955,70 @@ angular.module('ngAnimate', ['ng'])
* | 5. the .on, .on-add-active and .off-remove-active classes are added and .off is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active” |
* | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
* | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
* | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation on" |
* | 9. The returned promise is resolved. | class="my-animation on" |
*
* @param {DOMElement} element the element which will have its CSS classes changed
* removed from it
* @param {string} add the CSS classes which will be added to the element
* @param {string} remove the CSS class which will be removed from the element
* @param {function=} done the callback function (if provided) that will be fired after the
* CSS classes have been set on the element
* @return {function} the animation cancellation function
* @return {Promise} the animation callback promise
*/
setClass : function(element, add, remove, doneCallback) {
setClass : function(element, add, remove) {
var STORAGE_KEY = '$$animateClasses';
element = angular.element(element);
element = stripCommentsFromElement(element);
if (classBasedAnimationsBlocked(element)) {
return $delegate.setClass(element, add, remove, doneCallback);
return $delegate.setClass(element, add, remove);
}
add = isArray(add) ? add : add.split(' ');
remove = isArray(remove) ? remove : remove.split(' ');
doneCallback = doneCallback || noop;
var cache = element.data(STORAGE_KEY);
if (cache) {
cache.callbacks.push(doneCallback);
cache.add = cache.add.concat(add);
cache.remove = cache.remove.concat(remove);
//the digest cycle will combine all the animations into one function
return;
return cache.promise;
} else {
element.data(STORAGE_KEY, cache = {
callbacks : [doneCallback],
add : add,
remove : remove
});
}
return runAnimationPostDigest(function() {
return cache.promise = runAnimationPostDigest(function(done) {
var cache = element.data(STORAGE_KEY);
var callbacks = cache.callbacks;
element.removeData(STORAGE_KEY);
var state = element.data(NG_ANIMATE_STATE) || {};
var classes = resolveElementClasses(element, cache, state.active);
return !classes
? $$asyncCallback(onComplete)
? done()
: performAnimation('setClass', classes, element, null, null, function() {
$delegate.setClass(element, classes[0], classes[1]);
}, onComplete);
function onComplete() {
forEach(callbacks, function(fn) {
fn();
});
}
}, done);
});
},
/**
* @ngdoc method
* @name $animate#cancel
* @kind function
*
* @param {Promise} animationPromise The animation promise that is returned when an animation is started.
*
* @description
* Cancels the provided animation.
*/
cancel : function(promise) {
promise.$$cancelFn();
},
/**
* @ngdoc method
* @name $animate#enabled
@@ -1183,11 +1224,7 @@ angular.module('ngAnimate', ['ng'])
function fireDoneCallbackAsync() {
fireDOMCallback('close');
if (doneCallback) {
$$asyncCallback(function() {
doneCallback();
});
}
doneCallback();
}
//it is less complicated to use a flag than managing and canceling

View File

@@ -767,14 +767,22 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
};
});
$provide.decorator('$animate', ['$delegate', '$$asyncCallback',
function($delegate, $$asyncCallback) {
$provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser',
function($delegate, $$asyncCallback, $timeout, $browser) {
var animate = {
queue : [],
cancel : $delegate.cancel,
enabled : $delegate.enabled,
triggerCallbacks : function() {
triggerCallbackEvents : function() {
$$asyncCallback.flush();
},
triggerCallbackPromise : function() {
$timeout.flush(0);
},
triggerCallbacks : function() {
this.triggerCallbackEvents();
this.triggerCallbackPromise();
},
triggerReflow : function() {
angular.forEach(reflowQueue, function(fn) {
fn();

View File

@@ -206,7 +206,7 @@ function ngViewFactory( $route, $anchorScroll, $animate) {
currentScope = null;
}
if(currentElement) {
$animate.leave(currentElement, function() {
$animate.leave(currentElement).then(function() {
previousElement = null;
});
previousElement = currentElement;
@@ -229,7 +229,7 @@ function ngViewFactory( $route, $anchorScroll, $animate) {
// function is called before linking the content, which would apply child
// directives to non existing elements.
var clone = $transclude(newScope, function(clone) {
$animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
$animate.enter(clone, null, currentElement || $element).then(function onNgViewEnter () {
if (angular.isDefined(autoScrollExp)
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
$anchorScroll();

View File

@@ -51,6 +51,7 @@
"isBoolean": false,
"trim": false,
"isElement": false,
"isPromiseLike": false,
"makeMap": false,
"map": false,
"size": false,

View File

@@ -50,6 +50,11 @@ beforeEach(function() {
toBePristine: cssMatcher('ng-pristine', 'ng-dirty'),
toBeUntouched: cssMatcher('ng-untouched', 'ng-touched'),
toBeTouched: cssMatcher('ng-touched', 'ng-untouched'),
toBeAPromise: function() {
this.message = valueFn(
"Expected object " + (this.isNot ? "not ": "") + "to be a promise");
return isPromiseLike(this.actual);
},
toBeShown: function() {
this.message = valueFn(
"Expected element " + (this.isNot ? "": "not ") + "to have 'ng-hide' class");

View File

@@ -57,18 +57,18 @@ describe("$animate", function() {
expect(element).toBeHidden();
}));
it("should run each method and return a noop function", inject(function($animate, $document) {
it("should run each method and return a promise", inject(function($animate, $document) {
var element = jqLite('<div></div>');
var move = jqLite('<div></div>');
var parent = jqLite($document[0].body);
parent.append(move);
expect($animate.enter(element, parent)).toBe(noop);
expect($animate.move(element, move)).toBe(noop);
expect($animate.addClass(element, 'on')).toBe(noop);
expect($animate.addClass(element, 'off')).toBe(noop);
expect($animate.setClass(element, 'on', 'off')).toBe(noop);
expect($animate.leave(element)).toBe(noop);
expect($animate.enter(element, parent)).toBeAPromise();
expect($animate.move(element, move)).toBeAPromise();
expect($animate.addClass(element, 'on')).toBeAPromise();
expect($animate.removeClass(element, 'off')).toBeAPromise();
expect($animate.setClass(element, 'on', 'off')).toBeAPromise();
expect($animate.leave(element)).toBeAPromise();
}));
it("should add and remove classes on SVG elements", inject(function($animate) {

View File

@@ -441,7 +441,7 @@ describe('ngClass animations', function() {
$compile(element)($rootScope);
var enterComplete = false;
$animate.enter(element, $rootElement, null, function() {
$animate.enter(element, $rootElement, null).then(function() {
enterComplete = true;
});

View File

@@ -315,14 +315,12 @@ describe('ngIf animations', function () {
it('should destroy the previous leave animation if a new one takes place', function() {
module(function($provide) {
$provide.value('$animate', {
enabled : function() { return true; },
leave : function() {
//DOM operation left blank
},
enter : function(element, parent) {
parent.append(element);
}
$provide.decorator('$animate', function($delegate, $$q) {
var emptyPromise = $$q.defer().promise;
$delegate.leave = function() {
return emptyPromise;
};
return $delegate;
});
});
inject(function ($compile, $rootScope, $animate) {

View File

@@ -693,14 +693,12 @@ describe('ngInclude animations', function() {
it('should destroy the previous leave animation if a new one takes place', function() {
module(function($provide) {
$provide.value('$animate', {
enabled : function() { return true; },
leave : function() {
//DOM operation left blank
},
enter : function(element, parent, after) {
angular.element(after).after(element);
}
$provide.decorator('$animate', function($delegate, $$q) {
var emptyPromise = $$q.defer().promise;
$delegate.leave = function() {
return emptyPromise;
};
return $delegate;
});
});
inject(function ($compile, $rootScope, $animate, $templateCache) {

View File

@@ -397,14 +397,12 @@ describe('ngSwitch animations', function() {
it('should destroy the previous leave animation if a new one takes place', function() {
module(function($provide) {
$provide.value('$animate', {
enabled : function() { return true; },
leave : function() {
//DOM operation left blank
},
enter : function(element, parent, after) {
angular.element(after).after(element);
}
$provide.decorator('$animate', function($delegate, $$q) {
var emptyPromise = $$q.defer().promise;
$delegate.leave = function() {
return emptyPromise;
};
return $delegate;
});
});
inject(function ($compile, $rootScope, $animate, $templateCache) {

View File

@@ -566,7 +566,7 @@ describe("ngAnimate", function() {
expect(child.attr('class')).toContain('ng-enter');
expect(child.attr('class')).toContain('ng-enter-active');
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
//move
element.append(after);
@@ -577,7 +577,7 @@ describe("ngAnimate", function() {
expect(child.attr('class')).toContain('ng-move');
expect(child.attr('class')).toContain('ng-move-active');
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
//hide
$animate.addClass(child, 'ng-hide');
@@ -631,72 +631,72 @@ describe("ngAnimate", function() {
});
inject(function($animate, $sniffer, $rootScope, $timeout) {
var fn;
var promise;
$animate.enabled(true);
$rootScope.$digest();
element[0].removeChild(child[0]);
child.addClass('track-me');
//enter
fn = $animate.enter(child, element);
promise = $animate.enter(child, element);
$rootScope.$digest();
$animate.triggerReflow();
expect(captures.enter).toBeUndefined();
fn();
$animate.cancel(promise);
expect(captures.enter).toBeTruthy();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
//move
element.append(after);
fn = $animate.move(child, element, after);
promise = $animate.move(child, element, after);
$rootScope.$digest();
$animate.triggerReflow();
expect(captures.move).toBeUndefined();
fn();
$animate.cancel(promise);
expect(captures.move).toBeTruthy();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
//addClass
fn = $animate.addClass(child, 'ng-hide');
promise = $animate.addClass(child, 'ng-hide');
$rootScope.$digest();
$animate.triggerReflow();
expect(captures.addClass).toBeUndefined();
fn();
$animate.cancel(promise);
expect(captures.addClass).toBeTruthy();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
//removeClass
fn = $animate.removeClass(child, 'ng-hide');
promise = $animate.removeClass(child, 'ng-hide');
$rootScope.$digest();
$animate.triggerReflow();
expect(captures.removeClass).toBeUndefined();
fn();
$animate.cancel(promise);
expect(captures.removeClass).toBeTruthy();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
//setClass
child.addClass('red');
fn = $animate.setClass(child, 'blue', 'red');
promise = $animate.setClass(child, 'blue', 'red');
$rootScope.$digest();
$animate.triggerReflow();
expect(captures.setClass).toBeUndefined();
fn();
$animate.cancel(promise);
expect(captures.setClass).toBeTruthy();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
//leave
fn = $animate.leave(child);
promise = $animate.leave(child);
$rootScope.$digest();
expect(captures.leave).toBeUndefined();
fn();
$animate.cancel(promise);
expect(captures.leave).toBeTruthy();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
});
});
@@ -844,7 +844,7 @@ describe("ngAnimate", function() {
expect(element).toHaveClass('ng-animate');
removeClassDone();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(element).not.toHaveClass('ng-animate');
});
@@ -854,7 +854,7 @@ describe("ngAnimate", function() {
inject(function($animate, $rootScope, $sniffer, $timeout) {
var completed = false;
$animate.enter(child, element, null, function() {
$animate.enter(child, element, null).then(function() {
completed = true;
});
$rootScope.$digest();
@@ -870,7 +870,7 @@ describe("ngAnimate", function() {
$animate.triggerReflow();
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(completed).toBe(true);
}));
@@ -1945,7 +1945,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('ng-enter')).toBe(true);
expect(element.hasClass('ng-enter-active')).toBe(true);
browserTrigger(element,'transitionend', { timeStamp: Date.now() + 22000, elapsedTime: 22 });
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
}
expect(element.hasClass('abc')).toBe(true);
@@ -1959,7 +1959,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('ng-enter')).toBe(true);
expect(element.hasClass('ng-enter-active')).toBe(true);
browserTrigger(element,'transitionend', { timeStamp: Date.now() + 11000, elapsedTime: 11 });
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
}
expect(element.hasClass('xyz')).toBe(true);
}));
@@ -2029,12 +2029,12 @@ describe("ngAnimate", function() {
body.append($rootElement);
var flag = false;
$animate.enter(element, parent, null, function() {
$animate.enter(element, parent, null).then(function() {
flag = true;
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(flag).toBe(true);
}));
@@ -2049,12 +2049,12 @@ describe("ngAnimate", function() {
body.append($rootElement);
var flag = false;
$animate.leave(element, function() {
$animate.leave(element).then(function() {
flag = true;
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(flag).toBe(true);
}));
@@ -2070,12 +2070,12 @@ describe("ngAnimate", function() {
body.append($rootElement);
var flag = false;
$animate.move(element, parent, parent2, function() {
$animate.move(element, parent, parent2).then(function() {
flag = true;
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(flag).toBe(true);
expect(element.parent().id).toBe(parent2.id);
@@ -2093,19 +2093,19 @@ describe("ngAnimate", function() {
body.append($rootElement);
var signature = '';
$animate.addClass(element, 'on', function() {
$animate.addClass(element, 'on').then(function() {
signature += 'A';
});
$rootScope.$digest();
$animate.triggerReflow();
$animate.removeClass(element, 'on', function() {
$animate.removeClass(element, 'on').then(function() {
signature += 'B';
});
$rootScope.$digest();
$animate.triggerReflow();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(signature).toBe('AB');
}));
@@ -2122,13 +2122,13 @@ describe("ngAnimate", function() {
expect(element.hasClass('off')).toBe(true);
var signature = '';
$animate.setClass(element, 'on', 'off', function() {
$animate.setClass(element, 'on', 'off').then(function() {
signature += 'Z';
});
$rootScope.$digest();
$animate.triggerReflow();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(signature).toBe('Z');
expect(element.hasClass('on')).toBe(true);
@@ -2162,27 +2162,29 @@ describe("ngAnimate", function() {
steps.push(['close', data.className, data.event]);
});
$animate.addClass(element, 'klass', function() {
$animate.addClass(element, 'klass').then(function() {
steps.push(['done', 'klass', 'addClass']);
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackEvents();
expect(steps.pop()).toEqual(['before', 'klass', 'addClass']);
$animate.triggerReflow();
$animate.triggerCallbacks();
$animate.triggerCallbackEvents();
expect(steps.pop()).toEqual(['after', 'klass', 'addClass']);
browserTrigger(element,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
$animate.triggerCallbacks();
$animate.triggerCallbackEvents();
expect(steps.shift()).toEqual(['close', 'klass', 'addClass']);
$animate.triggerCallbackPromise();
expect(steps.shift()).toEqual(['done', 'klass', 'addClass']);
}));
@@ -2208,7 +2210,7 @@ describe("ngAnimate", function() {
$animate.enter(element, parent);
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackEvents();
expect(steps.shift()).toEqual(['before', 'ng-enter', 'enter']);
expect(steps.shift()).toEqual(['after', 'ng-enter', 'enter']);
@@ -2238,12 +2240,12 @@ describe("ngAnimate", function() {
body.append($rootElement);
var flag = false;
$animate.removeClass(element, 'ng-hide', function() {
$animate.removeClass(element, 'ng-hide').then(function() {
flag = true;
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(flag).toBe(true);
}));
@@ -2262,7 +2264,7 @@ describe("ngAnimate", function() {
var element = parent.find('span');
var flag = false;
$animate.addClass(element, 'ng-hide', function() {
$animate.addClass(element, 'ng-hide').then(function() {
flag = true;
});
$rootScope.$digest();
@@ -2271,7 +2273,7 @@ describe("ngAnimate", function() {
$animate.triggerReflow();
browserTrigger(element,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(flag).toBe(true);
}));
@@ -2286,12 +2288,12 @@ describe("ngAnimate", function() {
element.addClass('custom');
var flag = false;
$animate.removeClass(element, 'ng-hide', function() {
$animate.removeClass(element, 'ng-hide').then(function() {
flag = true;
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(flag).toBe(true);
}));
@@ -2310,11 +2312,11 @@ describe("ngAnimate", function() {
var element = parent.find('span');
var signature = '';
$animate.removeClass(element, 'ng-hide', function() {
$animate.removeClass(element, 'ng-hide').then(function() {
signature += 'A';
});
$rootScope.$digest();
$animate.addClass(element, 'ng-hide', function() {
$animate.addClass(element, 'ng-hide').then(function() {
signature += 'B';
});
$rootScope.$digest();
@@ -2324,7 +2326,7 @@ describe("ngAnimate", function() {
$animate.triggerReflow();
browserTrigger(element,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 9 });
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(signature).toBe('AB');
}));
});
@@ -2462,7 +2464,7 @@ describe("ngAnimate", function() {
var signature = '';
$animate.addClass(element,'klass', function() {
$animate.addClass(element,'klass').then(function() {
signature += 'A';
});
$rootScope.$digest();
@@ -2470,13 +2472,13 @@ describe("ngAnimate", function() {
expect(element.hasClass('klass')).toBe(true);
$animate.removeClass(element,'klass', function() {
$animate.removeClass(element,'klass').then(function() {
signature += 'B';
});
$rootScope.$digest();
$animate.triggerReflow();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(element.hasClass('klass')).toBe(false);
expect(signature).toBe('AB');
}));
@@ -2497,7 +2499,7 @@ describe("ngAnimate", function() {
var signature = '';
$animate.addClass(element,'klass', function() {
$animate.addClass(element,'klass').then(function() {
signature += '1';
});
$rootScope.$digest();
@@ -2510,10 +2512,10 @@ describe("ngAnimate", function() {
browserTrigger(element,'transitionend', { timeStamp: Date.now() + 3000, elapsedTime: 3 });
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
//this cancels out the older animation
$animate.removeClass(element,'klass', function() {
$animate.removeClass(element,'klass').then(function() {
signature += '2';
});
$rootScope.$digest();
@@ -2529,7 +2531,7 @@ describe("ngAnimate", function() {
browserTrigger(element,'transitionend', { timeStamp: Date.now() + 3000, elapsedTime: 3 });
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(element.hasClass('klass')).toBe(false);
expect(signature).toBe('12');
@@ -2546,7 +2548,7 @@ describe("ngAnimate", function() {
var signature = '';
$animate.addClass(element,'klassy', function() {
$animate.addClass(element,'klassy').then(function() {
signature += 'X';
});
$rootScope.$digest();
@@ -2556,7 +2558,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('klassy')).toBe(true);
$animate.removeClass(element,'klassy', function() {
$animate.removeClass(element,'klassy').then(function() {
signature += 'Y';
});
$rootScope.$digest();
@@ -2566,7 +2568,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('klassy')).toBe(false);
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(signature).toBe('XY');
}));
@@ -2580,7 +2582,7 @@ describe("ngAnimate", function() {
var signature = '';
$animate.addClass(element[0],'klassy', function() {
$animate.addClass(element[0],'klassy').then(function() {
signature += 'X';
});
$rootScope.$digest();
@@ -2590,7 +2592,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('klassy')).toBe(true);
$animate.removeClass(element[0],'klassy', function() {
$animate.removeClass(element[0],'klassy').then(function() {
signature += 'Y';
});
$rootScope.$digest();
@@ -2600,7 +2602,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('klassy')).toBe(false);
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(signature).toBe('XY');
}));
@@ -2619,7 +2621,7 @@ describe("ngAnimate", function() {
var signature = '';
$animate.addClass(element,'klass', function() {
$animate.addClass(element,'klass').then(function() {
signature += 'd';
});
$rootScope.$digest();
@@ -2633,10 +2635,10 @@ describe("ngAnimate", function() {
expect(element.hasClass('klass-add-active')).toBe(false);
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(element.hasClass('klass')).toBe(true);
$animate.removeClass(element,'klass', function() {
$animate.removeClass(element,'klass').then(function() {
signature += 'b';
});
$rootScope.$digest();
@@ -2650,7 +2652,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('klass-remove-active')).toBe(false);
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(element.hasClass('klass')).toBe(false);
expect(signature).toBe('db');
@@ -2671,7 +2673,7 @@ describe("ngAnimate", function() {
var element = jqLite(parent.find('span'));
var flag = false;
$animate.addClass(element,'one two', function() {
$animate.addClass(element,'one two').then(function() {
flag = true;
});
@@ -2692,7 +2694,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('two-add-active')).toBe(false);
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(element.hasClass('one')).toBe(true);
expect(element.hasClass('two')).toBe(true);
@@ -2719,7 +2721,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('two')).toBe(true);
var flag = false;
$animate.removeClass(element,'one two', function() {
$animate.removeClass(element,'one two').then(function() {
flag = true;
});
$rootScope.$digest();
@@ -2739,7 +2741,7 @@ describe("ngAnimate", function() {
expect(element.hasClass('two-remove-active')).toBe(false);
}
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(element.hasClass('one')).toBe(false);
expect(element.hasClass('two')).toBe(false);
@@ -2901,7 +2903,7 @@ describe("ngAnimate", function() {
child.addClass('usurper');
$animate.leave(child);
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(child.hasClass('ng-enter')).toBe(false);
expect(child.hasClass('ng-enter-active')).toBe(false);
@@ -2955,10 +2957,10 @@ describe("ngAnimate", function() {
// if($sniffer.transitions) {
// expect(element.hasClass('on')).toBe(false);
// expect(element.hasClass('on-add')).toBe(true);
// $animate.triggerCallbacks();
// $animate.triggerCallbackPromise();
// }
//
// $animate.triggerCallbacks();
// $animate.triggerCallbackPromise();
//
// expect(element.hasClass('on')).toBe(true);
// expect(element.hasClass('on-add')).toBe(false);
@@ -2971,7 +2973,7 @@ describe("ngAnimate", function() {
// $timeout.flush(10000);
// }
//
// $animate.triggerCallbacks();
// $animate.triggerCallbackPromise();
// expect(element.hasClass('on')).toBe(false);
// expect(element.hasClass('on-remove')).toBe(false);
// expect(element.hasClass('on-remove-active')).toBe(false);
@@ -3014,11 +3016,11 @@ describe("ngAnimate", function() {
//
// if($sniffer.transitions) {
// expect(element).toBeShown(); //still showing
// $animate.triggerCallbacks();
// $animate.triggerCallbackPromise();
// expect(element).toBeShown();
// $timeout.flush(5555);
// }
// $animate.triggerCallbacks();
// $animate.triggerCallbackPromise();
// expect(element).toBeHidden();
//
// expect(element.hasClass('showing')).toBe(false);
@@ -3027,11 +3029,11 @@ describe("ngAnimate", function() {
//
// if($sniffer.transitions) {
// expect(element).toBeHidden();
// $animate.triggerCallbacks();
// $animate.triggerCallbackPromise();
// expect(element).toBeHidden();
// $timeout.flush(5580);
// }
// $animate.triggerCallbacks();
// $animate.triggerCallbackPromise();
// expect(element).toBeShown();
//
// expect(element.hasClass('showing')).toBe(true);
@@ -3311,20 +3313,20 @@ describe("ngAnimate", function() {
angular.element($document[0].body).append($rootElement);
var log = '';
$animate.addClass(element, 'one', function() {
$animate.addClass(element, 'one').then(function() {
log += 'A';
});
$rootScope.$digest();
$animate.addClass(element, 'one', function() {
$animate.addClass(element, 'one').then(function() {
log += 'B';
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
$animate.triggerReflow();
continueAnimation();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(log).toBe('BA');
});
});
@@ -3349,13 +3351,13 @@ describe("ngAnimate", function() {
count++;
};
$animate.addClass(element, 'on', callback);
$animate.addClass(element, 'on', callback);
$animate.removeClass(element, 'on', callback);
$animate.removeClass(element, 'on', callback);
$animate.addClass(element, 'on').then(callback);
$animate.addClass(element, 'on').then(callback);
$animate.removeClass(element, 'on').then(callback);
$animate.removeClass(element, 'on').then(callback);
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(spy).not.toHaveBeenCalled();
expect(count).toBe(4);
@@ -4065,7 +4067,7 @@ describe("ngAnimate", function() {
forEach(element.children(), function(kid) {
browserTrigger(kid, 'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
});
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
$rootScope.items = [];
$rootScope.$digest();
@@ -4101,12 +4103,12 @@ describe("ngAnimate", function() {
jqLite($document[0].body).append($rootElement);
var enterDone = false;
$animate.enter(element, $rootElement, null, function() {
$animate.enter(element, $rootElement).then(function() {
enterDone = true;
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(captures['enter']).toBeUndefined();
expect(enterDone).toBe(true);
@@ -4114,12 +4116,12 @@ describe("ngAnimate", function() {
element.addClass('prefixed-animation');
var leaveDone = false;
$animate.leave(element, function() {
$animate.leave(element).then(function() {
leaveDone = true;
});
$rootScope.$digest();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(captures['leave']).toBe(true);
expect(leaveDone).toBe(true);
@@ -4157,14 +4159,14 @@ describe("ngAnimate", function() {
var element = upperElement.find('span');
var leaveDone = false;
$animate.leave(element, function() {
$animate.leave(element).then(function() {
leaveDone = true;
});
$rootScope.$digest();
$animate.triggerCallbacks();
expect(captures['leave']).toBe(true);
expect(captures.leave).toBe(true);
expect(leaveDone).toBe(true);
});
});
@@ -4187,7 +4189,7 @@ describe("ngAnimate", function() {
jqLite($document[0].body).append($rootElement);
var ready = false;
$animate.addClass(element, 'on', function() {
$animate.addClass(element, 'on').then(function() {
ready = true;
});
$rootScope.$digest();
@@ -4198,18 +4200,18 @@ describe("ngAnimate", function() {
browserTrigger(element, 'transitionend', { timeStamp: Date.now(), elapsedTime: 5 });
$animate.triggerReflow();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(ready).toBe(true);
ready = false;
$animate.removeClass(element, 'on', function() {
$animate.removeClass(element, 'on').then(function() {
ready = true;
});
$rootScope.$digest();
$animate.triggerReflow();
browserTrigger(element, 'transitionend', { timeStamp: Date.now(), elapsedTime: 1 });
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(ready).toBe(true);
}));
@@ -4228,13 +4230,13 @@ describe("ngAnimate", function() {
jqLite($document[0].body).append($rootElement);
var ready = false;
$animate.removeClass(element, 'on', function() {
$animate.removeClass(element, 'on').then(function() {
ready = true;
});
$rootScope.$digest();
$animate.triggerReflow();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(ready).toBe(true);
}));
@@ -4253,22 +4255,22 @@ describe("ngAnimate", function() {
jqLite($document[0].body).append($rootElement);
var signature = '';
$animate.removeClass(element, 'on', function() {
$animate.removeClass(element, 'on').then(function() {
signature += 'A';
});
$rootScope.$digest();
$animate.addClass(element, 'on', function() {
$animate.addClass(element, 'on').then(function() {
signature += 'B';
});
$rootScope.$digest();
$animate.triggerReflow();
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(signature).toBe('A');
browserTrigger(element, 'transitionend', { timeStamp: Date.now(), elapsedTime: 2000 });
$animate.triggerCallbacks();
$animate.triggerCallbackPromise();
expect(signature).toBe('AB');
}));

View File

@@ -846,14 +846,12 @@ describe('ngView animations', function() {
it('should destroy the previous leave animation if a new one takes place', function() {
module(function($provide) {
$provide.value('$animate', {
enabled : function() { return true; },
leave : function() {
//DOM operation left blank
},
enter : function(element, parent, after) {
angular.element(after).after(element);
}
$provide.decorator('$animate', function($delegate, $$q) {
var emptyPromise = $$q.defer().promise;
$delegate.leave = function() {
return emptyPromise;
};
return $delegate;
});
});
inject(function ($compile, $rootScope, $animate, $location) {