aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Deak2013-11-10 21:36:47 +0000
committerMatias Niemelä2013-11-21 23:37:01 -0500
commitc42d0a041890b39fc98afd357ec1307a3a36208d (patch)
tree4c9853aaa18ed3538d96117d297235fc1335d83e
parent3fbb25e25cc9bd1ddad8efab9f43749735e53454 (diff)
downloadangular.js-c42d0a041890b39fc98afd357ec1307a3a36208d.tar.bz2
fix(ngAnimate): correctly retain and restore existing styles during and after animation
Closes #4869
-rw-r--r--src/ngAnimate/animate.js25
-rw-r--r--test/ngAnimate/animateSpec.js50
2 files changed, 60 insertions, 15 deletions
diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js
index 81d20043..26d48012 100644
--- a/src/ngAnimate/animate.js
+++ b/src/ngAnimate/animate.js
@@ -876,13 +876,6 @@ angular.module('ngAnimate', ['ng'])
}, 10, false);
}
- function applyStyle(node, style) {
- var oldStyle = node.getAttribute('style') || '';
- var newStyle = (oldStyle.length > 0 ? '; ' : '') + style;
- node.setAttribute('style', newStyle);
- return oldStyle;
- }
-
function getElementAnimationDetails(element, cacheKey) {
var data = cacheKey ? lookupCache[cacheKey] : null;
if(!data) {
@@ -1057,10 +1050,9 @@ angular.module('ngAnimate', ['ng'])
var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * 1000;
var startTime = Date.now();
var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
- var formerStyle;
var ii = data.ii;
- var applyFallbackStyle, style = '';
+ var applyFallbackStyle, style = '', appliedStyles = [];
if(timings.transitionDuration > 0) {
var propertyStyle = timings.transitionPropertyStyle;
if(propertyStyle.indexOf('all') == -1) {
@@ -1068,6 +1060,8 @@ angular.module('ngAnimate', ['ng'])
var fallbackProperty = $sniffer.msie ? '-ms-zoom' : 'border-spacing';
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; ';
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; ';
+ appliedStyles.push(CSS_PREFIX + 'transition-property');
+ appliedStyles.push(CSS_PREFIX + 'transition-duration');
}
} else {
unblockKeyframeAnimations(element);
@@ -1082,16 +1076,19 @@ angular.module('ngAnimate', ['ng'])
style += CSS_PREFIX + 'transition-delay: ' +
prepareStaggerDelay(delayStyle, stagger.transitionDelay, ii) + '; ';
+ appliedStyles.push(CSS_PREFIX + 'transition-delay');
}
if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
style += CSS_PREFIX + 'animation-delay: ' +
prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, ii) + '; ';
+ appliedStyles.push(CSS_PREFIX + 'animation-delay');
}
}
- if(style.length > 0) {
- formerStyle = applyStyle(node, style);
+ if(appliedStyles.length > 0) {
+ var oldStyle = node.getAttribute('style') || '';
+ node.setAttribute('style', oldStyle + ' ' + style);
}
element.on(css3AnimationEvents, onAnimationProgress);
@@ -1104,10 +1101,8 @@ angular.module('ngAnimate', ['ng'])
element.off(css3AnimationEvents, onAnimationProgress);
element.removeClass(activeClassName);
animateClose(element, className);
- if(formerStyle != null) {
- formerStyle.length > 0 ?
- node.setAttribute('style', formerStyle) :
- node.removeAttribute('style');
+ for (var i in appliedStyles) {
+ node.style.removeProperty(appliedStyles[i]);
}
};
diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js
index cbf9de63..c585e72b 100644
--- a/test/ngAnimate/animateSpec.js
+++ b/test/ngAnimate/animateSpec.js
@@ -420,6 +420,27 @@ describe("ngAnimate", function() {
expect(element.children().length).toBe(0);
}));
+ it("should retain existing styles of the animated element",
+ inject(function($animate, $rootScope, $sniffer, $timeout) {
+
+ element.append(child);
+ child.attr('style', 'width: 20px');
+
+ $animate.addClass(child, 'ng-hide');
+ $animate.leave(child);
+ $rootScope.$digest();
+
+ if($sniffer.transitions) {
+ $timeout.flush();
+
+ //this is to verify that the existing style is appended with a semicolon automatically
+ expect(child.attr('style')).toMatch(/width: 20px;.+?/i);
+ browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
+ }
+
+ expect(child.attr('style')).toMatch(/width: 20px/i);
+ }));
+
it("should call the cancel callback when another animation is called on the same element",
inject(function($animate, $rootScope, $sniffer, $timeout) {
@@ -975,6 +996,35 @@ describe("ngAnimate", function() {
expect(element).toBeShown();
}));
+ it("should NOT overwrite styles with outdated values when animation completes",
+ inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
+
+ if(!$sniffer.transitions) return;
+
+ var style = '-webkit-transition-duration: 1s, 2000ms, 1s;' +
+ '-webkit-transition-property: height, left, opacity;' +
+ 'transition-duration: 1s, 2000ms, 1s;' +
+ 'transition-property: height, left, opacity;';
+
+ ss.addRule('.ng-hide-add', style);
+ ss.addRule('.ng-hide-remove', style);
+
+ element = $compile(html('<div style="width: 100px">foo</div>'))($rootScope);
+ element.addClass('ng-hide');
+
+ $animate.removeClass(element, 'ng-hide');
+
+ $timeout.flush();
+
+ var now = Date.now();
+ browserTrigger(element,'transitionend', { timeStamp: now + 1000, elapsedTime: 1 });
+ browserTrigger(element,'transitionend', { timeStamp: now + 1000, elapsedTime: 1 });
+
+ element.css('width', '200px');
+ browserTrigger(element,'transitionend', { timeStamp: now + 2000, elapsedTime: 2 });
+ expect(element.css('width')).toBe("200px");
+ }));
+
it("should animate for the highest duration",
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
var style = '-webkit-transition:1s linear all 2s;' +