Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(module: modal): support nzMask and nzMaskClosable global config #3033

Merged
merged 14 commits into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions components/modal/doc/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
23 changes: 23 additions & 0 deletions components/modal/doc/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`,用于自定义底部按钮。
Expand Down
16 changes: 3 additions & 13 deletions components/modal/nz-modal-config.ts
Original file line number Diff line number Diff line change
@@ -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>('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<NzModalConfig>('NZ_MODAL_CONFIG');
2 changes: 1 addition & 1 deletion components/modal/nz-modal.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<ng-template #tplOriginContent><ng-content></ng-content></ng-template> <!-- Compatible: the <ng-content> can appear only once -->

<div [nzNoAnimation]="nzNoAnimation">
<div *ngIf="nzMask"
<div *ngIf="mask"
class="ant-modal-mask"
[ngClass]="maskAnimationClassMap"
[class.ant-modal-mask-hidden]="hidden"
Expand Down
52 changes: 41 additions & 11 deletions components/modal/nz-modal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
OnChanges,
OnDestroy,
OnInit,
Optional,
Output,
SimpleChanges,
TemplateRef,
Expand All @@ -33,7 +34,7 @@ import { InputBoolean } from '../core/util/convert';
import { isPromise } from '../core/util/is-promise';
import { NzI18nService } from '../i18n/nz-i18n.service';
import ModalUtil from './modal-util';
import { NzModalConfig, NZ_MODAL_CONFIG, NZ_MODAL_DEFAULT_CONFIG } from './nz-modal-config';
import { NzModalConfig, NZ_MODAL_CONFIG } from './nz-modal-config';
import { NzModalControlService } from './nz-modal-control.service';
import { NzModalRef } from './nz-modal-ref.class';
import { ModalButtonOptions, ModalOptions, ModalType, OnClickCallback } from './nz-modal.type';
Expand All @@ -54,14 +55,14 @@ export class NzModalComponent<T = any, R = any> extends NzModalRef<T, R>
implements OnInit, OnChanges, AfterViewInit, OnDestroy, ModalOptions<T> {
@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<T>; // [STATIC] If not specified, will use <ng-content>
@Input() nzComponentParams: T; // [STATIC] ONLY avaliable when nzContent is a component
@Input() nzFooter: string | TemplateRef<{}> | Array<ModalButtonOptions<T>> | null; // [STATIC] Default Modal ONLY
Expand Down Expand Up @@ -113,6 +114,40 @@ export class NzModalComponent<T = any, R = any> extends NzModalRef<T, R>
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;
Expand All @@ -137,11 +172,10 @@ export class NzModalComponent<T = any, R = any> extends NzModalRef<T, R>
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();
}

Expand Down Expand Up @@ -256,8 +290,8 @@ export class NzModalComponent<T = any, R = any> extends NzModalRef<T, R>

onClickMask($event: MouseEvent): void {
if (
this.nzMask &&
this.nzMaskClosable &&
this.mask &&
this.maskClosable &&
($event.target as HTMLElement).classList.contains('ant-modal-wrap') &&
this.nzVisible
) {
Expand Down Expand Up @@ -444,10 +478,6 @@ export class NzModalComponent<T = any, R = any> extends NzModalRef<T, R>
}
}

private mergeDefaultConfig(config: NzModalConfig): NzModalConfig {
return { ...NZ_MODAL_DEFAULT_CONFIG, ...config };
}

private savePreviouslyFocusedElement(): void {
if (this.document) {
this.previouslyFocusedElement = this.document.activeElement as HTMLElement;
Expand Down
61 changes: 61 additions & 0 deletions components/modal/nz-modal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -370,6 +371,54 @@ describe('modal testing (legacy)', () => {
});
});

describe('global config', () => {
let basicFixture: ComponentFixture<NzDemoModalBasicComponent>;
let inputFixture: ComponentFixture<NzDemoModalWithInputComponent>;
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>(NzDemoModalBasicComponent);
inputFixture = TestBed.createComponent<NzDemoModalWithInputComponent>(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;
Expand Down Expand Up @@ -627,6 +676,18 @@ class NzDemoModalBasicComponent {
modalAvailable = true;
}

@Component({
template: `
<nz-modal *ngIf="modalAvailable" [nzMask]="nzMask">
<p>content</p>
</nz-modal>
`
})
class NzDemoModalWithInputComponent {
modalAvailable = true;
nzMask = true;
}

@Component({
selector: 'nz-demo-modal-async',
template: `
Expand Down