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

Commit

Permalink
feat(modal): Added ability to add CSS class to top window
Browse files Browse the repository at this point in the history
- Added ability to add a class to the most recently opened modal window.
  Note that even if different classes are specified, the class will
only be present if the modal is the most recently opened modal, i.e. if
modal1 was opened with a top class of `foo`, and modal2 is opened
afterwards with a top class of `bar`, modal2 will have the class `bar`
for the modal window, and modal1 will not have the class `foo`.

Closes #2524
  • Loading branch information
Pavel R3VoLuT1OneR Zhytomirsky authored and wesleycho committed Sep 10, 2015
1 parent 0328a76 commit bd38e8f
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/modal/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
19 changes: 18 additions & 1 deletion src/modal/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();

Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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'
Expand Down Expand Up @@ -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,
Expand Down
39 changes: 38 additions & 1 deletion src/modal/test/modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,17 @@ describe('$modal', function () {
});
});

describe('top window class', function () {
it('should support top class option', function () {
open({
template: '<div>With custom window top class</div>',
windowTopClass: 'top-class'
});

expect($document.find('div.modal')).toHaveClass('top-class');
});
});

describe('size', function() {
it('should support creating small modal dialogs', function() {
open({
Expand Down Expand Up @@ -805,7 +816,7 @@ describe('$modal', function () {
describe('animation', function() {
it('should have animation fade classes by default', function() {
open({
template: '<div>Small modal dialog</div>',
template: '<div>Small modal dialog</div>'
});

expect($document.find('.modal')).toHaveClass('fade');
Expand Down Expand Up @@ -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: '<div>Content1</div>', windowClass: 'modal1', windowTopClass: 'modal-top'});
expect($document.find('div.modal1')).toHaveClass('modal-top');
expect($document).toHaveModalsOpen(1);

var modal2 = open({template: '<div>Content1</div>', 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: '<div>Content1</div>', 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() {
Expand Down
9 changes: 9 additions & 0 deletions src/modal/test/modalWindow.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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('<div modal-window animate="animate" window-top-class="test foo">content</div>')($rootScope);
$rootScope.$digest();

expect(windowEl).toHaveClass('test');
expect(windowEl).toHaveClass('foo');
});

it('should support custom template url', inject(function($templateCache) {
$templateCache.put('window.html', '<div class="mywindow" ng-transclude></div>');

Expand Down

0 comments on commit bd38e8f

Please sign in to comment.