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

fix($animate): invalid CSS class names should not break subsequent elements #12725

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 52 additions & 47 deletions src/ng/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,61 +105,66 @@ var $$CoreAnimateQueueProvider = function() {
}
};

function addRemoveClassesPostDigest(element, add, remove) {
var classVal, data = postDigestQueue.get(element);

if (!data) {
postDigestQueue.put(element, data = {});
postDigestElements.push(element);
function updateData(data, classes, value) {
var changed = false;
if (classes) {
classes = isString(classes) ? classes.split(' ') :
isArray(classes) ? classes : [];
forEach(classes, function(className) {
if (className) {
changed = true;
data[className] = value;
}
});
}
return changed;
}

var updateData = function(classes, value) {
var changed = false;
if (classes) {
classes = isString(classes) ? classes.split(' ') :
isArray(classes) ? classes : [];
forEach(classes, function(className) {
if (className) {
changed = true;
data[className] = value;
function handleCSSClassChanges() {
forEach(postDigestElements, function(element) {
var data = postDigestQueue.get(element);
if (data) {
var existing = splitClasses(element.attr('class'));
var toAdd = '';
var toRemove = '';
forEach(data, function(status, className) {
var hasClass = !!existing[className];
if (status !== hasClass) {
if (status) {
toAdd += (toAdd.length ? ' ' : '') + className;
} else {
toRemove += (toRemove.length ? ' ' : '') + className;
}
}
});

forEach(element, function(elm) {
toAdd && jqLiteAddClass(elm, toAdd);
toRemove && jqLiteRemoveClass(elm, toRemove);
});
postDigestQueue.remove(element);
}
return changed;
};

var classesAdded = updateData(add, true);
var classesRemoved = updateData(remove, false);
if ((!classesAdded && !classesRemoved) || postDigestElements.length > 1) return;

$rootScope.$$postDigest(function() {
forEach(postDigestElements, function(element) {
var data = postDigestQueue.get(element);
if (data) {
var existing = splitClasses(element.attr('class'));
var toAdd = '';
var toRemove = '';
forEach(data, function(status, className) {
var hasClass = !!existing[className];
if (status !== hasClass) {
if (status) {
toAdd += (toAdd.length ? ' ' : '') + className;
} else {
toRemove += (toRemove.length ? ' ' : '') + className;
}
}
});
});
postDigestElements.length = 0;
}

forEach(element, function(elm) {
toAdd && jqLiteAddClass(elm, toAdd);
toRemove && jqLiteRemoveClass(elm, toRemove);
});
postDigestQueue.remove(element);
}
});

postDigestElements.length = 0;
});
function addRemoveClassesPostDigest(element, add, remove) {
var data = postDigestQueue.get(element) || {};

var classesAdded = updateData(data, add, true);
var classesRemoved = updateData(data, remove, false);

if (classesAdded || classesRemoved) {

postDigestQueue.put(element, data);
postDigestElements.push(element);

if (postDigestElements.length === 1) {
$rootScope.$$postDigest(handleCSSClassChanges);
}
}
}
}];
};
Expand Down
15 changes: 15 additions & 0 deletions test/ng/animateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,21 @@ describe("$animate", function() {
});
});


it('should not break postDigest for subsequent elements if addClass contains non-valid CSS class names', function() {
inject(function($animate, $rootScope, $rootElement) {
var element1 = jqLite('<div></div>');
var element2 = jqLite('<div></div>');

$animate.enter(element1, $rootElement, null, { addClass: ' ' });
$animate.enter(element2, $rootElement, null, { addClass: 'valid-name' });
$rootScope.$digest();

expect(element2.hasClass('valid-name')).toBeTruthy();
});
});


it('should not issue a call to removeClass if the provided class value is not a string or array', function() {
inject(function($animate, $rootScope, $rootElement) {
var spy = spyOn(window, 'jqLiteRemoveClass').andCallThrough();
Expand Down