aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ngAnimate/animate.js41
-rw-r--r--test/ngAnimate/animateSpec.js69
2 files changed, 102 insertions, 8 deletions
diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js
index 62f6381d..26fe982d 100644
--- a/src/ngAnimate/animate.js
+++ b/src/ngAnimate/animate.js
@@ -1043,7 +1043,7 @@ angular.module('ngAnimate', ['ng'])
return parentID + '-' + extractElementNode(element).className;
}
- function animateSetup(element, className) {
+ function animateSetup(element, className, calculationDecorator) {
var cacheKey = getCacheKey(element);
var eventCacheKey = cacheKey + ' ' + className;
var stagger = {};
@@ -1061,9 +1061,16 @@ angular.module('ngAnimate', ['ng'])
applyClasses && element.removeClass(staggerClassName);
}
+ /* the animation itself may need to add/remove special CSS classes
+ * before calculating the anmation styles */
+ calculationDecorator = calculationDecorator ||
+ function(fn) { return fn(); };
+
element.addClass(className);
- var timings = getElementAnimationDetails(element, eventCacheKey);
+ var timings = calculationDecorator(function() {
+ return getElementAnimationDetails(element, eventCacheKey);
+ });
/* there is no point in performing a reflow if the animation
timeout is empty (this would cause a flicker bug normally
@@ -1228,8 +1235,8 @@ angular.module('ngAnimate', ['ng'])
return style;
}
- function animateBefore(element, className) {
- if(animateSetup(element, className)) {
+ function animateBefore(element, className, calculationDecorator) {
+ if(animateSetup(element, className, calculationDecorator)) {
return function(cancelled) {
cancelled && animateClose(element, className);
};
@@ -1324,7 +1331,18 @@ angular.module('ngAnimate', ['ng'])
},
beforeAddClass : function(element, className, animationCompleted) {
- var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'));
+ var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'), function(fn) {
+
+ /* when a CSS class is added to an element then the transition style that
+ * is applied is the transition defined on the element when the CSS class
+ * is added at the time of the animation. This is how CSS3 functions
+ * outside of ngAnimate. */
+ element.addClass(className);
+ var timings = fn();
+ element.removeClass(className);
+ return timings;
+ });
+
if(cancellationMethod) {
afterReflow(element, function() {
unblockTransitions(element);
@@ -1341,7 +1359,18 @@ angular.module('ngAnimate', ['ng'])
},
beforeRemoveClass : function(element, className, animationCompleted) {
- var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'));
+ var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'), function(fn) {
+ /* when classes are removed from an element then the transition style
+ * that is applied is the transition defined on the element without the
+ * CSS class being there. This is how CSS3 functions outside of ngAnimate.
+ * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
+ var klass = element.attr('class');
+ element.removeClass(className);
+ var timings = fn();
+ element.attr('class', klass);
+ return timings;
+ });
+
if(cancellationMethod) {
afterReflow(element, function() {
unblockTransitions(element);
diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js
index db40d544..99527cc4 100644
--- a/test/ngAnimate/animateSpec.js
+++ b/test/ngAnimate/animateSpec.js
@@ -2801,14 +2801,14 @@ describe("ngAnimate", function() {
$animate.removeClass(element, 'base-class one two');
//still true since we're before the reflow
- expect(element.hasClass('base-class')).toBe(true);
+ expect(element.hasClass('base-class')).toBe(false);
//this will cancel the remove animation
$animate.addClass(element, 'base-class one two');
//the cancellation was a success and the class was added right away
//since there was no successive animation for the after animation
- expect(element.hasClass('base-class')).toBe(true);
+ expect(element.hasClass('base-class')).toBe(false);
//the reflow...
$timeout.flush();
@@ -3048,5 +3048,70 @@ describe("ngAnimate", function() {
expect(leaveDone).toBe(true);
});
});
+
+ it('should respect the most relevant CSS transition property if defined in multiple classes',
+ inject(function($sniffer, $compile, $rootScope, $rootElement, $animate, $timeout) {
+
+ if (!$sniffer.transitions) return;
+
+ ss.addRule('.base-class', '-webkit-transition:1s linear all;' +
+ 'transition:1s linear all;');
+
+ ss.addRule('.base-class.on', '-webkit-transition:5s linear all;' +
+ 'transition:5s linear all;');
+
+ $animate.enabled(true);
+
+ var element = $compile('<div class="base-class"></div>')($rootScope);
+ $rootElement.append(element);
+ jqLite($document[0].body).append($rootElement);
+
+ var ready = false;
+ $animate.addClass(element, 'on', function() {
+ ready = true;
+ });
+
+ $timeout.flush(10);
+ browserTrigger(element, 'transitionend', { timeStamp: Date.now(), elapsedTime: 1 });
+ $timeout.flush(1);
+ expect(ready).toBe(false);
+
+ browserTrigger(element, 'transitionend', { timeStamp: Date.now(), elapsedTime: 5 });
+ $timeout.flush(1);
+ expect(ready).toBe(true);
+
+ ready = false;
+ $animate.removeClass(element, 'on', function() {
+ ready = true;
+ });
+
+ $timeout.flush(10);
+ browserTrigger(element, 'transitionend', { timeStamp: Date.now(), elapsedTime: 1 });
+ $timeout.flush(1);
+ expect(ready).toBe(true);
+ }));
+
+ it('should not apply a transition upon removal of a class that has a transition',
+ inject(function($sniffer, $compile, $rootScope, $rootElement, $animate, $timeout) {
+
+ if (!$sniffer.transitions) return;
+
+ ss.addRule('.base-class.on', '-webkit-transition:5s linear all;' +
+ 'transition:5s linear all;');
+
+ $animate.enabled(true);
+
+ var element = $compile('<div class="base-class on"></div>')($rootScope);
+ $rootElement.append(element);
+ jqLite($document[0].body).append($rootElement);
+
+ var ready = false;
+ $animate.removeClass(element, 'on', function() {
+ ready = true;
+ });
+
+ $timeout.flush(1);
+ expect(ready).toBe(true);
+ }));
});
});