Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit f7ed003

Browse files
committed
fix(modal): backdrop animation on AngularJS 1.4
Fixes #3896
1 parent 13a0354 commit f7ed003

File tree

3 files changed

+38
-49
lines changed

3 files changed

+38
-49
lines changed

Diff for: src/modal/modal.js

+32-38
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ angular.module('ui.bootstrap.modal', [])
5757
/**
5858
* A helper directive for the $modal service. It creates a backdrop element.
5959
*/
60-
.directive('modalBackdrop', ['$timeout', function ($timeout) {
60+
.directive('modalBackdrop', [
61+
'$animate', '$modalStack',
62+
function ($animate , $modalStack) {
6163
return {
6264
restrict: 'EA',
6365
replace: true,
@@ -71,10 +73,14 @@ angular.module('ui.bootstrap.modal', [])
7173
function linkFn(scope, element, attrs) {
7274
scope.animate = false;
7375

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

@@ -123,7 +129,7 @@ angular.module('ui.bootstrap.modal', [])
123129
if (attrs.modalInClass) {
124130
$animate.addClass(element, attrs.modalInClass);
125131

126-
scope.$on($modalStack.WINDOW_CLOSING_EVENT, function (e, setIsAsync) {
132+
scope.$on($modalStack.NOW_CLOSING_EVENT, function (e, setIsAsync) {
127133
var done = setIsAsync();
128134
$animate.removeClass(element, attrs.modalInClass).then(done);
129135
});
@@ -189,7 +195,7 @@ angular.module('ui.bootstrap.modal', [])
189195
var backdropDomEl, backdropScope;
190196
var openedWindows = $$stackedMap.createNew();
191197
var $modalStack = {
192-
WINDOW_CLOSING_EVENT: 'modal.stack.window-closing'
198+
NOW_CLOSING_EVENT: 'modal.stack.now-closing'
193199
};
194200

195201
function backdropIndex() {
@@ -217,25 +223,7 @@ angular.module('ui.bootstrap.modal', [])
217223
//clean up the stack
218224
openedWindows.remove(modalInstance);
219225

220-
var closingDeferred;
221-
var closingPromise;
222-
var setIsAsync = function () {
223-
if (!closingDeferred) {
224-
closingDeferred = $q.defer();
225-
closingPromise = closingDeferred.promise;
226-
}
227-
228-
return function () {
229-
closingDeferred.resolve();
230-
};
231-
};
232-
modalWindow.modalScope.$broadcast($modalStack.WINDOW_CLOSING_EVENT, setIsAsync);
233-
234-
//remove window DOM element
235-
$q.when(closingPromise).then(function() {
236-
modalWindow.modalDomEl.remove();
237-
modalWindow.modalScope.$destroy();
238-
226+
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
239227
body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
240228
checkRemoveBackdrop();
241229
});
@@ -261,18 +249,24 @@ angular.module('ui.bootstrap.modal', [])
261249
}
262250

263251
function removeAfterAnimate(domEl, scope, done) {
264-
// Closing animation
265-
scope.animate = false;
266-
267-
if (domEl.attr('modal-animation') && $animate.enabled()) {
268-
// transition out
269-
domEl.one('$animate:close', function closeFn() {
270-
$rootScope.$evalAsync(afterAnimating);
271-
});
272-
} else {
273-
// Ensure this call is async
274-
$timeout(afterAnimating);
275-
}
252+
var asyncDeferred;
253+
var asyncPromise = null;
254+
var setIsAsync = function () {
255+
if (!asyncDeferred) {
256+
asyncDeferred = $q.defer();
257+
asyncPromise = asyncDeferred.promise;
258+
}
259+
260+
return function asyncDone() {
261+
asyncDeferred.resolve();
262+
};
263+
};
264+
scope.$broadcast($modalStack.NOW_CLOSING_EVENT, setIsAsync);
265+
266+
// Note that it's intentional that asyncPromise might be null
267+
// That's when setIsAsync has not been called, if closing is
268+
// *not* asynchronous.
269+
return $q.when(asyncPromise).then(afterAnimating);
276270

277271
function afterAnimating() {
278272
if (afterAnimating.done) {

Diff for: src/modal/test/modal.spec.js

+5-11
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ describe('$modal', function () {
142142
function open(modalOptions) {
143143
var modal = $modal.open(modalOptions);
144144
$rootScope.$digest();
145+
$timeout.flush(0);
145146
return modal;
146147
}
147148

@@ -258,7 +259,6 @@ describe('$modal', function () {
258259
expect(document.activeElement.tagName).toBe('A');
259260

260261
var modal = open({template: '<div>Content<button>inside modal</button></div>'});
261-
$timeout.flush();
262262
expect(document.activeElement.tagName).toBe('DIV');
263263
expect($document).toHaveModalsOpen(1);
264264

@@ -280,7 +280,6 @@ describe('$modal', function () {
280280
expect(document.activeElement.tagName).toBe('A');
281281

282282
var modal = open({template: '<div>Content</div>'});
283-
$timeout.flush();
284283
expect(document.activeElement.tagName).toBe('DIV');
285284
expect($document).toHaveModalsOpen(1);
286285

@@ -580,20 +579,17 @@ describe('$modal', function () {
580579
expect($document).toHaveBackdrop();
581580
});
582581

583-
it('should animate backdrop on each modal opening', function () {
582+
it('should contain backdrop in classes on each modal opening', function () {
584583

585584
var modal = open({ template: '<div>With backdrop</div>' });
586585
var backdropEl = $document.find('body > div.modal-backdrop');
587-
expect(backdropEl).not.toHaveClass('in');
588-
589-
$timeout.flush();
590586
expect(backdropEl).toHaveClass('in');
591587

592588
dismiss(modal);
593589

594590
modal = open({ template: '<div>With backdrop</div>' });
595591
backdropEl = $document.find('body > div.modal-backdrop');
596-
expect(backdropEl).not.toHaveClass('in');
592+
expect(backdropEl).toHaveClass('in');
597593

598594
});
599595

@@ -750,13 +746,11 @@ describe('$modal', function () {
750746
expect(document.activeElement.tagName).toBe('A');
751747

752748
var modal1 = open({template: '<div>Modal1<button id="focus">inside modal1</button></div>'});
753-
$timeout.flush();
754749
document.getElementById('focus').focus();
755750
expect(document.activeElement.tagName).toBe('BUTTON');
756751
expect($document).toHaveModalsOpen(1);
757752

758753
var modal2 = open({template: '<div>Modal2</div>'});
759-
$timeout.flush();
760754
expect(document.activeElement.tagName).toBe('DIV');
761755
expect($document).toHaveModalsOpen(2);
762756

@@ -789,7 +783,7 @@ describe('$modal', function () {
789783
modal = open({template: template, controller: TestCtrl});
790784

791785
preventDefault = true;
792-
expect(close(modal, 'result')).toBeFalsy();
786+
expect(close(modal, 'result', true)).toBeFalsy();
793787
expect($document).toHaveModalsOpen(1);
794788

795789
preventDefault = false;
@@ -799,7 +793,7 @@ describe('$modal', function () {
799793
modal = open({template: template, controller: TestCtrl});
800794

801795
preventDefault = true;
802-
expect(dismiss(modal, 'result')).toBeFalsy();
796+
expect(dismiss(modal, 'result', true)).toBeFalsy();
803797
expect($document).toHaveModalsOpen(1);
804798

805799
preventDefault = false;

Diff for: template/modal/backdrop.html

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

0 commit comments

Comments
 (0)