From 071a7d493f6e133cf639324fcb174511de18648b Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Sun, 5 May 2019 11:32:30 +0800 Subject: [PATCH 1/2] fix(module:modal): should not close when mousedown in the body close #3394 --- components/modal/nz-modal.component.html | 2 + components/modal/nz-modal.component.ts | 18 +++++++- components/modal/nz-modal.spec.ts | 56 +++++++++++++++++++++++- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/components/modal/nz-modal.component.html b/components/modal/nz-modal.component.html index 552adb92d54..be423e10b5f 100644 --- a/components/modal/nz-modal.component.html +++ b/components/modal/nz-modal.component.html @@ -10,6 +10,7 @@ >
extends NzModalRef private focusTrap: FocusTrap; private scrollStrategy: BlockScrollStrategy; private overlayRef: OverlayRef; + private dialogMouseDown = false; + private timeoutId: number; [key: string]: any; // tslint:disable-line:no-any @@ -260,6 +262,7 @@ export class NzModalComponent extends NzModalRef this.unsubscribe$.next(); this.unsubscribe$.complete(); }); + clearTimeout(this.timeoutId); } setOverlayRef(overlayRef: OverlayRef): void { @@ -309,12 +312,25 @@ export class NzModalComponent extends NzModalRef return this.elementRef && this.elementRef.nativeElement; } + onMaskDialogDown(): void { + this.dialogMouseDown = true; + } + + onDialogUp(): void { + if (this.dialogMouseDown) { + this.timeoutId = setTimeout(() => { + this.dialogMouseDown = false; + }, 0); + } + } + onClickMask($event: MouseEvent): void { if ( this.mask && this.maskClosable && ($event.target as HTMLElement).classList.contains('ant-modal-wrap') && - this.nzVisible + this.nzVisible && + !this.dialogMouseDown ) { this.onClickOkCancel('cancel'); } diff --git a/components/modal/nz-modal.spec.ts b/components/modal/nz-modal.spec.ts index 2d9fb5563d4..324e16e0351 100644 --- a/components/modal/nz-modal.spec.ts +++ b/components/modal/nz-modal.spec.ts @@ -9,7 +9,7 @@ import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/t import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NzButtonComponent, NzButtonModule } from 'ng-zorro-antd/button'; -import { dispatchKeyboardEvent, NzMeasureScrollbarService } from 'ng-zorro-antd/core'; +import { dispatchFakeEvent, dispatchKeyboardEvent, NzMeasureScrollbarService } from 'ng-zorro-antd/core'; import { NzI18nService } from 'ng-zorro-antd/i18n'; import { NzIconTestModule } from 'ng-zorro-antd/icon/testing'; import en_US from '../i18n/languages/en_US'; @@ -441,7 +441,7 @@ describe('NzModal', () => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule, NzModalModule], providers: [NzMeasureScrollbarService], - declarations: [NzDemoModalBasicComponent, ModalByServiceComponent] + declarations: [NzDemoModalBasicComponent, NzDemoModalMaskComponent, ModalByServiceComponent] }); TestBed.compileComponents(); @@ -672,6 +672,44 @@ describe('NzModal', () => { document.body.removeChild(forceScrollElement); })); }); + + describe('close with mask', () => { + let fixture: ComponentFixture; + beforeEach(() => { + fixture = TestBed.createComponent(NzDemoModalMaskComponent); + }); + + it('should close when mask click', fakeAsync(() => { + fixture.componentInstance.isVisible = true; + fixture.detectChanges(); + tick(1000); + fixture.detectChanges(); + const nativeElement = fixture.debugElement.query(By.css('.ant-modal-wrap')).nativeElement; + fixture.detectChanges(); + nativeElement!.click(); + fixture.detectChanges(); + tick(1000); + fixture.detectChanges(); + expectModalHidden(fixture.debugElement.query(By.css('nz-modal')).nativeElement, true); + })); + + it('should not close if mouse down in dialog', fakeAsync(() => { + fixture.componentInstance.isVisible = true; + fixture.detectChanges(); + tick(1000); + fixture.detectChanges(); + const bodyNativeElement = fixture.debugElement.query(By.css('.ant-modal-body')).nativeElement; + dispatchFakeEvent(bodyNativeElement, 'mousedown'); + fixture.detectChanges(); + const warpNativeElement = fixture.debugElement.query(By.css('.ant-modal-wrap')).nativeElement; + dispatchFakeEvent(warpNativeElement, 'mouseup'); + dispatchFakeEvent(warpNativeElement, 'click'); + fixture.detectChanges(); + tick(1000); + fixture.detectChanges(); + expectModalHidden(fixture.debugElement.query(By.css('nz-modal')).nativeElement, false); + })); + }); }); // ------------------------------------------- @@ -689,6 +727,20 @@ class NzDemoModalBasicComponent { modalAvailable = true; } +@Component({ + template: ` + +

content

+
+ ` +}) +class NzDemoModalMaskComponent { + isVisible = false; + handleCancel(): void { + this.isVisible = false; + } +} + @Component({ template: ` From 3d0b864108d9bb5a238108148d92dbb1647b5506 Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Sun, 5 May 2019 13:38:51 +0800 Subject: [PATCH 2/2] chore(module:modal): use variable to save classname string --- components/modal/nz-modal.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/modal/nz-modal.component.ts b/components/modal/nz-modal.component.ts index abb8bd1d6fc..9becfaac7d8 100644 --- a/components/modal/nz-modal.component.ts +++ b/components/modal/nz-modal.component.ts @@ -49,6 +49,7 @@ import { ModalButtonOptions, ModalOptions, ModalType, OnClickCallback } from './ export const MODAL_ANIMATE_DURATION = 200; // Duration when perform animations (ms) type AnimationState = 'enter' | 'leave' | null; +export const WRAP_CLASS_NAME = 'ant-modal-wrap'; @Component({ selector: 'nz-modal', @@ -328,7 +329,7 @@ export class NzModalComponent extends NzModalRef if ( this.mask && this.maskClosable && - ($event.target as HTMLElement).classList.contains('ant-modal-wrap') && + ($event.target as HTMLElement).classList.contains(WRAP_CLASS_NAME) && this.nzVisible && !this.dialogMouseDown ) {