Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
fix($animate): ensure animations work properly when the $rootElement …
Browse files Browse the repository at this point in the history
…is being animated

Closes #4397
Closes #4231
  • Loading branch information
matsko committed Oct 23, 2013
1 parent f5289fe commit 2623de1
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 12 deletions.
53 changes: 41 additions & 12 deletions src/ngAnimate/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ angular.module('ngAnimate', ['ng'])
var ELEMENT_NODE = 1;
var NG_ANIMATE_STATE = '$$ngAnimateState';
var NG_ANIMATE_CLASS_NAME = 'ng-animate';
var rootAnimateState = {running:true};
$provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', '$rootScope',
function($delegate, $injector, $sniffer, $rootElement, $timeout, $rootScope) {
var rootAnimateState = {disabled:true};
$provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', '$rootScope', '$document',
function($delegate, $injector, $sniffer, $rootElement, $timeout, $rootScope, $document) {

$rootElement.data(NG_ANIMATE_STATE, rootAnimateState);

Expand Down Expand Up @@ -466,18 +466,17 @@ angular.module('ngAnimate', ['ng'])
}
else {
var data = element.data(NG_ANIMATE_STATE) || {};
data.structural = true;
data.running = true;
data.disabled = true;
element.data(NG_ANIMATE_STATE, data);
}
break;

case 1:
rootAnimateState.running = !value;
rootAnimateState.disabled = !value;
break;

default:
value = !rootAnimateState.running;
value = !rootAnimateState.disabled;
break;
}
return !!value;
Expand All @@ -498,7 +497,6 @@ angular.module('ngAnimate', ['ng'])
parent = after ? after.parent() : element.parent();
}

var disabledAnimation = { running : true };
var matches = lookup(animationLookup);
var isClassBased = event == 'addClass' || event == 'removeClass';
var ngAnimateState = element.data(NG_ANIMATE_STATE) || {};
Expand All @@ -507,7 +505,7 @@ angular.module('ngAnimate', ['ng'])
//the element is not currently attached to the document body or then completely close
//the animation if any matching animations are not found at all.
//NOTE: IE8 + IE9 should close properly (run done()) in case a NO animation is not found.
if ((parent.inheritedData(NG_ANIMATE_STATE) || disabledAnimation).running || matches.length == 0) {
if (animationsDisabled(element, parent) || matches.length === 0) {
done();
return;
}
Expand All @@ -528,7 +526,7 @@ angular.module('ngAnimate', ['ng'])

//this would mean that an animation was not allowed so let the existing
//animation do it's thing and close this one early
if(animations.length == 0) {
if(animations.length === 0) {
onComplete && onComplete();
return;
}
Expand Down Expand Up @@ -622,8 +620,39 @@ angular.module('ngAnimate', ['ng'])
}

function cleanup(element) {
element.removeClass(NG_ANIMATE_CLASS_NAME);
element.removeData(NG_ANIMATE_STATE);
if(element[0] == $rootElement[0]) {
if(!rootAnimateState.disabled) {
rootAnimateState.running = false;
rootAnimateState.structural = false;
}
}
else {
element.removeClass(NG_ANIMATE_CLASS_NAME);
element.removeData(NG_ANIMATE_STATE);
}
}

function animationsDisabled(element, parent) {
if(element == $rootElement) {
return rootAnimateState.disabled || rootAnimateState.running;
}

var validState;
do {
//the element did not reach the root element which means that it
//is not apart of the DOM. Therefore there is no reason to do
//any animations on it
if(parent.length === 0 || parent[0] == $document[0]) return true;

var state = parent.data(NG_ANIMATE_STATE);
if(state && (state.disabled != null || state.running != null)) {
validState = state;
break;
}
}
while(parent = parent.parent());

return validState ? (validState.disabled || validState.running) : true;
}
}]);

Expand Down
88 changes: 88 additions & 0 deletions test/ngAnimate/animateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,70 @@ describe("ngAnimate", function() {
expect($animate.enabled(1)).toBe(true);
expect($animate.enabled()).toBe(true);
});

it('should place a hard disable on all child animations', function() {
var count = 0;
module(function($animateProvider) {
$animateProvider.register('.animated', function() {
return {
addClass : function(element, className, done) {
count++;
done();
}
}
});
});
inject(function($compile, $rootScope, $animate, $sniffer, $rootElement, $timeout) {
$animate.enabled(true);

var elm1 = $compile('<div class="animated"></div>')($rootScope);
var elm2 = $compile('<div class="animated"></div>')($rootScope);
$rootElement.append(elm1);
angular.element(document.body).append($rootElement);

$animate.addClass(elm1, 'klass');
expect(count).toBe(1);

$animate.enabled(false);

$animate.addClass(elm1, 'klass2');
expect(count).toBe(1);

$animate.enabled(true);

elm1.append(elm2);

$animate.addClass(elm2, 'klass');
expect(count).toBe(2);

$animate.enabled(false, elm1);

$animate.addClass(elm2, 'klass2');
expect(count).toBe(2);
});
});

it('should skip animations if the element is attached to the $rootElement', function() {
var count = 0;
module(function($animateProvider) {
$animateProvider.register('.animated', function() {
return {
addClass : function(element, className, done) {
count++;
done();
}
}
});
});
inject(function($compile, $rootScope, $animate, $sniffer, $rootElement, $timeout) {
$animate.enabled(true);

var elm1 = $compile('<div class="animated"></div>')($rootScope);

$animate.addClass(elm1, 'klass2');
expect(count).toBe(0);
});
});
});

describe("with polyfill", function() {
Expand Down Expand Up @@ -1956,4 +2020,28 @@ describe("ngAnimate", function() {
expect(element.hasClass('red-add')).toBe(false);
expect(element.hasClass('yellow-add')).toBe(true);
}));

it('should enable and disable animations properly on the root element', function() {
var count = 0;
module(function($animateProvider) {
$animateProvider.register('.animated', function() {
return {
addClass : function(element, className, done) {
count++;
done();
}
}
});
});
inject(function($compile, $rootScope, $animate, $sniffer, $rootElement, $timeout) {

$rootElement.addClass('animated');
$animate.addClass($rootElement, 'green');
expect(count).toBe(1);

$animate.addClass($rootElement, 'red');
expect(count).toBe(2);
});
});

});

0 comments on commit 2623de1

Please sign in to comment.