Skip to content

Commit b07d30b

Browse files
committed
fix(ngAnimate): don't normalize classes on follow-up animations to joined animations
This allows follow-up animations to remove a class that is currently being added. Fixes angular#13339 Fixes angular#13380 Closes angular#13414
1 parent 1dd206e commit b07d30b

File tree

2 files changed

+78
-4
lines changed

2 files changed

+78
-4
lines changed

src/ngAnimate/animateQueue.js

+39-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
1212
join: []
1313
};
1414

15+
function makeTruthyMapFromKeys(keys) {
16+
var map = Object.create(null);
17+
forEach(keys, function(key) {
18+
map[key] = true;
19+
});
20+
return map;
21+
}
22+
1523
function isAllowed(ruleType, element, currentAnimation, previousAnimation) {
1624
return rules[ruleType].some(function(fn) {
1725
return fn(element, currentAnimation, previousAnimation);
@@ -59,11 +67,38 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
5967
});
6068

6169
rules.cancel.push(function(element, newAnimation, currentAnimation) {
62-
var nO = newAnimation.options;
63-
var cO = currentAnimation.options;
70+
var ONE_SPACE = ' ';
71+
72+
var nA = newAnimation.options.addClass;
73+
var nR = newAnimation.options.removeClass;
74+
var cA = currentAnimation.options.addClass;
75+
var cR = currentAnimation.options.removeClass;
76+
77+
// early detection to save the global CPU shortage :)
78+
if ((!isDefined(nA) && !isDefined(nR)) || (!isDefined(cA) && !isDefined(cR))) {
79+
return false;
80+
}
81+
82+
var cancelSomething = false;
83+
84+
cA = cA ? makeTruthyMapFromKeys(cA.split(ONE_SPACE)) : null;
85+
cR = cR ? makeTruthyMapFromKeys(cR.split(ONE_SPACE)) : null;
86+
87+
if (cR && nA) {
88+
cancelSomething = nA.split(ONE_SPACE).some(function(className) {
89+
return cR[className];
90+
});
91+
92+
if (cancelSomething) return true;
93+
}
94+
95+
if (cA && nR) {
96+
cancelSomething = nR.split(ONE_SPACE).some(function(className) {
97+
return cA[className];
98+
});
99+
}
64100

65-
// if the exact same CSS class is added/removed then it's safe to cancel it
66-
return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass);
101+
return cancelSomething;
67102
});
68103

69104
this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',

test/ngAnimate/integrationSpec.js

+39
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,45 @@ describe('ngAnimate integration tests', function() {
387387

388388
dealoc(element);
389389
}));
390+
391+
392+
it("should not normalize classes in a follow-up animation to a joined class-based animation",
393+
inject(function($animate, $animateCss, $rootScope, $document, $rootElement, $$rAF) {
394+
395+
ss.addRule('.hide', 'opacity: 0');
396+
ss.addRule('.hide-add, .hide-remove', 'transition: 1s linear all');
397+
398+
jqLite($document[0].body).append($rootElement);
399+
element = jqLite('<div></div>');
400+
$rootElement.append(element);
401+
402+
// These animations will be joined together
403+
$animate.addClass(element, 'red');
404+
$animate.addClass(element, 'hide');
405+
$rootScope.$digest();
406+
407+
expect(element).toHaveClass('red-add');
408+
expect(element).toHaveClass('hide-add');
409+
410+
// When a digest has passed, but no $rAF has been issued yet, .hide hasn't been added to
411+
// the element, which means class normalization does not allow .hide to get removed
412+
$animate.removeClass(element, 'hide');
413+
$rootScope.$digest();
414+
$$rAF.flush();
415+
416+
expect(element).not.toHaveClass('hide-add hide-add-active');
417+
expect(element).toHaveClass('hide-remove hide-remove-active');
418+
419+
//End the animation process
420+
browserTrigger(element, 'transitionend',
421+
{ timeStamp: Date.now() + 1000, elapsedTime: 2 });
422+
$animate.flush();
423+
424+
expect(element).not.toHaveClass('hide-add-active red-add-active');
425+
expect(element).toHaveClass('red');
426+
expect(element).not.toHaveClass('hide');
427+
}));
428+
390429
});
391430

392431
describe('JS animations', function() {

0 commit comments

Comments
 (0)