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

Commit 61527f3

Browse files
committed
fix($animateCss): respect transition styles already on the element
Previously, $animateCss wouldn't use transition styles that were on the element before the animation process started. Precisely, transition property, timing-function and delay were overwritten in the process.
1 parent 2e23a3c commit 61527f3

File tree

4 files changed

+75
-28
lines changed

4 files changed

+75
-28
lines changed

src/ngAnimate/.jshintrc

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
"TRANSITION_DURATION_PROP": false,
3333
"TRANSITION_DELAY_PROP": false,
34+
"TRANSITION_TIMING_PROP": false,
35+
"TRANSITION_PROPERTY_PROP": false,
3436
"TRANSITION_PROP": false,
3537
"PROPERTY_KEY": false,
3638
"DURATION_KEY": false,

src/ngAnimate/animateCss.js

+21-24
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ var DETECT_CSS_PROPERTIES = {
226226
transitionDuration: TRANSITION_DURATION_PROP,
227227
transitionDelay: TRANSITION_DELAY_PROP,
228228
transitionProperty: TRANSITION_PROP + PROPERTY_KEY,
229+
transitionTimingFunction: TRANSITION_PROP + TIMING_KEY,
229230
animationDuration: ANIMATION_DURATION_PROP,
230231
animationDelay: ANIMATION_DELAY_PROP,
231232
animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY
@@ -292,14 +293,14 @@ function truthyTimingValue(val) {
292293
return val === 0 || val != null;
293294
}
294295

295-
function getCssTransitionDurationStyle(duration, applyOnlyDuration) {
296+
function getCssTransitionStyle(timings, duration) {
296297
var style = TRANSITION_PROP;
297298
var value = duration + 's';
298-
if (applyOnlyDuration) {
299-
style += DURATION_KEY;
300-
} else {
301-
value += ' linear all';
302-
}
299+
300+
value += ' ' + timings[TRANSITION_TIMING_PROP];
301+
value += ' ' + (timings[TRANSITION_PROPERTY_PROP] || 'all');
302+
value += timings[TRANSITION_DELAY_PROP] ? ' ' + timings[TRANSITION_DELAY_PROP] + 's' : '';
303+
303304
return [style, value];
304305
}
305306

@@ -550,15 +551,6 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
550551
temporaryStyles.push(transitionStyle);
551552
}
552553

553-
if (options.duration >= 0) {
554-
applyOnlyDuration = node.style[TRANSITION_PROP].length > 0;
555-
var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration);
556-
557-
// we set the duration so that it will be picked up by getComputedStyle later
558-
applyInlineStyle(node, durationStyle);
559-
temporaryStyles.push(durationStyle);
560-
}
561-
562554
if (options.keyframeStyle) {
563555
var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle];
564556
applyInlineStyle(node, keyframeStyle);
@@ -571,8 +563,18 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
571563
: gcsLookup.count(cacheKey)
572564
: 0;
573565

574-
var isFirst = itemIndex === 0;
566+
var timings = computeTimings(node, fullClassName, cacheKey);
567+
568+
if (options.duration > 0) {
569+
// Duration in options overwrites duration set in style
570+
timings[TRANSITION_DURATION_PROP] = options.duration;
571+
}
572+
573+
var relativeDelay = timings.maxDelay;
574+
maxDelay = Math.max(relativeDelay, 0);
575+
maxDuration = timings.maxDuration;
575576

577+
var isFirst = itemIndex === 0;
576578
// this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY
577579
// without causing any combination of transitions to kick in. By adding a negative delay value
578580
// it forces the setup class' transition to end immediately. We later then remove the negative
@@ -583,16 +585,11 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
583585
blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
584586
}
585587

586-
var timings = computeTimings(node, fullClassName, cacheKey);
587-
var relativeDelay = timings.maxDelay;
588-
maxDelay = Math.max(relativeDelay, 0);
589-
maxDuration = timings.maxDuration;
590-
591588
var flags = {};
592589
flags.hasTransitions = timings.transitionDuration > 0;
593590
flags.hasAnimations = timings.animationDuration > 0;
594591
flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty == 'all';
595-
flags.applyTransitionDuration = hasToStyles && (
592+
flags.applyTransitionDuration = options.duration > 0 || hasToStyles && (
596593
(flags.hasTransitions && !flags.hasTransitionAll)
597594
|| (flags.hasAnimations && !flags.hasTransitions));
598595
flags.applyAnimationDuration = options.duration && flags.hasAnimations;
@@ -606,15 +603,15 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
606603
if (flags.applyTransitionDuration) {
607604
flags.hasTransitions = true;
608605
timings.transitionDuration = maxDuration;
609-
applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0;
610-
temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration));
606+
temporaryStyles.push(getCssTransitionStyle(timings, maxDuration));
611607
}
612608

613609
if (flags.applyAnimationDuration) {
614610
flags.hasAnimations = true;
615611
timings.animationDuration = maxDuration;
616612
temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration));
617613
}
614+
618615
}
619616

620617
if (maxDuration === 0 && !flags.recalculateTimingStyles) {

src/ngAnimate/shared.js

+2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
6666
var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
6767
var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
6868
var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
69+
var TRANSITION_TIMING_PROP = TRANSITION_PROP + TIMING_KEY;
70+
var TRANSITION_PROPERTY_PROP = TRANSITION_PROP + PROPERTY_KEY;
6971

7072
var isPromiseLike = function(p) {
7173
return p && p.then ? true : false;

test/ngAnimate/animateCssSpec.js

+50-4
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,52 @@ describe("ngAnimate $animateCss", function() {
634634
keyframeProgress(element, 1, 20);
635635
assertAnimationComplete(true);
636636
}));
637+
638+
it("should apply all transition shorthand properties that are already on the element",
639+
inject(function($animateCss, $rootElement) {
640+
641+
ss.addRule('.action', 'transition: color 1s ease-out 5s;');
642+
element.addClass('action');
643+
644+
var options = {
645+
to: { background: 'blue' }
646+
};
647+
648+
var animator = $animateCss(element, options);
649+
animator.start();
650+
triggerAnimationStartFrame();
651+
652+
var style = element.attr('style');
653+
expect(element.css('transition-duration')).toMatch('1s');
654+
expect(element.css('transition-delay')).toMatch('5s');
655+
expect(element.css('transition-property')).toMatch('color');
656+
expect(style).toContain('ease-out');
657+
}));
658+
659+
it("should apply all explicit transition properties that are already on the element",
660+
inject(function($animateCss, $rootElement) {
661+
662+
ss.addRule('.action', 'transition-duration: 1s;' +
663+
'transition-timing-function: ease-out;' +
664+
'transition-property: color;' +
665+
'transition-delay: 5s');
666+
element.addClass('action');
667+
668+
var options = {
669+
to: { background: 'blue' }
670+
};
671+
672+
var animator = $animateCss(element, options);
673+
animator.start();
674+
triggerAnimationStartFrame();
675+
676+
var style = element.attr('style');
677+
expect(element.css('transition-duration')).toMatch('1s');
678+
expect(element.css('transition-delay')).toMatch('5s');
679+
expect(element.css('transition-property')).toMatch('color');
680+
expect(style).toContain('ease-out');
681+
}));
682+
637683
});
638684

639685
describe("staggering", function() {
@@ -1855,7 +1901,7 @@ describe("ngAnimate $animateCss", function() {
18551901

18561902
var style = element.attr('style');
18571903
expect(style).toContain('3000s');
1858-
expect(style).toContain('linear');
1904+
expect(style).toContain('ease');
18591905
}));
18601906

18611907
it("should be applied to a CSS keyframe animation directly if keyframes are detected within the CSS class",
@@ -2125,7 +2171,7 @@ describe("ngAnimate $animateCss", function() {
21252171
var animator = $animateCss(element, options);
21262172

21272173
expect(element.attr('style') || '').not.toContain('animation-delay');
2128-
expect(element.attr('style') || '').not.toContain('transition-delay');
2174+
expect(element.css('transition-delay')).toEqual('-2s');
21292175
expect(classSpy).not.toHaveBeenCalled();
21302176

21312177
//redefine the classSpy to assert that the delay values have been
@@ -2561,7 +2607,7 @@ describe("ngAnimate $animateCss", function() {
25612607
var style = element.attr('style');
25622608
expect(element.css('transition-duration')).toMatch('2.5s');
25632609
expect(element.css('transition-property')).toMatch('all');
2564-
expect(style).toContain('linear');
2610+
expect(style).toContain('ease');
25652611
}));
25662612

25672613
it("should remove all inline transition styling when an animation completes",
@@ -2708,7 +2754,7 @@ describe("ngAnimate $animateCss", function() {
27082754

27092755
var style = element.attr('style');
27102756
expect(element.css('transition-duration')).toMatch('1s');
2711-
expect(element.css('transition-property')).toMatch('all');
2757+
expect(element.css('transition-property')).toMatch('color');
27122758
expect(style).toContain('linear');
27132759
}));
27142760

0 commit comments

Comments
 (0)