From 12cac9ed48654d11fa2c41f80a47e52ffc123dbe Mon Sep 17 00:00:00 2001 From: kekehaoz Date: Thu, 18 Apr 2019 11:25:09 +0800 Subject: [PATCH] feat(module: modal): support `nzMask` and `nzMaskClosable` global config (#3033) --- components/modal/doc/index.en-US.md | 24 ++++++++++ components/modal/doc/index.zh-CN.md | 23 +++++++++ components/modal/nz-modal-config.ts | 16 ++----- components/modal/nz-modal.component.html | 2 +- components/modal/nz-modal.component.ts | 52 +++++++++++++++----- components/modal/nz-modal.spec.ts | 61 ++++++++++++++++++++++++ 6 files changed, 153 insertions(+), 25 deletions(-) diff --git a/components/modal/doc/index.en-US.md b/components/modal/doc/index.en-US.md index 909afd5ad06..5e7904dae44 100644 --- a/components/modal/doc/index.en-US.md +++ b/components/modal/doc/index.en-US.md @@ -120,6 +120,30 @@ The dialog created by the service method `NzModalService.xxx()` will return a `N | triggerOk() | Manually trigger nzOnOk | | triggerCancel() | Manually trigger nzOnCancel | + +### Global Configuration + +Global Configuration(NZ_MODAL_CONFIG) + +if your want to set global configuration, you can use the value of provide `NZ_MODAL_CONFIG` to accomplish it. +(eg, add `{ provide: NZ_MODAL_CONFIG, useValue: { nzMask: false }}` to `providers` of your module, you can import `NZ_MODAL_CONFIG` from `ng-zorro-antd`) + +The weight of global configuration, component default value, component input value: + +component input value > global configuration > component default value + +supported global configuration item +```ts +{ + provide: NZ_MODAL_CONFIG, + useValue: { + nzMask?: boolean; // Whether show mask or not. + nzMaskClosable?: boolean; // Whether to close the modal dialog when the mask (area outside the modal) is clicked + } +} +``` +> Note: global configuration does not have default value which component has it. + #### ModalButtonOptions (used to customize the bottom button) An array of `ModalButtonOptions` type can be passed to `nzFooter` for custom bottom buttons. diff --git a/components/modal/doc/index.zh-CN.md b/components/modal/doc/index.zh-CN.md index 38524f41ed8..9c2fbc722f4 100644 --- a/components/modal/doc/index.zh-CN.md +++ b/components/modal/doc/index.zh-CN.md @@ -120,6 +120,29 @@ constructor(modal: NzModalService) { | triggerOk() | 手动触发nzOnOk | | triggerCancel() | 手动触发nzOnCancel | + +### 全局配置 + +全局配置(NZ_MODAL_CONFIG) +如果要进行全局默认配置,你可以设置提供商 `NZ_MODAL_CONFIG` 的值来实现。 +(如:在你的模块的`providers`中加入 `{ provide: NZ_MODAL_CONFIG, useValue: { nzMask: false }}`,`NZ_MODAL_CONFIG` 可以从 `ng-zorro-antd` 中导入) + +全局配置,组件默认值,组件层级配置之间的权重如下: + +组件层级配置 > 全局配置 > 组件默认值 + +当前支持的全局配置 +```ts +{ + provide: NZ_MODAL_CONFIG, + useValue: { + nzMask?: boolean; // 是否展示遮罩 + nzMaskClosable?: boolean; // 点击蒙层是否允许关闭 + } +} +``` +注:全局配置并无默认值,因为nzMask和nzMaskClosable默认值存在于组件中 + #### ModalButtonOptions(用于自定义底部按钮) 可将此类型数组传入 `nzFooter`,用于自定义底部按钮。 diff --git a/components/modal/nz-modal-config.ts b/components/modal/nz-modal-config.ts index db66f7f1751..205e99358da 100644 --- a/components/modal/nz-modal-config.ts +++ b/components/modal/nz-modal-config.ts @@ -1,17 +1,7 @@ import { InjectionToken } from '@angular/core'; -export const NZ_MODAL_DEFAULT_CONFIG: NzModalConfig = { - autoBodyPadding: true -}; - -export const NZ_MODAL_CONFIG = new InjectionToken('NzModalConfig', { - providedIn: 'root', - factory: () => NZ_MODAL_DEFAULT_CONFIG // Default config -}); - export interface NzModalConfig { - /** - * @deprecated used {@link BlockScrollStrategy} instead. - */ - autoBodyPadding?: boolean; // Whether add the padding-right and overflow to body automatically to play smoothly + nzMask?: boolean; + nzMaskClosable?: boolean; } +export const NZ_MODAL_CONFIG = new InjectionToken('NZ_MODAL_CONFIG'); diff --git a/components/modal/nz-modal.component.html b/components/modal/nz-modal.component.html index 2d12d419661..8f85e3e2616 100644 --- a/components/modal/nz-modal.component.html +++ b/components/modal/nz-modal.component.html @@ -1,7 +1,7 @@
-
extends NzModalRef implements OnInit, OnChanges, AfterViewInit, OnDestroy, ModalOptions { @Input() @InputBoolean() nzVisible: boolean = false; @Input() @InputBoolean() nzClosable: boolean = true; - @Input() @InputBoolean() nzMask: boolean = true; - @Input() @InputBoolean() nzMaskClosable: boolean = true; @Input() @InputBoolean() nzOkLoading: boolean = false; @Input() @InputBoolean() nzOkDisabled: boolean = false; @Input() @InputBoolean() nzCancelDisabled: boolean = false; @Input() @InputBoolean() nzCancelLoading: boolean = false; @Input() @InputBoolean() nzKeyboard: boolean = true; @Input() @InputBoolean() nzNoAnimation = false; + @Input() @InputBoolean() nzMask: boolean; + @Input() @InputBoolean() nzMaskClosable: boolean; @Input() nzContent: string | TemplateRef<{}> | Type; // [STATIC] If not specified, will use @Input() nzComponentParams: T; // [STATIC] ONLY avaliable when nzContent is a component @Input() nzFooter: string | TemplateRef<{}> | Array> | null; // [STATIC] Default Modal ONLY @@ -113,6 +114,40 @@ export class NzModalComponent extends NzModalRef return !this.nzVisible && !this.animationState; } // Indicate whether this dialog should hidden + /** + * @description + * The calculated highest weight of mask value + * + * Weight of different mask input: + * component default value < global configuration < component input value + */ + get mask(): boolean { + if (this.nzMask != null) { + return this.nzMask; + } else if (this.nzModalGlobalConfig && this.nzModalGlobalConfig.nzMask != null) { + return this.nzModalGlobalConfig.nzMask; + } else { + return true; + } + } + + /** + * @description + * The calculated highest weight of maskClosable value + * + * Weight of different maskClosable input: + * component default value < global configuration < component input value + */ + get maskClosable(): boolean { + if (this.nzMaskClosable != null) { + return this.nzMaskClosable; + } else if (this.nzModalGlobalConfig && this.nzModalGlobalConfig.nzMaskClosable != null) { + return this.nzModalGlobalConfig.nzMaskClosable; + } else { + return true; + } + } + locale: { okText?: string; cancelText?: string } = {}; maskAnimationClassMap: object | null; modalAnimationClassMap: object | null; @@ -137,11 +172,10 @@ export class NzModalComponent extends NzModalRef private modalControl: NzModalControlService, private focusTrapFactory: FocusTrapFactory, private cdr: ChangeDetectorRef, - @Inject(NZ_MODAL_CONFIG) private config: NzModalConfig, + @Optional() @Inject(NZ_MODAL_CONFIG) private nzModalGlobalConfig: NzModalConfig, @Inject(DOCUMENT) private document: any // tslint:disable-line:no-any ) { super(); - this.config = this.mergeDefaultConfig(this.config); this.scrollStrategy = this.overlay.scrollStrategies.block(); } @@ -256,8 +290,8 @@ export class NzModalComponent extends NzModalRef onClickMask($event: MouseEvent): void { if ( - this.nzMask && - this.nzMaskClosable && + this.mask && + this.maskClosable && ($event.target as HTMLElement).classList.contains('ant-modal-wrap') && this.nzVisible ) { @@ -444,10 +478,6 @@ export class NzModalComponent extends NzModalRef } } - private mergeDefaultConfig(config: NzModalConfig): NzModalConfig { - return { ...NZ_MODAL_DEFAULT_CONFIG, ...config }; - } - private savePreviouslyFocusedElement(): void { if (this.document) { this.previouslyFocusedElement = this.document.activeElement as HTMLElement; diff --git a/components/modal/nz-modal.spec.ts b/components/modal/nz-modal.spec.ts index ffbb10e5707..e42d30d6634 100644 --- a/components/modal/nz-modal.spec.ts +++ b/components/modal/nz-modal.spec.ts @@ -17,6 +17,7 @@ import en_US from '../i18n/languages/en_US'; import { NzI18nService } from '../i18n/nz-i18n.service'; import { NzIconTestModule } from '../icon/nz-icon-test.module'; import { CssUnitPipe } from './css-unit.pipe'; +import { NZ_MODAL_CONFIG } from './nz-modal-config'; import { NzModalControlService } from './nz-modal-control.service'; import { NzModalRef } from './nz-modal-ref.class'; import { NzModalComponent } from './nz-modal.component'; @@ -370,6 +371,54 @@ describe('modal testing (legacy)', () => { }); }); +describe('global config', () => { + let basicFixture: ComponentFixture; + let inputFixture: ComponentFixture; + let nativeElement: HTMLElement; + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule, NzModalModule], + providers: [ + { + provide: NZ_MODAL_CONFIG, + useValue: { + nzMask: false, + nzMaskClosable: false + } + } + ], + declarations: [NzDemoModalBasicComponent, NzDemoModalWithInputComponent] + }).compileComponents(); + basicFixture = TestBed.createComponent(NzDemoModalBasicComponent); + inputFixture = TestBed.createComponent(NzDemoModalWithInputComponent); + }); + + it('nzMask should be global config value', fakeAsync(() => { + const debugElement = basicFixture.debugElement.query(By.css('.ant-modal-mask')); + basicFixture.detectChanges(); + expect(debugElement).toBeNull(); + })); + + it('nzMask should be input value', fakeAsync(() => { + inputFixture.componentInstance.nzMask = true; + inputFixture.detectChanges(); + nativeElement = inputFixture.debugElement.query(By.css('.ant-modal-mask')).nativeElement; + inputFixture.detectChanges(); + expect(nativeElement).not.toBeNull(); + })); + + it('nzMaskClosable should be global config value', fakeAsync(() => { + inputFixture.componentInstance.nzMask = true; + inputFixture.detectChanges(); + nativeElement = inputFixture.debugElement.query(By.css('.ant-modal-wrap')).nativeElement; + inputFixture.detectChanges(); + nativeElement!.click(); + inputFixture.detectChanges(); + console.log(inputFixture.debugElement.nativeElement); + expectModalHidden(inputFixture.debugElement.query(By.css('nz-modal')).nativeElement, true); + })); +}); + describe('NzModal', () => { let modalService: NzModalService; let overlayContainer: OverlayContainer; @@ -627,6 +676,18 @@ class NzDemoModalBasicComponent { modalAvailable = true; } +@Component({ + template: ` + +

content

+
+ ` +}) +class NzDemoModalWithInputComponent { + modalAvailable = true; + nzMask = true; +} + @Component({ selector: 'nz-demo-modal-async', template: `