From 8cdd7bd0c60998964e66228342ffa2b340e513b8 Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Fri, 15 Jul 2016 12:33:01 +0300 Subject: [PATCH 1/4] fix($animate): improve detection on `ng-animate` in `classNameFilter` RegExp --- src/ng/animate.js | 13 +++++++------ test/ngAnimate/animateSpec.js | 18 +++++++++++------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/ng/animate.js b/src/ng/animate.js index 923126eed045..7457baca60af 100644 --- a/src/ng/animate.js +++ b/src/ng/animate.js @@ -179,6 +179,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() { */ var $AnimateProvider = ['$provide', /** @this */ function($provide) { var provider = this; + var classNameFilter = null; this.$$registeredAnimations = Object.create(null); @@ -247,15 +248,15 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) { */ this.classNameFilter = function(expression) { if (arguments.length === 1) { - this.$$classNameFilter = (expression instanceof RegExp) ? expression : null; - if (this.$$classNameFilter) { - var reservedRegex = new RegExp('(\\s+|\\/)' + NG_ANIMATE_CLASSNAME + '(\\s+|\\/)'); - if (reservedRegex.test(this.$$classNameFilter.toString())) { - throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME); + classNameFilter = (expression instanceof RegExp) ? expression : null; + if (classNameFilter) { + var reservedRegex = new RegExp('[(\\s|\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\s|\\/)]'); + if (reservedRegex.test(classNameFilter.toString())) { + throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME); } } } - return this.$$classNameFilter; + return classNameFilter; }; this.$get = ['$$animateQueue', function($$animateQueue) { diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index e1f37c4e4462..99c284f6bbc0 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -255,29 +255,33 @@ describe('animations', function() { }); }); - it('should throw a minErr if a regex value is used which partially contains or fully matches the `ng-animate` CSS class', function() { + it('should throw a minErr if a regex value is used which partially contains or fully matches the `ng-animate` CSS class', module(function($animateProvider) { + var errorMessage = '$animateProvider.classNameFilter(regex) prohibits accepting a regex ' + + 'value which matches/contains the "ng-animate" CSS class.'; + assertError(/ng-animate/, true); assertError(/first ng-animate last/, true); assertError(/ng-animate-special/, false); assertError(/first ng-animate-special last/, false); assertError(/first ng-animate ng-animate-special last/, true); + assertError(/(ng-animate)/, true); + assertError(/(foo|ng-animate|bar)/, true); + assertError(/(foo|)ng-animate(|bar)/, true); function assertError(regex, bool) { var expectation = expect(function() { $animateProvider.classNameFilter(regex); }); - var message = '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "ng-animate" CSS class.'; - if (bool) { - expectation.toThrowMinErr('$animate', 'nongcls', message); + expectation.toThrowMinErr('$animate', 'nongcls', errorMessage); } else { - expectation.not.toThrowMinErr('$animate', 'nongcls', message); + expectation.not.toThrow(); } } - }); - }); + }) + ); it('should complete the leave DOM operation in case the classNameFilter fails', function() { module(function($animateProvider) { From 5bf4ab08114c70bc2850c5bbd9d30abf29ec9545 Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Fri, 15 Jul 2016 12:34:06 +0300 Subject: [PATCH 2/4] fix($animate): reset `classNameFilter` to `null` when a disallowed RegExp is used --- src/ng/animate.js | 1 + test/ngAnimate/animateSpec.js | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/ng/animate.js b/src/ng/animate.js index 7457baca60af..1f8054b5fade 100644 --- a/src/ng/animate.js +++ b/src/ng/animate.js @@ -252,6 +252,7 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) { if (classNameFilter) { var reservedRegex = new RegExp('[(\\s|\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\s|\\/)]'); if (reservedRegex.test(classNameFilter.toString())) { + classNameFilter = null; throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME); } } diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index 99c284f6bbc0..6f8391c1483f 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -283,6 +283,19 @@ describe('animations', function() { }) ); + it('should clear the `classNameFilter` if a disallowed RegExp is passed', + module(function($animateProvider) { + var validRegex = /no-ng-animate/; + var invalidRegex = /no ng-animate/; + + $animateProvider.classNameFilter(validRegex); + expect($animateProvider.classNameFilter()).toEqual(validRegex); + + try { $animateProvider.classNameFilter(invalidRegex); } catch (err) {} + expect($animateProvider.classNameFilter()).toBeNull(); + }) + ); + it('should complete the leave DOM operation in case the classNameFilter fails', function() { module(function($animateProvider) { $animateProvider.classNameFilter(/memorable-animation/); From 899c52ed0e2784331a7e66f31065d9bb1d8b751d Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Mon, 19 Dec 2016 23:47:34 +0200 Subject: [PATCH 3/4] fixup! fix($animate): improve detection on `ng-animate` in `classNameFilter` RegExp --- docs/content/error/$animate/nongcls.ngdoc | 8 +++++ test/ngAnimate/animateSpec.js | 36 ++++++++++------------- 2 files changed, 23 insertions(+), 21 deletions(-) create mode 100644 docs/content/error/$animate/nongcls.ngdoc diff --git a/docs/content/error/$animate/nongcls.ngdoc b/docs/content/error/$animate/nongcls.ngdoc new file mode 100644 index 000000000000..b5774bb46627 --- /dev/null +++ b/docs/content/error/$animate/nongcls.ngdoc @@ -0,0 +1,8 @@ +@ngdoc error +@name $animate:nongcls +@fullName `ng-animate` class not allowed +@description + +This error occurs, when trying to set `$animateProvider.classNameFilter()` to a RegExp containing +the reserved `ng-animate` class. Since `.ng-animate` will be added/removed by `$animate` itself, +using it as part of the `classNameFilter` RegExp is not allowed. diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index 6f8391c1483f..5634896396e9 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -257,28 +257,22 @@ describe('animations', function() { it('should throw a minErr if a regex value is used which partially contains or fully matches the `ng-animate` CSS class', module(function($animateProvider) { - var errorMessage = '$animateProvider.classNameFilter(regex) prohibits accepting a regex ' + - 'value which matches/contains the "ng-animate" CSS class.'; - - assertError(/ng-animate/, true); - assertError(/first ng-animate last/, true); - assertError(/ng-animate-special/, false); - assertError(/first ng-animate-special last/, false); - assertError(/first ng-animate ng-animate-special last/, true); - assertError(/(ng-animate)/, true); - assertError(/(foo|ng-animate|bar)/, true); - assertError(/(foo|)ng-animate(|bar)/, true); - - function assertError(regex, bool) { - var expectation = expect(function() { + expect(setFilter(/ng-animate/)).toThrowMinErr('$animate', 'nongcls'); + expect(setFilter(/first ng-animate last/)).toThrowMinErr('$animate', 'nongcls'); + expect(setFilter(/first ng-animate ng-animate-special last/)).toThrowMinErr('$animate', 'nongcls'); + expect(setFilter(/(ng-animate)/)).toThrowMinErr('$animate', 'nongcls'); + expect(setFilter(/(foo|ng-animate|bar)/)).toThrowMinErr('$animate', 'nongcls'); + expect(setFilter(/(foo|)ng-animate(|bar)/)).toThrowMinErr('$animate', 'nongcls'); + + expect(setFilter(/ng-animater/)).not.toThrow(); + expect(setFilter(/my-ng-animate/)).not.toThrow(); + expect(setFilter(/first ng-animater last/)).not.toThrow(); + expect(setFilter(/first my-ng-animate last/)).not.toThrow(); + + function setFilter(regex) { + return function() { $animateProvider.classNameFilter(regex); - }); - - if (bool) { - expectation.toThrowMinErr('$animate', 'nongcls', errorMessage); - } else { - expectation.not.toThrow(); - } + }; } }) ); From 7f0b72f520ce2cf66fca3266385741a86c240ffc Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Wed, 25 Jan 2017 21:19:54 +0200 Subject: [PATCH 4/4] fixup! fix($animate): reset `classNameFilter` to `null` when a disallowed RegExp is used --- test/ngAnimate/animateSpec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index 5634896396e9..dfa7fffbc2c5 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -285,6 +285,7 @@ describe('animations', function() { $animateProvider.classNameFilter(validRegex); expect($animateProvider.classNameFilter()).toEqual(validRegex); + // eslint-disable-next-line no-empty try { $animateProvider.classNameFilter(invalidRegex); } catch (err) {} expect($animateProvider.classNameFilter()).toBeNull(); })