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

Commit

Permalink
fix(ngAnimate): allow removing classes that are added by a running an…
Browse files Browse the repository at this point in the history
…imation

This allows follow-up animations to remove a class that is currently
being added.

Fixes #13339
Fixes #13380
Closes #13414
Closes #13472
Closes #13678
  • Loading branch information
Narretz committed Jan 6, 2016
1 parent 620a20d commit 6c4581f
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 4 deletions.
40 changes: 36 additions & 4 deletions src/ngAnimate/animateQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,37 @@ var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';
var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
var PRE_DIGEST_STATE = 1;
var RUNNING_STATE = 2;
var ONE_SPACE = ' ';

var rules = this.rules = {
skip: [],
cancel: [],
join: []
};

function makeTruthyCssClassMap(classString) {
if (!classString) {
return null;
}

var keys = classString.split(ONE_SPACE);
var map = Object.create(null);

forEach(keys, function(key) {
map[key] = true;
});
return map;
}

function hasMatchingClasses(newClassString, currentClassString) {
if (newClassString && currentClassString) {
var currentClassMap = makeTruthyCssClassMap(currentClassString);
return newClassString.split(ONE_SPACE).some(function(className) {
return currentClassMap[className];
});
}
}

function isAllowed(ruleType, element, currentAnimation, previousAnimation) {
return rules[ruleType].some(function(fn) {
return fn(element, currentAnimation, previousAnimation);
Expand Down Expand Up @@ -59,11 +83,19 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
});

rules.cancel.push(function(element, newAnimation, currentAnimation) {
var nO = newAnimation.options;
var cO = currentAnimation.options;

// if the exact same CSS class is added/removed then it's safe to cancel it
return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass);

var nA = newAnimation.options.addClass;
var nR = newAnimation.options.removeClass;
var cA = currentAnimation.options.addClass;
var cR = currentAnimation.options.removeClass;

// early detection to save the global CPU shortage :)
if ((isUndefined(nA) && isUndefined(nR)) || (isUndefined(cA) && isUndefined(cR))) {
return false;
}

return (hasMatchingClasses(nA, cR)) || (hasMatchingClasses(nR, cA));
});

this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
Expand Down
39 changes: 39 additions & 0 deletions test/ngAnimate/integrationSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,45 @@ describe('ngAnimate integration tests', function() {

dealoc(element);
}));


it("should remove a class when the same class is currently being added by a joined class-based animation",
inject(function($animate, $animateCss, $rootScope, $document, $rootElement, $$rAF) {

ss.addRule('.hide', 'opacity: 0');
ss.addRule('.hide-add, .hide-remove', 'transition: 1s linear all');

jqLite($document[0].body).append($rootElement);
element = jqLite('<div></div>');
$rootElement.append(element);

// These animations will be joined together
$animate.addClass(element, 'red');
$animate.addClass(element, 'hide');
$rootScope.$digest();

expect(element).toHaveClass('red-add');
expect(element).toHaveClass('hide-add');

// When a digest has passed, but no $rAF has been issued yet, .hide hasn't been added to
// the element yet
$animate.removeClass(element, 'hide');
$rootScope.$digest();
$$rAF.flush();

expect(element).not.toHaveClass('hide-add hide-add-active');
expect(element).toHaveClass('hide-remove hide-remove-active');

//End the animation process
browserTrigger(element, 'transitionend',
{ timeStamp: Date.now() + 1000, elapsedTime: 2 });
$animate.flush();

expect(element).not.toHaveClass('hide-add-active red-add-active');
expect(element).toHaveClass('red');
expect(element).not.toHaveClass('hide');
}));

});

describe('JS animations', function() {
Expand Down

0 comments on commit 6c4581f

Please sign in to comment.