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

Commit

Permalink
fix(modal): ensure correct index is set
Browse files Browse the repository at this point in the history
- Fixes index set to avoid potential concurrent z-index values for multiple modals

Closes #5733
Fixes #5670
  • Loading branch information
Pem Taira authored and wesleycho committed Apr 5, 2016
1 parent 4ec35e4 commit a08ad70
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 1 deletion.
20 changes: 19 additions & 1 deletion src/modal/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
var $modalStack = {
NOW_CLOSING_EVENT: 'modal.stack.now-closing'
};
var topModalIndex = 0;
var previousTopOpenedModal = null;

//Modal focus behavior
var tabableSelector = 'a[href], area[href], input:not([disabled]), ' +
Expand All @@ -278,6 +280,12 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
topBackdropIndex = i;
}
}

// If any backdrop exist, ensure that it's index is always
// right below the top modal
if (topBackdropIndex > -1 && topBackdropIndex < topModalIndex) {
topBackdropIndex = topModalIndex;
}
return topBackdropIndex;
}

Expand All @@ -293,6 +301,10 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p

//clean up the stack
openedWindows.remove(modalInstance);
previousTopOpenedModal = openedWindows.top();
if (previousTopOpenedModal) {
topModalIndex = parseInt(previousTopOpenedModal.value.modalDomEl.attr('index'), 10);
}

removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS;
Expand Down Expand Up @@ -432,6 +444,10 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
modalBodyClass = modal.openedClass || OPENED_MODAL_CLASS;

toggleTopWindowClass(false);

// Store the current top first, to determine what index we ought to use
// for the current top modal
previousTopOpenedModal = openedWindows.top();

openedWindows.add(modalInstance, {
deferred: modal.deferred,
Expand Down Expand Up @@ -468,13 +484,15 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
$animate.enter(backdropDomEl, appendToElement);
}

// Set the top modal index based on the index of the previous top modal
topModalIndex = previousTopOpenedModal ? parseInt(previousTopOpenedModal.value.modalDomEl.attr('index'), 10) + 1 : 0;
var angularDomEl = angular.element('<div uib-modal-window="modal-window"></div>');
angularDomEl.attr({
'template-url': modal.windowTemplateUrl,
'window-class': modal.windowClass,
'window-top-class': modal.windowTopClass,
'size': modal.size,
'index': openedWindows.length() - 1,
'index': topModalIndex,
'animate': 'animate'
}).html(modal.content);
if (modal.animation) {
Expand Down
101 changes: 101 additions & 0 deletions src/modal/test/modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1615,6 +1615,107 @@ describe('$uibModal', function() {
expect($document.find('div.modal1')).toHaveClass('modal-top');
expect($document).toHaveModalsOpen(1);
});

it('should have top modal with highest index', function() {
var modal2Index = null;
var modal3Index = null;

var modal1Instance = {
result: $q.defer(),
opened: $q.defer(),
closed: $q.defer(),
rendered: $q.defer(),
close: function(result) {
return $uibModalStack.close(modal1Instance, result);
},
dismiss: function(reason) {
return $uibModalStack.dismiss(modal1Instance, reason);
}
};
var modal2Instance = {
result: $q.defer(),
opened: $q.defer(),
closed: $q.defer(),
rendered: $q.defer(),
close: function(result) {
return $uibModalStack.close(modal2Instance, result);
},
dismiss: function(reason) {
return $uibModalStack.dismiss(modal2Instance, reason);
}
};
var modal3Instance = {
result: $q.defer(),
opened: $q.defer(),
closed: $q.defer(),
rendered: $q.defer(),
close: function(result) {
return $uibModalStack.close(modal13nstance, result);
},
dismiss: function(reason) {
return $uibModalStack.dismiss(modal3Instance, reason);
}
};

var modal1 = $uibModalStack.open(modal1Instance, {
appendTo: angular.element(document.body),
scope: $rootScope.$new(),
deferred: modal1Instance.result,
renderDeferred: modal1Instance.rendered,
closedDeferred: modal1Instance.closed,
content: '<div>Modal1</div>'
});

expect($document).toHaveModalsOpen(0);
$rootScope.$digest();
$animate.flush();
expect($document).toHaveModalsOpen(1);

expect(parseInt($uibModalStack.getTop().value.modalDomEl.attr('index'), 10)).toEqual(0);

var modal2 = $uibModalStack.open(modal2Instance, {
appendTo: angular.element(document.body),
scope: $rootScope.$new(),
deferred: modal2Instance.result,
renderDeferred: modal2Instance.rendered,
closedDeferred: modal2Instance.closed,
content: '<div>Modal2</div>'
});

modal2Instance.rendered.promise.then(function() {
modal2Index = parseInt($uibModalStack.getTop().value.modalDomEl.attr('index'), 10);
});

expect($document).toHaveModalsOpen(1);
$rootScope.$digest();
$animate.flush();
expect($document).toHaveModalsOpen(2);

expect(modal2Index).toEqual(1);
close(modal1Instance);
expect($document).toHaveModalsOpen(1);

var modal3 = $uibModalStack.open(modal3Instance, {
appendTo: angular.element(document.body),
scope: $rootScope.$new(),
deferred: modal3Instance.result,
renderDeferred: modal3Instance.rendered,
closedDeferred: modal3Instance.closed,
content: '<div>Modal3</div>'
});

modal3Instance.rendered.promise.then(function() {
modal3Index = parseInt($uibModalStack.getTop().value.modalDomEl.attr('index'), 10);
});

expect($document).toHaveModalsOpen(1);
$rootScope.$digest();
$animate.flush();
expect($document).toHaveModalsOpen(2);

expect(modal3Index).toEqual(2);
expect(modal2Index).toBeLessThan(modal3Index);
});
});

describe('modal.closing event', function() {
Expand Down

0 comments on commit a08ad70

Please sign in to comment.