Skip to content

Commit e021a8b

Browse files
chrisirhcfernando-sendMail
authored andcommitted
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 angular-ui#1007 Closes angular-ui#2725
1 parent f815cd9 commit e021a8b

File tree

4 files changed

+44
-72
lines changed

4 files changed

+44
-72
lines changed

src/modal/docs/readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ Finally, a `modal.closing` event is broadcast to the modal scope before the moda
3636
preventDefault on the event, then the modal will remain open. The $close and $dismiss methods return true if the
3737
event was allowed. The event itself includes a parameter for the result/reason and a boolean parameter that indicates
3838
whether the modal is being closed (true) or dismissed.
39+
40+
The `modalConfig` exposes the following global option for all modals/backdrops:
41+

src/modal/modal.js

Lines changed: 39 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ angular.module('ui.bootstrap.modal', [])
5757
/**
5858
* A helper directive for the $modal service. It creates a backdrop element.
5959
*/
60-
.directive('modalBackdrop', [
61-
'$animate', '$modalStack',
62-
function ($animate , $modalStack) {
60+
.directive('modalBackdrop', ['$timeout', function ($timeout) {
6361
return {
6462
restrict: 'EA',
6563
replace: true,
@@ -71,24 +69,21 @@ angular.module('ui.bootstrap.modal', [])
7169
};
7270

7371
function linkFn(scope, element, attrs) {
74-
if (attrs.modalInClass) {
75-
$animate.addClass(element, attrs.modalInClass);
72+
scope.animate = false;
7673

77-
scope.$on($modalStack.NOW_CLOSING_EVENT, function (e, setIsAsync) {
78-
var done = setIsAsync();
79-
$animate.removeClass(element, attrs.modalInClass).then(done);
80-
});
81-
}
74+
//trigger CSS transitions
75+
$timeout(function () {
76+
scope.animate = true;
77+
});
8278
}
8379
}])
8480

85-
.directive('modalWindow', [
86-
'$modalStack', '$q', '$animate',
87-
function ($modalStack , $q , $animate) {
81+
.directive('modalWindow', ['$modalStack', '$q', function ($modalStack, $q) {
8882
return {
8983
restrict: 'EA',
9084
scope: {
91-
index: '@'
85+
index: '@',
86+
animate: '='
9287
},
9388
replace: true,
9489
transclude: true,
@@ -124,14 +119,8 @@ angular.module('ui.bootstrap.modal', [])
124119
});
125120

126121
modalRenderDeferObj.promise.then(function () {
127-
if (attrs.modalInClass) {
128-
$animate.addClass(element, attrs.modalInClass);
129-
130-
scope.$on($modalStack.NOW_CLOSING_EVENT, function (e, setIsAsync) {
131-
var done = setIsAsync();
132-
$animate.removeClass(element, attrs.modalInClass).then(done);
133-
});
134-
}
122+
// trigger CSS transitions
123+
scope.animate = true;
135124

136125
var inputsWithAutofocus = element[0].querySelectorAll('[autofocus]');
137126
/**
@@ -180,21 +169,14 @@ angular.module('ui.bootstrap.modal', [])
180169
};
181170
})
182171

183-
.factory('$modalStack', [
184-
'$animate', '$timeout', '$document', '$compile', '$rootScope',
185-
'$q',
186-
'$$stackedMap',
187-
function ($animate , $timeout , $document , $compile , $rootScope ,
188-
$q,
189-
$$stackedMap) {
172+
.factory('$modalStack', ['$animate', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap',
173+
function ($animate, $timeout, $document, $compile, $rootScope, $$stackedMap) {
190174

191175
var OPENED_MODAL_CLASS = 'modal-open';
192176

193177
var backdropDomEl, backdropScope;
194178
var openedWindows = $$stackedMap.createNew();
195-
var $modalStack = {
196-
NOW_CLOSING_EVENT: 'modal.stack.now-closing'
197-
};
179+
var $modalStack = {};
198180

199181
function backdropIndex() {
200182
var topBackdropIndex = -1;
@@ -213,25 +195,19 @@ angular.module('ui.bootstrap.modal', [])
213195
}
214196
});
215197

216-
function removeModalWindow(modalInstance, elementToReceiveFocus) {
198+
function removeModalWindow(modalInstance) {
217199

218200
var body = $document.find('body').eq(0);
219201
var modalWindow = openedWindows.get(modalInstance).value;
220202

221203
//clean up the stack
222204
openedWindows.remove(modalInstance);
223205

206+
//remove window DOM element
224207
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
225208
body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
226209
checkRemoveBackdrop();
227210
});
228-
229-
//move focus to specified element if available, or else to body
230-
if (elementToReceiveFocus && elementToReceiveFocus.focus) {
231-
elementToReceiveFocus.focus();
232-
} else {
233-
body.focus();
234-
}
235211
}
236212

237213
function checkRemoveBackdrop() {
@@ -247,24 +223,18 @@ angular.module('ui.bootstrap.modal', [])
247223
}
248224

249225
function removeAfterAnimate(domEl, scope, done) {
250-
var asyncDeferred;
251-
var asyncPromise = null;
252-
var setIsAsync = function () {
253-
if (!asyncDeferred) {
254-
asyncDeferred = $q.defer();
255-
asyncPromise = asyncDeferred.promise;
256-
}
257-
258-
return function asyncDone() {
259-
asyncDeferred.resolve();
260-
};
261-
};
262-
scope.$broadcast($modalStack.NOW_CLOSING_EVENT, setIsAsync);
263-
264-
// Note that it's intentional that asyncPromise might be null.
265-
// That's when setIsAsync has not been called during the
266-
// NOW_CLOSING_EVENT broadcast.
267-
return $q.when(asyncPromise).then(afterAnimating);
226+
// Closing animation
227+
scope.animate = false;
228+
229+
if (domEl.attr('modal-animation') && $animate.enabled()) {
230+
// transition out
231+
domEl.one('$animate:close', function closeFn() {
232+
$rootScope.$evalAsync(afterAnimating);
233+
});
234+
} else {
235+
// Ensure this call is async
236+
$timeout(afterAnimating);
237+
}
268238

269239
function afterAnimating() {
270240
if (afterAnimating.done) {
@@ -296,8 +266,6 @@ angular.module('ui.bootstrap.modal', [])
296266

297267
$modalStack.open = function (modalInstance, modal) {
298268

299-
var modalOpener = $document[0].activeElement;
300-
301269
openedWindows.add(modalInstance, {
302270
deferred: modal.deferred,
303271
renderDeferred: modal.renderDeferred,
@@ -335,7 +303,6 @@ angular.module('ui.bootstrap.modal', [])
335303

336304
var modalDomEl = $compile(angularDomEl)(modal.scope);
337305
openedWindows.top().value.modalDomEl = modalDomEl;
338-
openedWindows.top().value.modalOpener = modalOpener;
339306
body.append(modalDomEl);
340307
body.addClass(OPENED_MODAL_CLASS);
341308
};
@@ -348,7 +315,7 @@ angular.module('ui.bootstrap.modal', [])
348315
var modalWindow = openedWindows.get(modalInstance);
349316
if (modalWindow && broadcastClosing(modalWindow, result, true)) {
350317
modalWindow.value.deferred.resolve(result);
351-
removeModalWindow(modalInstance, modalWindow.value.modalOpener);
318+
removeModalWindow(modalInstance);
352319
return true;
353320
}
354321
return !modalWindow;
@@ -358,7 +325,7 @@ angular.module('ui.bootstrap.modal', [])
358325
var modalWindow = openedWindows.get(modalInstance);
359326
if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
360327
modalWindow.value.deferred.reject(reason);
361-
removeModalWindow(modalInstance, modalWindow.value.modalOpener);
328+
removeModalWindow(modalInstance);
362329
return true;
363330
}
364331
return !modalWindow;
@@ -390,17 +357,20 @@ angular.module('ui.bootstrap.modal', [])
390357
var $modalProvider = {
391358
options: {
392359
animation: true,
393-
backdrop: true, //can also be false or 'static'
360+
backdrop: true, //can be also false or 'static'
394361
keyboard: true
395362
},
396-
$get: ['$injector', '$rootScope', '$q', '$templateRequest', '$controller', '$modalStack',
397-
function ($injector, $rootScope, $q, $templateRequest, $controller, $modalStack) {
363+
$get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
364+
function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
398365

399366
var $modal = {};
400367

401368
function getTemplatePromise(options) {
402369
return options.template ? $q.when(options.template) :
403-
$templateRequest(angular.isFunction(options.templateUrl) ? (options.templateUrl)() : options.templateUrl);
370+
$http.get(angular.isFunction(options.templateUrl) ? (options.templateUrl)() : options.templateUrl,
371+
{cache: $templateCache}).then(function (result) {
372+
return result.data;
373+
});
404374
}
405375

406376
function getResolvePromises(resolves) {
@@ -488,8 +458,8 @@ angular.module('ui.bootstrap.modal', [])
488458

489459
templateAndResolvePromise.then(function () {
490460
modalOpenedDeferred.resolve(true);
491-
}, function (reason) {
492-
modalOpenedDeferred.reject(reason);
461+
}, function () {
462+
modalOpenedDeferred.reject(false);
493463
});
494464

495465
return modalInstance;

template/modal/backdrop.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="modal-backdrop"
22
modal-animation-class="fade"
3-
modal-in-class="in"
3+
ng-class="{in: animate}"
44
ng-style="{'z-index': 1040 + (index && 1 || 0) + index*10}"
55
></div>

template/modal/window.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<div modal-render="{{$isRendered}}" tabindex="-1" role="dialog" class="modal"
22
modal-animation-class="fade"
3-
modal-in-class="in"
4-
ng-style="{'z-index': 1050 + index*10, display: 'block'}" ng-click="close($event)">
3+
ng-class="{in: animate}" ng-style="{'z-index': 1050 + index*10, display: 'block'}" ng-click="close($event)">
54
<div class="modal-dialog" ng-class="size ? 'modal-' + size : ''"><div class="modal-content" modal-transclude></div></div>
65
</div>

0 commit comments

Comments
 (0)