Skip to content

Commit 531716e

Browse files
committed
feat(ngAnimate): provide configuration support to match specific className values to trigger animations
Closes angular#5357 Closes angular#5283
1 parent 73c6671 commit 531716e

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
@@ -2926,5 +2926,55 @@ describe("ngAnimate", function() {
29262926
expect(capturedAnimation).toBe('leave');
29272927
});
29282928
});
2929+
2930+
it('should animate only the specified CSS className', function() {
2931+
var captures = {};
2932+
module(function($animateProvider) {
2933+
$animateProvider.classNameFilter(/prefixed-animation/);
2934+
$animateProvider.register('.capture', function() {
2935+
return {
2936+
enter : buildFn('enter'),
2937+
leave : buildFn('leave')
2938+
};
2939+
2940+
function buildFn(key) {
2941+
return function(element, className, done) {
2942+
captures[key] = true;
2943+
(done || className)();
2944+
}
2945+
}
2946+
});
2947+
});
2948+
inject(function($rootScope, $compile, $rootElement, $document, $timeout, $templateCache, $sniffer, $animate) {
2949+
if(!$sniffer.transitions) return;
2950+
2951+
var element = $compile('<div class="capture"></div>')($rootScope);
2952+
$rootElement.append(element);
2953+
jqLite($document[0].body).append($rootElement);
2954+
2955+
var enterDone = false;
2956+
$animate.enter(element, $rootElement, null, function() {
2957+
enterDone = true;
2958+
});
2959+
2960+
$rootScope.$digest();
2961+
$timeout.flush();
2962+
2963+
expect(captures['enter']).toBeUndefined();
2964+
expect(enterDone).toBe(true);
2965+
2966+
element.addClass('prefixed-animation');
2967+
2968+
var leaveDone = false;
2969+
$animate.leave(element, function() {
2970+
leaveDone = true;
2971+
});
2972+
$rootScope.$digest();
2973+
$timeout.flush();
2974+
2975+
expect(captures['leave']).toBe(true);
2976+
expect(leaveDone).toBe(true);
2977+
});
2978+
});
29292979
});
29302980
});

0 commit comments

Comments
 (0)