Skip to content
This repository has been archived by the owner on Sep 7, 2020. It is now read-only.

Commit

Permalink
Closes #57, #157.
Browse files Browse the repository at this point in the history
  • Loading branch information
Douglas Ludlow committed Oct 2, 2017
1 parent eab850d commit 9665f06
Show file tree
Hide file tree
Showing 13 changed files with 308 additions and 169 deletions.
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,21 @@ Feel free to request more.

#### Outputs

- `onShow: EventEmitter<Event>`

Emits when the `show.bs.modal` event is triggered, just before the modal is shown. Call `Event.preventDefault()` to cancel the modal from showing.

- `onHide: EventEmitter<BsModalHideEvent>`

Emits when the `hide.bs.modal` event is triggered, just before the modal is hidden. Call `BsModalHideEvent.event.preventDefault()` to cancel the modal from hiding.

- `onClose: EventEmitter<any>`

Emits when `ModalComponent.close()` is called. Will emit whatever was passed into `ModalComponent.close()`.

- `onDismiss: EventEmitter<BsModalCloseSource>`
- `onDismiss: EventEmitter<BsModalHideType>`

Emits when `ModalComponent.dismiss()` is called, or when the modal is dismissed with the keyboard or backdrop. Returns a `BsModalCloseSource` that can be used to determine how the modal was dismissed.
Emits when `ModalComponent.dismiss()` is called, or when the modal is dismissed with the keyboard or backdrop. Returns a `BsModalHideType` that can be used to determine how the modal was dismissed.

- `onOpen: EventEmitter`

Expand Down Expand Up @@ -157,7 +165,7 @@ Feel free to request more.

- `dismissAll(): void`

Dismiss all open modals.
Dismiss all open modals. Inject the `BsModalService` into a componet/service to use.

## Example Usage

Expand Down
95 changes: 86 additions & 9 deletions src/demo/app/modal-demo.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ <h2>Common Usage</h2>
<button type="button" class="btn btn-default" (click)="modal.open()">Open me!</button>
<button type="button" class="btn btn-default" (click)="modal.open('lg')">Large modal</button>
<button type="button" class="btn btn-default" (click)="modal.open('sm')">Small modal</button>
<button type="button" class="btn btn-default" (click)="noEventsModal.open()">No Events</button>
</p>
<br />

Expand All @@ -31,11 +32,20 @@ <h2>Other Usages</h2>
</p>
<br />

<h2>Intercepting events</h2>
<hr>
<p>
<button type="button" class="btn btn-default" (click)="interceptDismissModal.open()">Intercept hide</button>
<button type="button" class="btn btn-default" (click)="interceptOpenModal.open()">Intercept show</button>
| <button type="button" class="btn btn-default" (click)="intercept = !intercept">Toggle intercept ({{intercept}})</button>
</p>
<br />

<h2>Output</h2>
<pre>{{ output }}</pre>

<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()" (onDismiss)="dismissed()"
(onOpen)="opened()" [cssClass]="cssClass" #modal >
<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()" (onDismiss)="dismissed($event)"
(onOpen)="opened()" [cssClass]="cssClass" #modal>
<bs-modal-header [showDismiss]="true">
<h4 class="modal-title">I'm a modal!</h4>
</bs-modal-header>
Expand All @@ -45,12 +55,31 @@ <h4 class="modal-title">I'm a modal!</h4>
<a href="#" (click)="$event.preventDefault(); selected = item">{{ item }}</a>
</li>
</ul>
<p *ngIf="selected">Selected: <b>{{ selected }}</b></p>
<p *ngIf="selected">Selected:
<b>{{ selected }}</b>
</p>
</bs-modal-body>
<bs-modal-footer [showDefaultButtons]="true"></bs-modal-footer>
</bs-modal>

<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="navigate()" (onDismiss)="dismissed()"
<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" [cssClass]="cssClass" #noEventsModal>
<bs-modal-header [showDismiss]="true">
<h4 class="modal-title">I'm a modal!</h4>
</bs-modal-header>
<bs-modal-body>
<ul>
<li *ngFor="let item of items">
<a href="#" (click)="$event.preventDefault(); selected = item">{{ item }}</a>
</li>
</ul>
<p *ngIf="selected">Selected:
<b>{{ selected }}</b>
</p>
</bs-modal-body>
<bs-modal-footer [showDefaultButtons]="true"></bs-modal-footer>
</bs-modal>

<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="navigate()" (onDismiss)="dismissed($event)"
(onOpen)="opened()" [cssClass]="cssClass" #navigateModal>
<bs-modal-header [showDismiss]="true">
<h4 class="modal-title">I'm a modal!</h4>
Expand All @@ -64,13 +93,16 @@ <h4 class="modal-title">I'm a modal!</h4>
</bs-modal-footer>
</bs-modal>

<bs-modal style="z-index: 1049" [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()" (onDismiss)="dismissed()"
(onOpen)="opened()" [cssClass]="cssClass" #parentModal>
<bs-modal style="z-index: 1049" [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()"
(onDismiss)="dismissed($event)" (onOpen)="opened()" [cssClass]="cssClass" #parentModal>
<bs-modal-header [showDismiss]="true">
<h4 class="modal-title">I'm a modal!</h4>
</bs-modal-header>
<bs-modal-body>
<p><strong>Note:</strong> My <code>z-index</code> is set to <code>1049</code>.</p>
<p>
<strong>Note:</strong> My
<code>z-index</code> is set to
<code>1049</code>.</p>
<button type="button" class="btn btn-default" (click)="stackedModel.open()">Open another modal</button>
</bs-modal-body>
<bs-modal-footer>
Expand All @@ -79,7 +111,7 @@ <h4 class="modal-title">I'm a modal!</h4>
</bs-modal-footer>
</bs-modal>

<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()" (onDismiss)="dismissed()"
<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()" (onDismiss)="dismissed($event)"
(onOpen)="opened()" [cssClass]="cssClass" #stackedModel>
<bs-modal-header [showDismiss]="true">
<h4 class="modal-title">I'm a stacked modal!</h4>
Expand All @@ -90,7 +122,7 @@ <h4 class="modal-title">I'm a stacked modal!</h4>
<bs-modal-footer [showDefaultButtons]="true"></bs-modal-footer>
</bs-modal>

<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()" (onDismiss)="dismissed()"
<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()" (onDismiss)="dismissed($event)"
(onOpen)="opened()" [cssClass]="cssClass" #validationModal>
<form #modalForm="ngForm">
<bs-modal-header [showDismiss]="true">
Expand All @@ -112,4 +144,49 @@ <h4 class="modal-title">I'm a modal!</h4>
</bs-modal-footer>
</form>
</bs-modal>

<bs-modal [animation]="animation" [keyboard]="false" [backdrop]="'static'" (onClose)="closed()" (onDismiss)="dismissed($event)"
(onOpen)="opened()" [cssClass]="cssClass" (onHide)="interceptDismiss($event)" #interceptDismissModal>
<bs-modal-header [showDismiss]="true">
<h4 class="modal-title">Can't dismiss if <code>intercept</code> is enabled</h4>
</bs-modal-header>
<bs-modal-body>
<p>
Note: Keyboard and backdrop events cannot be prevented with
<code>event.preventDefault()</code>. Use the
<code>keyboard</code> and
<code>backdrop</code> options.
</p>
<ul>
<li *ngFor="let item of items">
<a href="#" (click)="$event.preventDefault(); selected = item">{{ item }}</a>
</li>
</ul>
<p *ngIf="selected">Selected:
<b>{{ selected }}</b>
</p>
<button type="button" class="btn btn-default" (click)="intercept = !intercept" >Toggle intercept ({{intercept}})</button>
</bs-modal-body>
<bs-modal-footer [showDefaultButtons]="true"></bs-modal-footer>
</bs-modal>

<bs-modal [animation]="animation" [keyboard]="keyboard" [backdrop]="backdrop" (onClose)="closed()" (onDismiss)="dismissed($event)"
(onOpen)="opened()" (onShow)="interceptOpen($event)" [cssClass]="cssClass" #interceptOpenModal>
<bs-modal-header [showDismiss]="true">
<h4 class="modal-title">I'm a modal!</h4>
</bs-modal-header>
<bs-modal-body>
<ul>
<li *ngFor="let item of items">
<a href="#" (click)="$event.preventDefault(); selected = item">{{ item }}</a>
</li>
</ul>
<p *ngIf="selected">Selected:
<b>{{ selected }}</b>
</p>
</bs-modal-body>
<bs-modal-footer [showDefaultButtons]="true"></bs-modal-footer>
</bs-modal>


</section>
23 changes: 19 additions & 4 deletions src/demo/app/modal-demo.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Component, ViewChild, ViewEncapsulation} from '@angular/core';
import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { Router } from '@angular/router';
import { BsModalComponent, BsModalService } from '../../ng2-bs3-modal/ng2-bs3-modal';
import { BsModalComponent, BsModalService, BsModalHideType } from '../../ng2-bs3-modal/ng2-bs3-modal';

@Component({
moduleId: module.id,
Expand Down Expand Up @@ -36,15 +36,16 @@ export class ModalDemoComponent {
keyboard = true;
backdrop: string | boolean = true;
css = false;
intercept = true;

constructor(private router: Router, private modalservice: BsModalService) { }

closed() {
this.output = '(closed) ' + this.selected;
}

dismissed() {
this.output = '(dismissed)';
dismissed(type) {
this.output = `(dismissed) ${BsModalHideType[type]}`;
}

opened() {
Expand All @@ -62,6 +63,20 @@ export class ModalDemoComponent {
dismissAll() {
this.modalservice.dismissAll();
}

interceptDismiss(e) {
if (this.intercept && e.type === BsModalHideType.Dismiss) {
e.event.preventDefault();
this.output = '(intercepted) Dismiss';
}
}

interceptOpen(e) {
if (this.intercept) {
e.preventDefault();
this.output = '(intercepted) Open';
}
}
}

export class Person {
Expand Down
42 changes: 26 additions & 16 deletions src/ng2-bs3-modal/modal/modal-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,46 @@ import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/filter';

import { BsModalComponent } from './modal';
import { BsModalCloseSource } from './models';
import { BsModalHideType } from './models';
import { JQueryStyleEventEmitter } from 'rxjs/observable/FromEventObservable';

const EVENT_SUFFIX = 'ng2-bs3-modal';
const KEYUP_EVENT_NAME = `keyup.${EVENT_SUFFIX}`;
const CLICK_EVENT_NAME = `click.${EVENT_SUFFIX}`;
const SHOW_EVENT_NAME = `show.bs.modal.${EVENT_SUFFIX}`;

@Injectable()
export class BsModalService {

private modals: BsModalComponent[] = [];
private $body: JQuery;

public onBackdropClose: Observable<BsModalCloseSource>;
public onKeyboardClose: Observable<BsModalCloseSource>;
public onBackdropClose$: Observable<BsModalHideType>;
public onKeyboardClose$: Observable<BsModalHideType>;
public onModalStack$: Observable<Event>;

constructor() {
this.onBackdropClose = Observable.fromEvent(jQuery(document) as JQueryStyleEventEmitter, CLICK_EVENT_NAME)
.filter((e: MouseEvent) => e.target === jQuery('.modal')[0])
.map(() => BsModalCloseSource.Backdrop)
this.$body = jQuery(document.body);

this.onBackdropClose$ = Observable.fromEvent(this.$body as JQueryStyleEventEmitter, CLICK_EVENT_NAME)
.filter((e: MouseEvent) => jQuery(e.target).is('.modal'))
.map(() => BsModalHideType.Backdrop)
.share();

this.onKeyboardClose = Observable.fromEvent(jQuery(document) as JQueryStyleEventEmitter, KEYUP_EVENT_NAME)
this.onKeyboardClose$ = Observable.fromEvent(this.$body as JQueryStyleEventEmitter, KEYUP_EVENT_NAME)
.filter((e: KeyboardEvent) => e.which === 27)
.map(() => BsModalCloseSource.Keyboard)
.map(() => BsModalHideType.Keyboard)
.share();

jQuery(document).on('show.bs.modal', '.modal', function () {
const zIndex = 1040 + (10 * $('.modal:visible').length);
$(this).css('z-index', zIndex);
setTimeout(function() {
$('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');
}, 0);
});
this.onModalStack$ = Observable.fromEvent<Event>(this.$body as JQueryStyleEventEmitter, SHOW_EVENT_NAME)
.do(() => {
const zIndex = 1040 + (10 * $('.modal:visible').length);
$(this).css('z-index', zIndex);
setTimeout(function() {
$('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');
}, 0);
})
.share();
}

public add(modal: BsModalComponent) {
Expand All @@ -50,7 +57,10 @@ export class BsModalService {

public focusNext() {
const visible = this.modals.filter(m => m.visible);
if (visible.length) visible[visible.length - 1].focus();
if (visible.length) {
this.$body.addClass('modal-open');
visible[visible.length - 1].focus();
}
}

public dismissAll() {
Expand Down
Loading

0 comments on commit 9665f06

Please sign in to comment.