fix(ngAnimate): remove compound JS selector animations

This commit is contained in:
Matias Niemelä 2013-08-01 22:17:10 -04:00 committed by Misko Hevery
parent 4ed5fc90b9
commit 6e8bd786ba
4 changed files with 45 additions and 32 deletions

View file

@ -0,0 +1,6 @@
@ngdoc error
@name $animate:notcsel
@fullName Not class CSS selector
@description
Expecting a CSS selector for class. Class selectors must start with `.`, for example: `.my-class-name`.

View file

@ -1,5 +1,7 @@
'use strict';
var $animateMinErr = minErr('$animate');
/**
* @ngdoc object
* @name ng.$animateProvider
@ -14,7 +16,7 @@
*/
var $AnimateProvider = ['$provide', function($provide) {
this.$$selectors = [];
this.$$selectors = {};
/**
@ -47,13 +49,11 @@ var $AnimateProvider = ['$provide', function($provide) {
* @param {function} factory The factory function that will be executed to return the animation object.
*/
this.register = function(name, factory) {
var classes = name.substr(1).split('.');
name += '-animation';
this.$$selectors.push({
selectors : classes,
name : name
});
$provide.factory(name, factory);
var key = name + '-animation';
if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
"Expecting class selector starting with '.' got '{0}'.", name);
this.$$selectors[name.substr(1)] = key;
$provide.factory(key, factory);
};
this.$get = ['$timeout', function($timeout) {

View file

@ -174,7 +174,7 @@
* a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
* the element's CSS class attribute value and then run the matching animation event function (if found).
* In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function
* be executed. It should be also noted that only simple or compound class selectors are allowed.
* be executed. It should be also noted that only simple class selectors are allowed.
*
* Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
* As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run,
@ -211,27 +211,23 @@ angular.module('ngAnimate', ['ng'])
$rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
function lookup(name) {
var i, ii;
if (name) {
var classes = name.substr(1).split('.'),
classMap = {};
var matches = [],
flagMap = {},
classes = name.substr(1).split('.');
for (i = 0, ii = classes.length; i < ii; i++) {
classMap[classes[i]] = true;
}
//the empty string value is the default animation
//operation which performs CSS transition and keyframe
//animations sniffing. This is always included for each
//element animation procedure
classes.push('');
var matches = [];
for (i = 0, ii = selectors.length; i < ii; i++) {
var selectorFactory = selectors[i];
var found = true;
for(var j = 0, jj = selectorFactory.selectors.length; j < jj; j++) {
var klass = selectorFactory.selectors[j];
if(klass.length > 0) {
found = found && classMap[klass];
}
}
if(found) {
matches.push($injector.get(selectorFactory.name));
for(var i=0; i < classes.length; i++) {
var klass = classes[i],
selectorFactoryName = selectors[klass];
if(selectorFactoryName && !flagMap[klass]) {
matches.push($injector.get(selectorFactoryName));
flagMap[klass] = true;
}
}
return matches;
@ -444,8 +440,8 @@ angular.module('ngAnimate', ['ng'])
and the onComplete callback will be fired once the animation is fully complete.
*/
function performAnimation(event, className, element, parent, after, onComplete) {
var classes = ((element.attr('class') || '') + ' ' + className),
animationLookup = (' ' + classes).replace(/\s+/g,'.'),
var classes = (element.attr('class') || '') + ' ' + className;
var animationLookup = (' ' + classes).replace(/\s+/g,'.'),
animations = [];
forEach(lookup(animationLookup), function(animation, index) {
animations.push({

View file

@ -1,9 +1,11 @@
describe("$animate", function() {
describe("without animation", function() {
beforeEach(inject(function($compile, _$rootElement_, $rootScope) {
element = $compile('<div></div>')($rootScope);
$rootElement = _$rootElement_;
beforeEach(module(function() {
return function($compile, _$rootElement_, $rootScope) {
element = $compile('<div></div>')($rootScope);
$rootElement = _$rootElement_;
};
}));
it("should add element at the start of enter animation", inject(function($animate, $compile, $rootScope) {
@ -37,5 +39,14 @@ describe("$animate", function() {
$animate.addClass(element, 'ng-hide');
expect(element).toBeHidden();
}));
it("should throw error on wrong selector", function() {
module(function($animateProvider) {
expect(function() {
$animateProvider.register('abc', null);
}).toThrow("[$animate:notcsel] Expecting class selector starting with '.' got 'abc'.");
});
inject();
});
});
});