Skip to content

Commit

Permalink
feat(ngAnimate): provide configuration support to match specific clas…
Browse files Browse the repository at this point in the history
…sName values to trigger animations

Closes angular#5357
Closes angular#5283
  • Loading branch information
matsko authored and jamesdaily committed Jan 27, 2014
1 parent 99a8484 commit 8cca444
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 4 deletions.
22 changes: 22 additions & 0 deletions src/ng/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

/**
Expand Down
18 changes: 14 additions & 4 deletions src/ngAnimate/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [],
Expand Down Expand Up @@ -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();
Expand Down
50 changes: 50 additions & 0 deletions test/ngAnimate/animateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
});

0 comments on commit 8cca444

Please sign in to comment.