aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatias Niemelä2013-12-16 15:45:57 -0500
committerMatias Niemelä2013-12-19 16:37:29 -0500
commitcef084ade9072090259d8c679751cac3ffeaed51 (patch)
treefe42b514dbbbdd893122fa3f7c7d647afba676b7
parent937caab6475e53a7ea0206e992f8a52449232e78 (diff)
downloadangular.js-cef084ade9072090259d8c679751cac3ffeaed51.tar.bz2
feat(ngAnimate): provide configuration support to match specific className values to trigger animations
Closes #5357 Closes #5283
-rw-r--r--src/ng/animate.js22
-rw-r--r--src/ngAnimate/animate.js18
-rw-r--r--test/ngAnimate/animateSpec.js50
3 files changed, 86 insertions, 4 deletions
diff --git a/src/ng/animate.js b/src/ng/animate.js
index b662d9c1..fa5b936d 100644
--- a/src/ng/animate.js
+++ b/src/ng/animate.js
@@ -61,6 +61,28 @@ var $AnimateProvider = ['$provide', function($provide) {
$provide.factory(key, factory);
};
+ /**
+ * @ngdoc function
+ * @name ng.$animateProvider#classNameFilter
+ * @methodOf ng.$animateProvider
+ *
+ * @description
+ * Sets and/or returns the CSS class regular expression that is checked when performing
+ * an animation. Upon bootstrap the classNameFilter value is not set at all and will
+ * therefore enable $animate to attempt to perform an animation on any element.
+ * When setting the classNameFilter value, animations will only be performed on elements
+ * that successfully match the filter expression. This in turn can boost performance
+ * for low-powered devices as well as applications containing a lot of structural operations.
+ * @param {RegExp=} expression The className expression which will be checked against all animations
+ * @return {RegExp} The current CSS className expression value. If null then there is no expression value
+ */
+ this.classNameFilter = function(expression) {
+ if(arguments.length === 1) {
+ this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
+ }
+ return this.$$classNameFilter;
+ };
+
this.$get = ['$timeout', function($timeout) {
/**
diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js
index 16d0aa0d..08c088e9 100644
--- a/src/ngAnimate/animate.js
+++ b/src/ngAnimate/animate.js
@@ -288,6 +288,13 @@ angular.module('ngAnimate', ['ng'])
});
});
+ var classNameFilter = $animateProvider.classNameFilter();
+ var isAnimatableClassName = !classNameFilter
+ ? function() { return true; }
+ : function(className) {
+ return classNameFilter.test(className);
+ };
+
function lookup(name) {
if (name) {
var matches = [],
@@ -569,17 +576,20 @@ angular.module('ngAnimate', ['ng'])
and the onComplete callback will be fired once the animation is fully complete.
*/
function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
- var node = extractElementNode(element);
+ var currentClassName, classes, node = extractElementNode(element);
+ if(node) {
+ currentClassName = node.className;
+ classes = currentClassName + ' ' + className;
+ }
+
//transcluded directives may sometimes fire an animation using only comment nodes
//best to catch this early on to prevent any animation operations from occurring
- if(!node) {
+ if(!node || !isAnimatableClassName(classes)) {
fireDOMOperation();
closeAnimation();
return;
}
- var currentClassName = node.className;
- var classes = currentClassName + ' ' + className;
var animationLookup = (' ' + classes).replace(/\s+/g,'.');
if (!parentElement) {
parentElement = afterElement ? afterElement.parent() : element.parent();
diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js
index c9a08fe8..fedea535 100644
--- a/test/ngAnimate/animateSpec.js
+++ b/test/ngAnimate/animateSpec.js
@@ -2947,5 +2947,55 @@ describe("ngAnimate", function() {
expect(capturedAnimation).toBe('leave');
});
});
+
+ it('should animate only the specified CSS className', function() {
+ var captures = {};
+ module(function($animateProvider) {
+ $animateProvider.classNameFilter(/prefixed-animation/);
+ $animateProvider.register('.capture', function() {
+ return {
+ enter : buildFn('enter'),
+ leave : buildFn('leave')
+ };
+
+ function buildFn(key) {
+ return function(element, className, done) {
+ captures[key] = true;
+ (done || className)();
+ }
+ }
+ });
+ });
+ inject(function($rootScope, $compile, $rootElement, $document, $timeout, $templateCache, $sniffer, $animate) {
+ if(!$sniffer.transitions) return;
+
+ var element = $compile('<div class="capture"></div>')($rootScope);
+ $rootElement.append(element);
+ jqLite($document[0].body).append($rootElement);
+
+ var enterDone = false;
+ $animate.enter(element, $rootElement, null, function() {
+ enterDone = true;
+ });
+
+ $rootScope.$digest();
+ $timeout.flush();
+
+ expect(captures['enter']).toBeUndefined();
+ expect(enterDone).toBe(true);
+
+ element.addClass('prefixed-animation');
+
+ var leaveDone = false;
+ $animate.leave(element, function() {
+ leaveDone = true;
+ });
+ $rootScope.$digest();
+ $timeout.flush();
+
+ expect(captures['leave']).toBe(true);
+ expect(leaveDone).toBe(true);
+ });
+ });
});
});