fix($animate): ensure the CSS driver properly works with SVG elements

The default CSS driver in ngAnimate directly uses node.className when reading
the CSS class string on the given element. While this works fine with standard
HTML DOM elements, SVG elements have their own DOM property. By switching to use
node.getAttribute, ngAnimate can extract the element's className value without
throwing an exception.

When using jQuery over jqLite, ngAnimate will not properly handle SVG elements
for an animation. This is because jQuery doesn't process SVG elements within it's
DOM operation code by default. To get this to work, simply include the jquery.svg.js
JavaScript file into your application.

Closes #6030
This commit is contained in:
Matias Niemelä
2014-04-03 00:56:53 -04:00
parent 2db66f5b69
commit 38ea542662
2 changed files with 39 additions and 2 deletions
+2 -2
View File
@@ -1211,7 +1211,7 @@ angular.module('ngAnimate', ['ng'])
parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
parentID = parentCounter;
}
return parentID + '-' + extractElementNode(element).className;
return parentID + '-' + extractElementNode(element).getAttribute('class');
}
function animateSetup(animationEvent, element, className, calculationDecorator) {
@@ -1316,7 +1316,7 @@ angular.module('ngAnimate', ['ng'])
function animateRun(animationEvent, element, className, activeAnimationComplete) {
var node = extractElementNode(element);
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
if(node.className.indexOf(className) == -1 || !elementData) {
if(node.getAttribute('class').indexOf(className) == -1 || !elementData) {
activeAnimationComplete();
return;
}
+37
View File
@@ -3652,5 +3652,42 @@ describe("ngAnimate", function() {
expect(element.children().length).toBe(0);
}));
describe('SVG', function() {
it('should properly apply transitions on an SVG element',
inject(function($animate, $rootScope, $compile, $rootElement, $sniffer) {
//jQuery doesn't handle SVG elements natively. Instead, an add-on library
//is required which is called jquery.svg.js. Therefore, when jQuery is
//active here there is no point to test this since it won't work by default.
if(!$sniffer.transitions || !_jqLiteMode) return;
ss.addRule('circle.ng-enter', '-webkit-transition:1s linear all;' +
'transition:1s linear all;');
var element = $compile('<svg width="500" height="500">' +
'<circle cx="15" cy="5" r="100" fill="orange" ng-if="on" />' +
'</svg>')($rootScope);
$rootElement.append(element);
jqLite($document[0].body).append($rootElement);
$rootScope.$digest();
$rootScope.on = true;
$rootScope.$digest();
$animate.triggerReflow();
var child = element.find('circle');
expect(child.hasClass('ng-enter')).toBe(true);
expect(child.hasClass('ng-enter-active')).toBe(true);
browserTrigger(child, 'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
expect(child.hasClass('ng-enter')).toBe(false);
expect(child.hasClass('ng-enter-active')).toBe(false);
}));
});
});
});