From 5476cb6e9b6d7a16e3a86585bc2db5e63b16cd4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemela=CC=88?= Date: Mon, 8 Apr 2013 20:37:57 -0400 Subject: [PATCH] feat($animator): allow to globally disable and enable animations --- src/ng/animator.js | 97 ++++++++++++++++++++++++++--------------- test/ng/animatorSpec.js | 82 +++++++++++++++++++++++++++++++++- 2 files changed, 141 insertions(+), 38 deletions(-) diff --git a/src/ng/animator.js b/src/ng/animator.js index 7cafa568e5f3..e1c3ab48a55b 100644 --- a/src/ng/animator.js +++ b/src/ng/animator.js @@ -121,21 +121,24 @@ * */ -/** - * @ngdoc function - * @name ng.$animator - * - * @description - * The $animator service provides the DOM manipulation API which is decorated with animations. - * - * @param {Scope} scope the scope for the ng-animate. - * @param {Attributes} attr the attributes object which contains the ngAnimate key / value pair. (The attributes are - * passed into the linking function of the directive using the `$animator`.) - * @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods. - */ var $AnimatorProvider = function() { - this.$get = ['$animation', '$window', '$sniffer', function($animation, $window, $sniffer) { - return function(scope, attrs) { + var globalAnimationEnabled = true; + + this.$get = ['$animation', '$window', '$sniffer', '$rootScope', function($animation, $window, $sniffer, $rootScope) { + /** + * @ngdoc function + * @name ng.$animator + * @function + * + * @description + * The $animator.create service provides the DOM manipulation API which is decorated with animations. + * + * @param {Scope} scope the scope for the ng-animate. + * @param {Attributes} attr the attributes object which contains the ngAnimate key / value pair. (The attributes are + * passed into the linking function of the directive using the `$animator`.) + * @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods. + */ + var AnimatorService = function(scope, attrs) { var ngAnimateAttr = attrs.ngAnimate; var animator = {}; @@ -230,7 +233,7 @@ var $AnimatorProvider = function() { var startClass = className + '-start'; return function(element, parent, after) { - if (!$sniffer.supportsTransitions && !polyfillSetup && !polyfillStart) { + if (!globalAnimationEnabled || !$sniffer.supportsTransitions && !polyfillSetup && !polyfillStart) { beforeFn(element, parent, after); afterFn(element, parent, after); return; @@ -280,32 +283,54 @@ var $AnimatorProvider = function() { } } } - } - function show(element) { - element.css('display', ''); - } + function show(element) { + element.css('display', ''); + } - function hide(element) { - element.css('display', 'none'); - } + function hide(element) { + element.css('display', 'none'); + } - function insert(element, parent, after) { - if (after) { - after.after(element); - } else { - parent.append(element); + function insert(element, parent, after) { + if (after) { + after.after(element); + } else { + parent.append(element); + } + } + + function remove(element) { + element.remove(); } - } - function remove(element) { - element.remove(); - } + function move(element, parent, after) { + // Do not remove element before insert. Removing will cause data associated with the + // element to be dropped. Insert will implicitly do the remove. + insert(element, parent, after); + } + }; + + /** + * @ngdoc function + * @name ng.animator#enabled + * @methodOf ng.$animator + * @function + * + * @param {Boolean=} If provided then set the animation on or off. + * @return {Boolean} Current animation state. + * + * @description + * Globally enables/disables animations. + * + */ + AnimatorService.enabled = function(value) { + if (arguments.length) { + globalAnimationEnabled = !!value; + } + return globalAnimationEnabled; + }; - function move(element, parent, after) { - // Do not remove element before insert. Removing will cause data associated with the - // element to be dropped. Insert will implicitly do the remove. - insert(element, parent, after); - } + return AnimatorService; }]; }; diff --git a/test/ng/animatorSpec.js b/test/ng/animatorSpec.js index a8c6c5475993..794574889e8c 100644 --- a/test/ng/animatorSpec.js +++ b/test/ng/animatorSpec.js @@ -8,6 +8,20 @@ describe("$animator", function() { dealoc(element); }); + describe("enable / disable", function() { + + it("should disable and enable the animations", inject(function($animator) { + expect($animator.enabled()).toBe(true); + + expect($animator.enabled(0)).toBe(false); + expect($animator.enabled()).toBe(false); + + expect($animator.enabled(1)).toBe(true); + expect($animator.enabled()).toBe(true); + })); + + }); + describe("without animation", function() { var window, animator; @@ -46,20 +60,27 @@ describe("$animator", function() { expect(element.text()).toBe('21'); })); - it("should animate the show animation event", inject(function($animator, $compile, $rootScope) { + it("should animate the show animation event", inject(function() { element.css('display','none'); expect(element.css('display')).toBe('none'); animator.show(element); expect(element[0].style.display).toBe(''); })); - it("should animate the hide animation event", inject(function($animator, $compile, $rootScope) { + it("should animate the hide animation event", inject(function() { element.css('display','block'); expect(element.css('display')).toBe('block'); animator.hide(element); expect(element.css('display')).toBe('none'); })); + it("should still perform DOM operations even if animations are disabled", inject(function($animator) { + $animator.enabled(false); + element.css('display','block'); + expect(element.css('display')).toBe('block'); + animator.hide(element); + expect(element.css('display')).toBe('none'); + })); }); describe("with polyfill", function() { @@ -206,6 +227,63 @@ describe("$animator", function() { window.setTimeout.expect(1).process(); expect(element.text()).toBe('memento'); })); + + it("should not run if animations are disabled", inject(function($animator, $rootScope) { + $animator.enabled(false); + + animator = $animator($rootScope, { + ngAnimate : '{show: \'setup-memo\'}' + }); + element.text('123'); + expect(element.text()).toBe('123'); + animator.show(element); + expect(element.text()).toBe('123'); + + $animator.enabled(true); + + animator.show(element); + window.setTimeout.expect(1).process(); + expect(element.text()).toBe('memento'); + })); + }); + + describe("with css3", function() { + var window, animator, prefix, vendorPrefix; + + beforeEach(function() { + module(function($animationProvider, $provide) { + $provide.value('$window', window = angular.mock.createMockWindow()); + return function($sniffer) { + vendorPrefix = '-' + $sniffer.vendorPrefix + '-'; + }; + }) + }); + + it("should skip animations if disabled and run when enabled", + inject(function($animator, $rootScope, $compile, $sniffer) { + $animator.enabled(false); + element = $compile('
1
')($rootScope); + var animator = $animator($rootScope, { + ngAnimate : '{show: \'inline-show\'}' + }); + + element.css('display','none'); + expect(element.css('display')).toBe('none'); + animator.show(element); + expect(element[0].style.display).toBe(''); + + $animator.enabled(true); + + element.css('display','none'); + expect(element.css('display')).toBe('none'); + + animator.show(element); + if ($sniffer.supportsTransitions) { + window.setTimeout.expect(1).process(); + window.setTimeout.expect(1000).process(); + } + expect(element[0].style.display).toBe(''); + })); }); it("should throw an error when an invalid ng-animate syntax is provided", inject(function($compile, $rootScope) {