diff --git a/src/modal/docs/readme.md b/src/modal/docs/readme.md index 9c444f9201..fc3b085bbf 100644 --- a/src/modal/docs/readme.md +++ b/src/modal/docs/readme.md @@ -15,6 +15,7 @@ The `$modal` service has only one method: `open(options)` where available option * `keyboard` - indicates whether the dialog should be closable by hitting the ESC key, defaults to true * `backdropClass` - additional CSS class(es) to be added to a modal backdrop template * `windowClass` - additional CSS class(es) to be added to a modal window template +* `windowTopClass` - CSS class(es) to be added to the top modal window * `windowTemplateUrl` - a path to a template overriding modal's window template * `size` - optional suffix of modal window class. The value used is appended to the `modal-` class, i.e. a value of `sm` gives `modal-sm` * `openedClass` - class added to the `body` element when the modal is opened. Defaults to `modal-open` diff --git a/src/modal/modal.js b/src/modal/modal.js index a1359b81c4..bd284c0a02 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -176,6 +176,7 @@ angular.module('ui.bootstrap.modal', []) }, link: function(scope, element, attrs) { element.addClass(attrs.windowClass || ''); + element.addClass(attrs.windowTopClass || ''); scope.size = attrs.size; scope.close = function(evt) { @@ -340,6 +341,7 @@ angular.module('ui.bootstrap.modal', []) var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS; openedClasses.remove(modalBodyClass, modalInstance); body.toggleClass(modalBodyClass, openedClasses.hasKey(modalBodyClass)); + toggleTopWindowClass(true); }); checkRemoveBackdrop(); @@ -351,6 +353,16 @@ angular.module('ui.bootstrap.modal', []) } } + // Add or remove "windowTopClass" from the top window in the stack + function toggleTopWindowClass(toggleSwitch) { + var modalWindow; + + if (openedWindows.length() > 0) { + modalWindow = openedWindows.top().value; + modalWindow.modalDomEl.toggleClass(modalWindow.windowTopClass || '', toggleSwitch); + } + } + function checkRemoveBackdrop() { //remove backdrop if no longer needed if (backdropDomEl && backdropIndex() == -1) { @@ -447,13 +459,16 @@ angular.module('ui.bootstrap.modal', []) var modalOpener = $document[0].activeElement, modalBodyClass = modal.openedClass || OPENED_MODAL_CLASS; + toggleTopWindowClass(false); + openedWindows.add(modalInstance, { deferred: modal.deferred, renderDeferred: modal.renderDeferred, modalScope: modal.scope, backdrop: modal.backdrop, keyboard: modal.keyboard, - openedClass: modal.openedClass + openedClass: modal.openedClass, + windowTopClass: modal.windowTopClass }); openedClasses.put(modalBodyClass, modalInstance); @@ -477,6 +492,7 @@ angular.module('ui.bootstrap.modal', []) angularDomEl.attr({ 'template-url': modal.windowTemplateUrl, 'window-class': modal.windowClass, + 'window-top-class': modal.windowTopClass, 'size': modal.size, 'index': openedWindows.length() - 1, 'animate': 'animate' @@ -701,6 +717,7 @@ angular.module('ui.bootstrap.modal', []) backdrop: modalOptions.backdrop, keyboard: modalOptions.keyboard, backdropClass: modalOptions.backdropClass, + windowTopClass: modalOptions.windowTopClass, windowClass: modalOptions.windowClass, windowTemplateUrl: modalOptions.windowTemplateUrl, size: modalOptions.size, diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index 647fc748ab..38afd1c4e4 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -773,6 +773,17 @@ describe('$modal', function () { }); }); + describe('top window class', function () { + it('should support top class option', function () { + open({ + template: '
With custom window top class
', + windowTopClass: 'top-class' + }); + + expect($document.find('div.modal')).toHaveClass('top-class'); + }); + }); + describe('size', function() { it('should support creating small modal dialogs', function() { open({ @@ -805,7 +816,7 @@ describe('$modal', function () { describe('animation', function() { it('should have animation fade classes by default', function() { open({ - template: '
Small modal dialog
', + template: '
Small modal dialog
' }); expect($document.find('.modal')).toHaveClass('fade'); @@ -1079,6 +1090,32 @@ describe('$modal', function () { permute(3, function(a) { test(a.map(function(x, i) { return i === 0 ? {reject:x} : x; })); }); permute(3, function(a) { test(a.map(function(x, i) { return i === 1 ? {reject:x} : x; })); }); }); + + it('should have top class only on top window', function () { + var modal1 = open({template: '
Content1
', windowClass: 'modal1', windowTopClass: 'modal-top'}); + expect($document.find('div.modal1')).toHaveClass('modal-top'); + expect($document).toHaveModalsOpen(1); + + var modal2 = open({template: '
Content1
', windowClass: 'modal2', windowTopClass: 'modal-top'}); + expect($document.find('div.modal1')).not.toHaveClass('modal-top'); + expect($document.find('div.modal2')).toHaveClass('modal-top'); + expect($document).toHaveModalsOpen(2); + + var modal3 = open({template: '
Content1
', windowClass: 'modal3', windowTopClass: 'modal-top'}); + expect($document.find('div.modal1')).not.toHaveClass('modal-top'); + expect($document.find('div.modal2')).not.toHaveClass('modal-top'); + expect($document.find('div.modal3')).toHaveClass('modal-top'); + expect($document).toHaveModalsOpen(3); + + dismiss(modal2); + expect($document.find('div.modal1')).not.toHaveClass('modal-top'); + expect($document.find('div.modal3')).toHaveClass('modal-top'); + expect($document).toHaveModalsOpen(2); + + close(modal3); + expect($document.find('div.modal1')).toHaveClass('modal-top'); + expect($document).toHaveModalsOpen(1); + }); }); describe('modal.closing event', function() { diff --git a/src/modal/test/modalWindow.spec.js b/src/modal/test/modalWindow.spec.js index 312d607645..da5303f08c 100644 --- a/src/modal/test/modalWindow.spec.js +++ b/src/modal/test/modalWindow.spec.js @@ -25,6 +25,15 @@ describe('modal window', function() { expect(windowEl).toHaveClass('foo'); }); + it('should support window top class', function () { + $rootScope.animate = false; + var windowEl = $compile('
content
')($rootScope); + $rootScope.$digest(); + + expect(windowEl).toHaveClass('test'); + expect(windowEl).toHaveClass('foo'); + }); + it('should support custom template url', inject(function($templateCache) { $templateCache.put('window.html', '
');