From 7fce2fe82f49ab8a11c488a7a19bddc5618a88e8 Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Sat, 7 Sep 2013 16:16:18 +0200 Subject: [PATCH] fix(modal): backdrop should cover previously opened modals Closes #922 Closes #931 --- src/modal/modal.js | 77 +++++++++++++++++++------------ src/modal/test/stackedMap.spec.js | 7 +++ template/modal/backdrop.html | 2 +- template/modal/window.html | 2 +- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/modal/modal.js b/src/modal/modal.js index 1426e89ec4..2b7752bb03 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -23,6 +23,13 @@ angular.module('ui.bootstrap.modal', []) } } }, + keys: function() { + var keys = []; + for (var i = 0; i < stack.length; i++) { + keys.push(stack[i].key); + } + return keys; + }, top: function () { return stack[stack.length - 1]; }, @@ -53,7 +60,6 @@ angular.module('ui.bootstrap.modal', []) .directive('modalBackdrop', ['$modalStack', '$timeout', function ($modalStack, $timeout) { return { restrict: 'EA', - scope: {}, replace: true, templateUrl: 'template/modal/backdrop.html', link: function (scope, element, attrs) { @@ -65,11 +71,10 @@ angular.module('ui.bootstrap.modal', []) scope.close = function (evt) { var modal = $modalStack.getTop(); - //TODO: this logic is duplicated with the place where modal gets opened - if (modal && modal.window.backdrop && modal.window.backdrop != 'static') { + if (modal && modal.value.backdrop && modal.value.backdrop != 'static') { evt.preventDefault(); evt.stopPropagation(); - $modalStack.dismiss(modal.instance, 'backdrop click'); + $modalStack.dismiss(modal.key, 'backdrop click'); } }; } @@ -79,7 +84,9 @@ angular.module('ui.bootstrap.modal', []) .directive('modalWindow', ['$timeout', function ($timeout) { return { restrict: 'EA', - scope: {}, + scope: { + index: '@' + }, replace: true, transclude: true, templateUrl: 'template/modal/window.html', @@ -97,10 +104,27 @@ angular.module('ui.bootstrap.modal', []) .factory('$modalStack', ['$document', '$compile', '$rootScope', '$$stackedMap', function ($document, $compile, $rootScope, $$stackedMap) { + var backdropjqLiteEl, backdropDomEl; + var backdropScope = $rootScope.$new(true); var body = $document.find('body').eq(0); var openedWindows = $$stackedMap.createNew(); var $modalStack = {}; + function backdropIndex() { + var topBackdropIndex = -1; + var opened = openedWindows.keys(); + for (var i = 0; i < opened.length; i++) { + if (openedWindows.get(opened[i]).value.backdrop) { + topBackdropIndex = i; + } + } + return topBackdropIndex; + } + + $rootScope.$watch(backdropIndex, function(newBackdropIndex){ + backdropScope.index = newBackdropIndex; + }); + function removeModalWindow(modalInstance) { var modalWindow = openedWindows.get(modalInstance).value; @@ -108,12 +132,13 @@ angular.module('ui.bootstrap.modal', []) //clean up the stack openedWindows.remove(modalInstance); - //remove DOM element + //remove window DOM element modalWindow.modalDomEl.remove(); - //remove backdrop - if (modalWindow.backdropDomEl) { - modalWindow.backdropDomEl.remove(); + //remove backdrop if no longer needed + if (backdropIndex() == -1) { + backdropDomEl.remove(); + backdropDomEl = undefined; } //destroy scope @@ -135,27 +160,27 @@ angular.module('ui.bootstrap.modal', []) $modalStack.open = function (modalInstance, modal) { - var backdropDomEl; - if (modal.backdrop) { - backdropDomEl = $compile(angular.element('
'))($rootScope); - body.append(backdropDomEl); - } + openedWindows.add(modalInstance, { + deferred: modal.deferred, + modalScope: modal.scope, + backdrop: modal.backdrop, + keyboard: modal.keyboard + }); var angularDomEl = angular.element('
'); angularDomEl.attr('window-class', modal.windowClass); + angularDomEl.attr('index', openedWindows.length() - 1); angularDomEl.html(modal.content); var modalDomEl = $compile(angularDomEl)(modal.scope); + openedWindows.top().value.modalDomEl = modalDomEl; body.append(modalDomEl); - openedWindows.add(modalInstance, { - deferred: modal.deferred, - modalScope: modal.scope, - modalDomEl: modalDomEl, - backdrop: modal.backdrop, - backdropDomEl: backdropDomEl, - keyboard: modal.keyboard - }); + if (backdropIndex() >= 0 && !backdropDomEl) { + backdropjqLiteEl = angular.element('
'); + backdropDomEl = $compile(backdropjqLiteEl)(backdropScope); + body.append(backdropDomEl); + } }; $modalStack.close = function (modalInstance, result) { @@ -175,13 +200,7 @@ angular.module('ui.bootstrap.modal', []) }; $modalStack.getTop = function () { - var top = openedWindows.top(); - if (top) { - return { - instance: top.key, - window: top.value - }; - } + return openedWindows.top(); }; return $modalStack; diff --git a/src/modal/test/stackedMap.spec.js b/src/modal/test/stackedMap.spec.js index d1a9d68cfe..47cd24bf1d 100644 --- a/src/modal/test/stackedMap.spec.js +++ b/src/modal/test/stackedMap.spec.js @@ -19,6 +19,13 @@ describe('stacked map', function () { expect(stackedMap.get('foo')).toBeUndefined(); }); + it('should support listing keys', function () { + stackedMap.add('foo', 'foo_value'); + stackedMap.add('bar', 'bar_value'); + + expect(stackedMap.keys()).toEqual(['foo', 'bar']); + }); + it('should get topmost element', function () { stackedMap.add('foo', 'foo_value'); diff --git a/template/modal/backdrop.html b/template/modal/backdrop.html index da5d62ad54..ebf8aa59a7 100644 --- a/template/modal/backdrop.html +++ b/template/modal/backdrop.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/template/modal/window.html b/template/modal/window.html index 787cd6afd7..3714dd61e6 100644 --- a/template/modal/window.html +++ b/template/modal/window.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file