From 5e661d47d6698fdfebb52402eb1687e5697c0040 Mon Sep 17 00:00:00 2001 From: Chris Chua Date: Sat, 20 Sep 2014 18:03:57 -0700 Subject: [PATCH] feat(modal): add option to disable animations Note: Move backdropClass logic into compile function because otherwise modifying classes in the compile function is broken when using an interpolated class attribute. Fixes #1007 Closes #2725 --- src/modal/docs/demo.html | 1 + src/modal/docs/demo.js | 8 +++++++ src/modal/docs/readme.md | 4 ++++ src/modal/modal.js | 42 +++++++++++++++++++++++++++--------- src/modal/test/modal.spec.js | 24 +++++++++++++++++++++ template/modal/backdrop.html | 3 ++- template/modal/window.html | 4 +++- 7 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/modal/docs/demo.html b/src/modal/docs/demo.html index 0496451c53..48302c7065 100644 --- a/src/modal/docs/demo.html +++ b/src/modal/docs/demo.html @@ -20,5 +20,6 @@ +
Selection from a modal: {{ selected }}
\ No newline at end of file diff --git a/src/modal/docs/demo.js b/src/modal/docs/demo.js index fa332f4cd3..4e1823c72f 100644 --- a/src/modal/docs/demo.js +++ b/src/modal/docs/demo.js @@ -2,9 +2,12 @@ angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope $scope.items = ['item1', 'item2', 'item3']; + $scope.animationsEnabled = true; + $scope.open = function (size) { var modalInstance = $modal.open({ + animation: $scope.animationsEnabled, templateUrl: 'myModalContent.html', controller: 'ModalInstanceCtrl', size: size, @@ -21,6 +24,11 @@ angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope $log.info('Modal dismissed at: ' + new Date()); }); }; + + $scope.toggleAnimation = function () { + $scope.animationsEnabled = !$scope.animationsEnabled; + }; + }); // Please note that $modalInstance represents a modal window (instance) dependency. diff --git a/src/modal/docs/readme.md b/src/modal/docs/readme.md index 2a8c081cdf..25014233b7 100644 --- a/src/modal/docs/readme.md +++ b/src/modal/docs/readme.md @@ -9,6 +9,7 @@ The `$modal` service has only one method: `open(options)` where available option * `controller` - a controller for a modal instance - it can initialize scope used by modal. Accepts the "controller-as" syntax in the form 'SomeCtrl as myctrl'; can be injected with `$modalInstance` * `controllerAs` - an alternative to the controller-as syntax, matching the API of directive definitions. Requires the `controller` option to be provided as well * `resolve` - members that will be resolved and passed to the controller as locals; it is equivalent of the `resolve` property for AngularJS routes +* `animation` - set to false to disable animations on new modal/backdrop. Does not toggle animations for modals/backdrops that are already displayed. * `backdrop` - controls presence of a backdrop. Allowed values: true (default), false (no backdrop), `'static'` - backdrop is present but modal window is not closed when clicking outside of the modal window. * `keyboard` - indicates whether the dialog should be closable by hitting the ESC key, defaults to true * `backdropClass` - additional CSS class(es) to be added to a modal backdrop template @@ -35,3 +36,6 @@ Finally, a `modal.closing` event is broadcast to the modal scope before the moda preventDefault on the event, then the modal will remain open. The $close and $dismiss methods return true if the event was allowed. The event itself includes a parameter for the result/reason and a boolean parameter that indicates whether the modal is being closed (true) or dismissed. + +The `modalConfig` exposes the following global option for all modals/backdrops: + diff --git a/src/modal/modal.js b/src/modal/modal.js index 9304b635f4..3c8aff93ce 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -62,17 +62,20 @@ angular.module('ui.bootstrap.modal', []) restrict: 'EA', replace: true, templateUrl: 'template/modal/backdrop.html', - link: function (scope, element, attrs) { - scope.backdropClass = attrs.backdropClass || ''; - - scope.animate = false; - - //trigger CSS transitions - $timeout(function () { - scope.animate = true; - }); + compile: function (tElement, tAttrs) { + tElement.addClass(tAttrs.backdropClass); + return linkFn; } }; + + function linkFn(scope, element, attrs) { + scope.animate = false; + + //trigger CSS transitions + $timeout(function () { + scope.animate = true; + }); + } }]) .directive('modalWindow', ['$modalStack', '$q', function ($modalStack, $q) { @@ -144,6 +147,17 @@ angular.module('ui.bootstrap.modal', []) }; }]) + .directive('modalAnimationClass', [ + function () { + return { + compile: function (tElement, tAttrs) { + if (tAttrs.modalAnimation) { + tElement.addClass(tAttrs.modalAnimationClass); + } + } + }; + }]) + .directive('modalTransclude', function () { return { link: function($scope, $element, $attrs, controller, $transclude) { @@ -212,7 +226,7 @@ angular.module('ui.bootstrap.modal', []) // Closing animation scope.animate = false; - if ($animate.enabled()) { + if (domEl.attr('modal-animation') && $animate.enabled()) { // transition out domEl.one('$animate:close', function closeFn() { $rootScope.$evalAsync(afterAnimating); @@ -268,6 +282,9 @@ angular.module('ui.bootstrap.modal', []) backdropScope.index = currBackdropIndex; var angularBackgroundDomEl = angular.element('
'); angularBackgroundDomEl.attr('backdrop-class', modal.backdropClass); + if (modal.animation) { + angularBackgroundDomEl.attr('modal-animation', 'true'); + } backdropDomEl = $compile(angularBackgroundDomEl)(backdropScope); body.append(backdropDomEl); } @@ -280,6 +297,9 @@ angular.module('ui.bootstrap.modal', []) 'index': openedWindows.length() - 1, 'animate': 'animate' }).html(modal.content); + if (modal.animation) { + angularDomEl.attr('modal-animation', 'true'); + } var modalDomEl = $compile(angularDomEl)(modal.scope); openedWindows.top().value.modalDomEl = modalDomEl; @@ -336,6 +356,7 @@ angular.module('ui.bootstrap.modal', []) var $modalProvider = { options: { + animation: true, backdrop: true, //can be also false or 'static' keyboard: true }, @@ -422,6 +443,7 @@ angular.module('ui.bootstrap.modal', []) deferred: modalResultDeferred, renderDeferred: modalRenderDeferred, content: tplAndVars[0], + animation: modalOptions.animation, backdrop: modalOptions.backdrop, keyboard: modalOptions.keyboard, backdropClass: modalOptions.backdropClass, diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index b6e3fa585e..f51ab18491 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -558,6 +558,30 @@ describe('$modal', function () { expect($document.find('div.modal-dialog')).toHaveClass('modal-custom'); }); }); + + describe('animation', function () { + + it('should have animation fade classes by default', function () { + open({ + template: '
Small modal dialog
', + }); + + expect($document.find('.modal')).toHaveClass('fade'); + expect($document.find('.modal-backdrop')).toHaveClass('fade'); + }); + + it('should not have fade classes if animation false', function () { + open({ + template: '
Small modal dialog
', + animation: false + }); + + expect($document.find('.modal')).not.toHaveClass('fade'); + expect($document.find('.modal-backdrop')).not.toHaveClass('fade'); + }); + + }); + }); describe('multiple modals', function () { diff --git a/template/modal/backdrop.html b/template/modal/backdrop.html index 9cbfcb6cbb..72514a377d 100644 --- a/template/modal/backdrop.html +++ b/template/modal/backdrop.html @@ -1,4 +1,5 @@ - diff --git a/template/modal/window.html b/template/modal/window.html index f46e952257..5501937bd6 100644 --- a/template/modal/window.html +++ b/template/modal/window.html @@ -1,3 +1,5 @@ -