diff options
| -rw-r--r-- | docs/content/error/animate/notcsel.ngdoc | 6 | ||||
| -rw-r--r-- | src/ng/animate.js | 16 | ||||
| -rw-r--r-- | src/ngAnimate/animate.js | 42 | ||||
| -rw-r--r-- | test/ng/animateSpec.js | 17 |
4 files changed, 47 insertions, 34 deletions
diff --git a/docs/content/error/animate/notcsel.ngdoc b/docs/content/error/animate/notcsel.ngdoc new file mode 100644 index 00000000..d8ceaa0e --- /dev/null +++ b/docs/content/error/animate/notcsel.ngdoc @@ -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`. diff --git a/src/ng/animate.js b/src/ng/animate.js index 7927b12f..2d9e6191 100644 --- a/src/ng/animate.js +++ b/src/ng/animate.js @@ -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) { diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js index 20ceaf07..d572619f 100644 --- a/src/ngAnimate/animate.js +++ b/src/ngAnimate/animate.js @@ -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 = {}; - - for (i = 0, ii = classes.length; i < ii; i++) { - classMap[classes[i]] = true; - } - - 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)); + var matches = [], + flagMap = {}, + classes = name.substr(1).split('.'); + + //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(''); + + 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({ diff --git a/test/ng/animateSpec.js b/test/ng/animateSpec.js index c5914a74..2e9034e4 100644 --- a/test/ng/animateSpec.js +++ b/test/ng/animateSpec.js @@ -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(); + }); }); }); |
