mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
fix(ngAnimate): correctly retain and restore existing styles during and after animation
Closes #4869
This commit is contained in:
parent
3fbb25e25c
commit
c42d0a0418
2 changed files with 60 additions and 15 deletions
|
|
@ -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]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;' +
|
||||
|
|
|
|||
Loading…
Reference in a new issue