diff --git a/src/ng/animate.js b/src/ng/animate.js index 88e0e160592c..f3b6ffdd4f3f 100644 --- a/src/ng/animate.js +++ b/src/ng/animate.js @@ -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); + } + } } }]; }; diff --git a/test/ng/animateSpec.js b/test/ng/animateSpec.js index 2e9fdcaa9d3c..76fae5ebcaa6 100644 --- a/test/ng/animateSpec.js +++ b/test/ng/animateSpec.js @@ -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('
'); + var element2 = jqLite(''); + + $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();