Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
fix(ngAnimate): correctly retain and restore existing styles during a…
Browse files Browse the repository at this point in the history
…nd after animation

Closes #4869
  • Loading branch information
Peter Deak authored and matsko committed Nov 22, 2013
1 parent 3fbb25e commit c42d0a0
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 15 deletions.
25 changes: 10 additions & 15 deletions src/ngAnimate/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -1057,17 +1050,18 @@ 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) {
applyFallbackStyle = true;
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);
Expand All @@ -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);
Expand All @@ -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]);
}
};

Expand Down
50 changes: 50 additions & 0 deletions test/ngAnimate/animateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand Down Expand Up @@ -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;' +
Expand Down

0 comments on commit c42d0a0

Please sign in to comment.