Skip to content

Commit

Permalink
fix(modal): stricter interpretation of backdrop clicks
Browse files Browse the repository at this point in the history
Fixes #1040
Fixes #1042

Closes #1067
  • Loading branch information
pkozlowski-opensource committed Nov 21, 2016
1 parent 13f65e7 commit 3af8329
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/modal/modal-window.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe('ngb-modal-dialog', () => {
done();
});

fixture.nativeElement.querySelector('.modal-dialog').click();
fixture.nativeElement.click();
});

it('should not dismiss on modal content click when there is active backdrop', (done) => {
Expand Down
9 changes: 3 additions & 6 deletions src/modal/modal-window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import {
Renderer,
OnInit,
AfterViewInit,
OnDestroy,
ViewChild,
OnDestroy
} from '@angular/core';

import {ModalDismissReasons} from './modal-dismiss-reasons';
Expand All @@ -25,16 +24,14 @@ import {ModalDismissReasons} from './modal-dismiss-reasons';
},
template: `
<div [class]="'modal-dialog' + (size ? ' modal-' + size : '')" role="document">
<div class="modal-content" #modalContent><ng-content></ng-content></div>
<div class="modal-content"><ng-content></ng-content></div>
</div>
`
})
export class NgbModalWindow implements OnInit,
AfterViewInit, OnDestroy {
private _elWithFocus: Element; // element that is focused prior to modal opening

@ViewChild('modalContent') contentEl: ElementRef;

@Input() backdrop: boolean | string = true;
@Input() keyboard = true;
@Input() size: string;
Expand All @@ -45,7 +42,7 @@ export class NgbModalWindow implements OnInit,
constructor(private _elRef: ElementRef, private _renderer: Renderer) {}

backdropClick($event): void {
if (this.backdrop === true && !this.contentEl.nativeElement.contains($event.target)) {
if (this.backdrop === true && this._elRef.nativeElement === $event.target) {
this.dismiss(ModalDismissReasons.BACKDROP_CLICK);
}
}
Expand Down
23 changes: 21 additions & 2 deletions src/modal/modal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Component, Injectable, ViewChild, OnDestroy, NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {TestBed, ComponentFixture} from '@angular/core/testing';
import {By} from '@angular/platform-browser';

Expand Down Expand Up @@ -307,6 +308,16 @@ describe('ngb-modal', () => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveModal();
});

it('should not dismiss on clicks that result in detached elements', () => {
fixture.componentInstance.openTplIf({});
fixture.detectChanges();
expect(fixture.nativeElement).toHaveModal();

(<HTMLElement>fixture.nativeElement.querySelector('button#if')).click();
fixture.detectChanges();
expect(fixture.nativeElement).toHaveModal();
});
});

describe('keyboard options', () => {
Expand Down Expand Up @@ -432,16 +443,23 @@ export class WithActiveModalCmpt {
<template #destroyableContent><destroyable-cmpt></destroyable-cmpt></template>
<template #contentWithClose let-close="close"><button id="close" (click)="close('myResult')">Close me</button></template>
<template #contentWithDismiss let-dismiss="dismiss"><button id="dismiss" (click)="dismiss('myReason')">Dismiss me</button></template>
<template #contentWithIf>
<template [ngIf]="show">
<button id="if" (click)="show = false">Click me</button>
</template>
</template>
<button id="open" (click)="open('from button')">Open</button>
`
})
class TestComponent {
name = 'World';
openedModal: NgbModalRef;
show = true;
@ViewChild('content') tplContent;
@ViewChild('destroyableContent') tplDestroyableContent;
@ViewChild('contentWithClose') tplContentWithClose;
@ViewChild('contentWithDismiss') tplContentWithDismiss;
openedModal: NgbModalRef;
@ViewChild('contentWithIf') tplContentWithIf;

constructor(private modalService: NgbModal) {}

Expand All @@ -459,12 +477,13 @@ class TestComponent {
openDestroyableTpl(options?: Object) { return this.modalService.open(this.tplDestroyableContent, options); }
openTplClose(options?: Object) { return this.modalService.open(this.tplContentWithClose, options); }
openTplDismiss(options?: Object) { return this.modalService.open(this.tplContentWithDismiss, options); }
openTplIf(options?: Object) { return this.modalService.open(this.tplContentWithIf, options); }
}

@NgModule({
declarations: [TestComponent, DestroyableCmpt, WithActiveModalCmpt],
exports: [TestComponent, DestroyableCmpt],
imports: [NgbModalModule.forRoot()],
imports: [CommonModule, NgbModalModule.forRoot()],
entryComponents: [DestroyableCmpt, WithActiveModalCmpt],
providers: [SpyService]
})
Expand Down

0 comments on commit 3af8329

Please sign in to comment.