Skip to content

Commit 8233da7

Browse files
committed
feat(ngAnimate): provide configuration support to match specific className values to trigger animations
Closes angular#5357 Closes angular#5283
1 parent 3fc8017 commit 8233da7

File tree

3 files changed

+83
-4
lines changed

3 files changed

+83
-4
lines changed

src/ng/animate.js

+21
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,27 @@ var $AnimateProvider = ['$provide', function($provide) {
6161
$provide.factory(key, factory);
6262
};
6363

64+
/**
65+
* @ngdoc function
66+
* @name ng.$animateProvider#classNameFilter
67+
* @methodOf ng.$animateProvider
68+
*
69+
* @description
70+
* Sets and/or returns the CSS class regular expression that is checked when performing
71+
* an animation. Upon bootstrap the classNameFilter value is not set at all (which matches
72+
* all CSS classes) and will therefore enable $animate to attempt to perform an animation on
73+
* any element. When setting the classNameFilter value, animations can only be performed
74+
* on elements that only match the filter expression.
75+
*
76+
* @param {RegExp=} expression The className expression which will be checked against all animations
77+
* @return {RegExp} The current CSS className expression value
78+
*/
79+
this.classNameFilter = function(expression) {
80+
return arguments.length == 1 ?
81+
(this.$$classNameFilter = expression) :
82+
this.$$classNameFilter;
83+
};
84+
6485
this.$get = ['$timeout', function($timeout) {
6586

6687
/**

src/ngAnimate/animate.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ angular.module('ngAnimate', ['ng'])
288288
});
289289
});
290290

291+
function isAcceptedClassName(className) {
292+
var exp = $animateProvider.classNameFilter();
293+
return !(exp instanceof RegExp) || exp.test(className);
294+
}
295+
291296
function lookup(name) {
292297
if (name) {
293298
var matches = [],
@@ -569,17 +574,20 @@ angular.module('ngAnimate', ['ng'])
569574
and the onComplete callback will be fired once the animation is fully complete.
570575
*/
571576
function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
572-
var node = extractElementNode(element);
577+
var currentClassName, classes, node = extractElementNode(element);
578+
if(node) {
579+
currentClassName = node.className;
580+
classes = currentClassName + ' ' + className;
581+
}
582+
573583
//transcluded directives may sometimes fire an animation using only comment nodes
574584
//best to catch this early on to prevent any animation operations from occurring
575-
if(!node) {
585+
if(!node || !isAcceptedClassName(classes)) {
576586
fireDOMOperation();
577587
closeAnimation();
578588
return;
579589
}
580590

581-
var currentClassName = node.className;
582-
var classes = currentClassName + ' ' + className;
583591
var animationLookup = (' ' + classes).replace(/\s+/g,'.');
584592
if (!parentElement) {
585593
parentElement = afterElement ? afterElement.parent() : element.parent();

test/ngAnimate/animateSpec.js

+50
Original file line numberDiff line numberDiff line change
@@ -2947,5 +2947,55 @@ describe("ngAnimate", function() {
29472947
expect(capturedAnimation).toBe('leave');
29482948
});
29492949
});
2950+
2951+
it('should animate only the specified CSS className', function() {
2952+
var captures = {};
2953+
module(function($animateProvider) {
2954+
$animateProvider.classNameFilter(/prefixed-animation/);
2955+
$animateProvider.register('.capture', function() {
2956+
return {
2957+
enter : buildFn('enter'),
2958+
leave : buildFn('leave')
2959+
};
2960+
2961+
function buildFn(key) {
2962+
return function(element, className, done) {
2963+
captures[key] = true;
2964+
(done || className)();
2965+
}
2966+
}
2967+
});
2968+
});
2969+
inject(function($rootScope, $compile, $rootElement, $document, $timeout, $templateCache, $sniffer, $animate) {
2970+
if(!$sniffer.transitions) return;
2971+
2972+
var element = $compile('<div class="capture"></div>')($rootScope);
2973+
$rootElement.append(element);
2974+
jqLite($document[0].body).append($rootElement);
2975+
2976+
var enterDone = false;
2977+
$animate.enter(element, $rootElement, null, function() {
2978+
enterDone = true;
2979+
});
2980+
2981+
$rootScope.$digest();
2982+
$timeout.flush();
2983+
2984+
expect(captures['enter']).toBeUndefined();
2985+
expect(enterDone).toBe(true);
2986+
2987+
element.addClass('prefixed-animation');
2988+
2989+
var leaveDone = false;
2990+
$animate.leave(element, function() {
2991+
leaveDone = true;
2992+
});
2993+
$rootScope.$digest();
2994+
$timeout.flush();
2995+
2996+
expect(captures['leave']).toBe(true);
2997+
expect(leaveDone).toBe(true);
2998+
});
2999+
});
29503000
});
29513001
});

0 commit comments

Comments
 (0)