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

Commit 158d267

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

File tree

3 files changed

+37
-51
lines changed

3 files changed

+37
-51
lines changed

src/modal/modal.js

+31-39
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,
@@ -69,12 +71,14 @@ angular.module('ui.bootstrap.modal', [])
6971
};
7072

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

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

@@ -123,7 +127,7 @@ angular.module('ui.bootstrap.modal', [])
123127
if (attrs.modalInClass) {
124128
$animate.addClass(element, attrs.modalInClass);
125129

126-
scope.$on($modalStack.WINDOW_CLOSING_EVENT, function (e, setIsAsync) {
130+
scope.$on($modalStack.NOW_CLOSING_EVENT, function (e, setIsAsync) {
127131
var done = setIsAsync();
128132
$animate.removeClass(element, attrs.modalInClass).then(done);
129133
});
@@ -189,7 +193,7 @@ angular.module('ui.bootstrap.modal', [])
189193
var backdropDomEl, backdropScope;
190194
var openedWindows = $$stackedMap.createNew();
191195
var $modalStack = {
192-
WINDOW_CLOSING_EVENT: 'modal.stack.window-closing'
196+
NOW_CLOSING_EVENT: 'modal.stack.now-closing'
193197
};
194198

195199
function backdropIndex() {
@@ -217,25 +221,7 @@ angular.module('ui.bootstrap.modal', [])
217221
//clean up the stack
218222
openedWindows.remove(modalInstance);
219223

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-
224+
removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
239225
body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
240226
checkRemoveBackdrop();
241227
});
@@ -261,18 +247,24 @@ angular.module('ui.bootstrap.modal', [])
261247
}
262248

263249
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-
}
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);
276268

277269
function afterAnimating() {
278270
if (afterAnimating.done) {

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;

template/modal/backdrop.html

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

0 commit comments

Comments
 (0)