From 96fb17c006a9352094ec9db776ea44ce0bce11b1 Mon Sep 17 00:00:00 2001 From: jmwolfe Date: Mon, 2 Sep 2013 14:55:43 -0400 Subject: [PATCH 1/2] Added z-index setting on modal and backdrops To support multiple modals with different sizes, added code in directives to set the z-index of each div based on the modal stack depth. Starts initial backdrop at 1040 (bootstrap's 'modal' class value) and the modal itself at 1050. Subsequent modals are offset by 20 with each additional modal. --- src/modal/modal.js | 9 +++++++- src/modal/test/modal.spec.js | 36 +++++++++++++++++++++++++++++-- src/modal/test/stackedMap.spec.js | 7 ++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/modal/modal.js b/src/modal/modal.js index e43d5319fb..9eb69cb15e 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -11,6 +11,7 @@ angular.module('ui.bootstrap.modal', []) return { add: function (key, value) { + value.stackIndex = stack.length; stack.push({ key: key, value: value @@ -61,6 +62,9 @@ angular.module('ui.bootstrap.modal', []) //trigger CSS transitions $timeout(function () { scope.animate = true; + var modal = $modalStack.getTop(); + var styleData = 'z-index: ' + (1040 + 20*modal.window.stackIndex) + ';'; + element[0].setAttribute('style', styleData); }); scope.close = function (evt) { @@ -76,7 +80,7 @@ angular.module('ui.bootstrap.modal', []) }; }]) - .directive('modalWindow', ['$timeout', function ($timeout) { + .directive('modalWindow', ['$timeout', '$modalStack',function ($timeout,$modalStack) { return { restrict: 'EA', scope: {}, @@ -86,6 +90,9 @@ angular.module('ui.bootstrap.modal', []) link: function (scope, element, attrs) { //trigger CSS transitions $timeout(function () { + var modal = $modalStack.getTop(); + var styleData = 'z-index: ' + (1050 + 20 * modal.window.stackIndex) + ';'; + element[0].setAttribute('style', styleData); scope.animate = true; }); } diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index 0182a68058..35f8250ffd 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -80,7 +80,27 @@ describe('$modal', function () { }; return backdropDomEls.length === 1; + }, + + toHaveOneDivWithCertainClassAndZindexInStyleAttr: function(divclass, expectedZindex) { + + var domEls = this.actual.find('body > div.'+divclass); + this.message = function() { + return "Expected '" + angular.mock.dump(domEls) + "' to be a div element with class '"+divclass+"' and style containing z-index: "+expectedZindex+"."; + }; + var divsAtLevel = 0; + for(var i=0; i < domEls.length; i++) + { + var domEl = domEls[i]; + var style = domEl.getAttribute('style'); + if (style.indexOf('z-index: ' + expectedZindex) != -1) { + divsAtLevel++; + } + } + + return divsAtLevel === 1; } + }); })); @@ -364,7 +384,7 @@ describe('$modal', function () { describe('multiple modals', function () { - it('it should allow opening of multiple modals', function () { + it('should allow opening of multiple modals', function () { var modal1 = open({template: '
Modal1
'}); var modal2 = open({template: '
Modal2
'}); @@ -377,7 +397,19 @@ describe('$modal', function () { dismiss(modal1); expect($document).toHaveModalsOpen(0); }); - + + it('should occlude any open child modals', function() { + var modal1 = open({template: '
Modal1
'}); + $timeout.flush(); // to call the directives in their natural order + var modal2 = open({template: '
Modal2
'}); + $timeout.flush(); + + expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal-backdrop','1040'); + expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal','1050'); + expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal-backdrop','1060'); + expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal','1070'); + }); + it('should not close any modals on ESC if the topmost one does not allow it', function () { var modal1 = open({template: '
Modal1
'}); diff --git a/src/modal/test/stackedMap.spec.js b/src/modal/test/stackedMap.spec.js index d1a9d68cfe..63a77470e6 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 add the stackIndex to the value object', function() { + stackedMap.add('foo', { name: 'foo_value'}); + stackedMap.add('bar', { name: 'bar_value'}); + expect(stackedMap.get('foo').value.stackIndex).toEqual(0); + expect(stackedMap.get('bar').value.stackIndex).toEqual(1); + }); + it('should get topmost element', function () { stackedMap.add('foo', 'foo_value'); From 2ff5820f17a40051a32d20cc0915e759920adb43 Mon Sep 17 00:00:00 2001 From: jmwolfe Date: Mon, 2 Sep 2013 20:14:28 -0400 Subject: [PATCH 2/2] Fixed errant tabs to spaces for jslint --- src/modal/modal.js | 14 ++++++------ src/modal/test/modal.spec.js | 44 ++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/modal/modal.js b/src/modal/modal.js index 9eb69cb15e..c2ba0ad4dc 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -11,7 +11,7 @@ angular.module('ui.bootstrap.modal', []) return { add: function (key, value) { - value.stackIndex = stack.length; + value.stackIndex = stack.length; stack.push({ key: key, value: value @@ -62,9 +62,9 @@ angular.module('ui.bootstrap.modal', []) //trigger CSS transitions $timeout(function () { scope.animate = true; - var modal = $modalStack.getTop(); - var styleData = 'z-index: ' + (1040 + 20*modal.window.stackIndex) + ';'; - element[0].setAttribute('style', styleData); + var modal = $modalStack.getTop(); + var styleData = 'z-index: ' + (1040 + 20*modal.window.stackIndex) + ';'; + element[0].setAttribute('style', styleData); }); scope.close = function (evt) { @@ -90,9 +90,9 @@ angular.module('ui.bootstrap.modal', []) link: function (scope, element, attrs) { //trigger CSS transitions $timeout(function () { - var modal = $modalStack.getTop(); - var styleData = 'z-index: ' + (1050 + 20 * modal.window.stackIndex) + ';'; - element[0].setAttribute('style', styleData); + var modal = $modalStack.getTop(); + var styleData = 'z-index: ' + (1050 + 20 * modal.window.stackIndex) + ';'; + element[0].setAttribute('style', styleData); scope.animate = true; }); } diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index 35f8250ffd..a1fe6dde6a 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -81,22 +81,22 @@ describe('$modal', function () { return backdropDomEls.length === 1; }, - + toHaveOneDivWithCertainClassAndZindexInStyleAttr: function(divclass, expectedZindex) { var domEls = this.actual.find('body > div.'+divclass); this.message = function() { return "Expected '" + angular.mock.dump(domEls) + "' to be a div element with class '"+divclass+"' and style containing z-index: "+expectedZindex+"."; }; - var divsAtLevel = 0; - for(var i=0; i < domEls.length; i++) - { - var domEl = domEls[i]; - var style = domEl.getAttribute('style'); - if (style.indexOf('z-index: ' + expectedZindex) != -1) { - divsAtLevel++; - } - } + var divsAtLevel = 0; + for(var i=0; i < domEls.length; i++) + { + var domEl = domEls[i]; + var style = domEl.getAttribute('style'); + if (style.indexOf('z-index: ' + expectedZindex) != -1) { + divsAtLevel++; + } + } return divsAtLevel === 1; } @@ -397,19 +397,19 @@ describe('$modal', function () { dismiss(modal1); expect($document).toHaveModalsOpen(0); }); - - it('should occlude any open child modals', function() { + + it('should occlude any open child modals', function() { var modal1 = open({template: '
Modal1
'}); - $timeout.flush(); // to call the directives in their natural order - var modal2 = open({template: '
Modal2
'}); - $timeout.flush(); - - expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal-backdrop','1040'); - expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal','1050'); - expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal-backdrop','1060'); - expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal','1070'); - }); - + $timeout.flush(); // to call the directives in their natural order + var modal2 = open({template: '
Modal2
'}); + $timeout.flush(); + + expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal-backdrop','1040'); + expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal','1050'); + expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal-backdrop','1060'); + expect($document).toHaveOneDivWithCertainClassAndZindexInStyleAttr('modal','1070'); + }); + it('should not close any modals on ESC if the topmost one does not allow it', function () { var modal1 = open({template: '
Modal1
'});