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

Commit 6e8bd78

Browse files
matskomhevery
authored andcommitted
fix(ngAnimate): remove compound JS selector animations
1 parent 4ed5fc9 commit 6e8bd78

File tree

4 files changed

+47
-34
lines changed

4 files changed

+47
-34
lines changed
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@ngdoc error
2+
@name $animate:notcsel
3+
@fullName Not class CSS selector
4+
@description
5+
6+
Expecting a CSS selector for class. Class selectors must start with `.`, for example: `.my-class-name`.

src/ng/animate.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
var $animateMinErr = minErr('$animate');
4+
35
/**
46
* @ngdoc object
57
* @name ng.$animateProvider
@@ -14,7 +16,7 @@
1416
*/
1517
var $AnimateProvider = ['$provide', function($provide) {
1618

17-
this.$$selectors = [];
19+
this.$$selectors = {};
1820

1921

2022
/**
@@ -47,13 +49,11 @@ var $AnimateProvider = ['$provide', function($provide) {
4749
* @param {function} factory The factory function that will be executed to return the animation object.
4850
*/
4951
this.register = function(name, factory) {
50-
var classes = name.substr(1).split('.');
51-
name += '-animation';
52-
this.$$selectors.push({
53-
selectors : classes,
54-
name : name
55-
});
56-
$provide.factory(name, factory);
52+
var key = name + '-animation';
53+
if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
54+
"Expecting class selector starting with '.' got '{0}'.", name);
55+
this.$$selectors[name.substr(1)] = key;
56+
$provide.factory(key, factory);
5757
};
5858

5959
this.$get = ['$timeout', function($timeout) {

src/ngAnimate/animate.js

+19-23
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174
* a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
175175
* the element's CSS class attribute value and then run the matching animation event function (if found).
176176
* In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function
177-
* be executed. It should be also noted that only simple or compound class selectors are allowed.
177+
* be executed. It should be also noted that only simple class selectors are allowed.
178178
*
179179
* Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
180180
* 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'])
211211
$rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
212212

213213
function lookup(name) {
214-
var i, ii;
215214
if (name) {
216-
var classes = name.substr(1).split('.'),
217-
classMap = {};
218-
219-
for (i = 0, ii = classes.length; i < ii; i++) {
220-
classMap[classes[i]] = true;
221-
}
222-
223-
var matches = [];
224-
for (i = 0, ii = selectors.length; i < ii; i++) {
225-
var selectorFactory = selectors[i];
226-
var found = true;
227-
for(var j = 0, jj = selectorFactory.selectors.length; j < jj; j++) {
228-
var klass = selectorFactory.selectors[j];
229-
if(klass.length > 0) {
230-
found = found && classMap[klass];
231-
}
232-
}
233-
if(found) {
234-
matches.push($injector.get(selectorFactory.name));
215+
var matches = [],
216+
flagMap = {},
217+
classes = name.substr(1).split('.');
218+
219+
//the empty string value is the default animation
220+
//operation which performs CSS transition and keyframe
221+
//animations sniffing. This is always included for each
222+
//element animation procedure
223+
classes.push('');
224+
225+
for(var i=0; i < classes.length; i++) {
226+
var klass = classes[i],
227+
selectorFactoryName = selectors[klass];
228+
if(selectorFactoryName && !flagMap[klass]) {
229+
matches.push($injector.get(selectorFactoryName));
230+
flagMap[klass] = true;
235231
}
236232
}
237233
return matches;
@@ -444,8 +440,8 @@ angular.module('ngAnimate', ['ng'])
444440
and the onComplete callback will be fired once the animation is fully complete.
445441
*/
446442
function performAnimation(event, className, element, parent, after, onComplete) {
447-
var classes = ((element.attr('class') || '') + ' ' + className),
448-
animationLookup = (' ' + classes).replace(/\s+/g,'.'),
443+
var classes = (element.attr('class') || '') + ' ' + className;
444+
var animationLookup = (' ' + classes).replace(/\s+/g,'.'),
449445
animations = [];
450446
forEach(lookup(animationLookup), function(animation, index) {
451447
animations.push({

test/ng/animateSpec.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
describe("$animate", function() {
22

33
describe("without animation", function() {
4-
beforeEach(inject(function($compile, _$rootElement_, $rootScope) {
5-
element = $compile('<div></div>')($rootScope);
6-
$rootElement = _$rootElement_;
4+
beforeEach(module(function() {
5+
return function($compile, _$rootElement_, $rootScope) {
6+
element = $compile('<div></div>')($rootScope);
7+
$rootElement = _$rootElement_;
8+
};
79
}));
810

911
it("should add element at the start of enter animation", inject(function($animate, $compile, $rootScope) {
@@ -37,5 +39,14 @@ describe("$animate", function() {
3739
$animate.addClass(element, 'ng-hide');
3840
expect(element).toBeHidden();
3941
}));
42+
43+
it("should throw error on wrong selector", function() {
44+
module(function($animateProvider) {
45+
expect(function() {
46+
$animateProvider.register('abc', null);
47+
}).toThrow("[$animate:notcsel] Expecting class selector starting with '.' got 'abc'.");
48+
});
49+
inject();
50+
});
4051
});
4152
});

0 commit comments

Comments
 (0)