From 1f5e9a0ca475f9c70ea448b0c512deffe5c2a918 Mon Sep 17 00:00:00 2001
From: Hsuan Lee
Date: Sun, 19 Jan 2020 14:45:01 +0800
Subject: [PATCH] chore: rename files
---
components/modal/demo/async.ts | 4 +-
components/modal/demo/basic.ts | 4 +-
components/modal/demo/confirm-promise.ts | 6 +-
components/modal/demo/confirm.ts | 4 +-
components/modal/demo/footer.ts | 4 +-
components/modal/demo/footer2.ts | 10 +-
components/modal/demo/info.ts | 4 +-
components/modal/demo/locale.ts | 4 +-
components/modal/demo/position.ts | 8 +-
components/modal/demo/service.ts | 69 +-
components/modal/modal-close.component.ts | 4 +-
.../{nz-modal-config.ts => modal-config.ts} | 0
.../modal-confirm-container.component.ts | 16 +-
components/modal/modal-container.component.ts | 305 +----
components/modal/modal-container.ts | 298 +++++
components/modal/modal-footer.component.ts | 12 +-
...spec.ts => modal-footer.directive.spec.ts} | 4 +-
...directive.ts => modal-footer.directive.ts} | 4 +-
.../modal/{nz-modal-ref.ts => modal-ref.ts} | 18 +-
components/modal/modal-title.component.ts | 4 +-
.../{nz-modal.type.ts => modal-types.ts} | 53 +-
components/modal/modal.component.ts | 22 +-
.../{nz-modal.module.ts => modal.module.ts} | 20 +-
.../modal/{nz-modal.ts => modal.service.ts} | 105 +-
components/modal/modal.spec.ts | 1 +
.../modal/nz-modal-control.service.module.ts | 12 -
components/modal/nz-modal-control.service.ts | 92 --
components/modal/nz-modal-ref.class.ts | 53 -
components/modal/nz-modal.component.html | 198 ----
components/modal/nz-modal.component.ts | 575 ---------
components/modal/nz-modal.service.module.ts | 12 -
components/modal/nz-modal.service.ts | 148 ---
components/modal/nz-modal.spec.ts | 1041 -----------------
components/modal/public-api.ts | 19 +-
components/modal/utils.ts | 8 +-
35 files changed, 466 insertions(+), 2675 deletions(-)
rename components/modal/{nz-modal-config.ts => modal-config.ts} (100%)
create mode 100644 components/modal/modal-container.ts
rename components/modal/{nz-modal-footer.directive.spec.ts => modal-footer.directive.spec.ts} (95%)
rename components/modal/{nz-modal-footer.directive.ts => modal-footer.directive.ts} (78%)
rename components/modal/{nz-modal-ref.ts => modal-ref.ts} (91%)
rename components/modal/{nz-modal.type.ts => modal-types.ts} (62%)
rename components/modal/{nz-modal.module.ts => modal.module.ts} (69%)
rename components/modal/{nz-modal.ts => modal.service.ts} (70%)
create mode 100644 components/modal/modal.spec.ts
delete mode 100644 components/modal/nz-modal-control.service.module.ts
delete mode 100644 components/modal/nz-modal-control.service.ts
delete mode 100644 components/modal/nz-modal-ref.class.ts
delete mode 100644 components/modal/nz-modal.component.html
delete mode 100644 components/modal/nz-modal.component.ts
delete mode 100644 components/modal/nz-modal.service.module.ts
delete mode 100644 components/modal/nz-modal.service.ts
delete mode 100644 components/modal/nz-modal.spec.ts
diff --git a/components/modal/demo/async.ts b/components/modal/demo/async.ts
index 86fbef3977f..197abf1f67b 100644
--- a/components/modal/demo/async.ts
+++ b/components/modal/demo/async.ts
@@ -6,7 +6,7 @@ import { Component } from '@angular/core';
-
Modal Content
-
+
`
})
export class NzDemoModalAsyncComponent {
diff --git a/components/modal/demo/basic.ts b/components/modal/demo/basic.ts
index ce7a14070ac..eed584370b7 100644
--- a/components/modal/demo/basic.ts
+++ b/components/modal/demo/basic.ts
@@ -4,12 +4,12 @@ import { Component } from '@angular/core';
selector: 'nz-demo-modal-basic',
template: `
-
+
Content one
Content two
Content three
Content three
-
+
`
})
export class NzDemoModalBasicComponent {
diff --git a/components/modal/demo/confirm-promise.ts b/components/modal/demo/confirm-promise.ts
index 25c5e0669f4..88401c322f4 100644
--- a/components/modal/demo/confirm-promise.ts
+++ b/components/modal/demo/confirm-promise.ts
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
-import { NzModal, NzModalRef2 } from 'ng-zorro-antd/modal';
+import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
@Component({
selector: 'nz-demo-modal-confirm-promise',
@@ -8,9 +8,9 @@ import { NzModal, NzModalRef2 } from 'ng-zorro-antd/modal';
`
})
export class NzDemoModalConfirmPromiseComponent {
- confirmModal: NzModalRef2; // For testing by now
+ confirmModal: NzModalRef; // For testing by now
- constructor(private modal: NzModal) {}
+ constructor(private modal: NzModalService) {}
showConfirm(): void {
this.confirmModal = this.modal.confirm({
diff --git a/components/modal/demo/confirm.ts b/components/modal/demo/confirm.ts
index 159dcb16c49..a70ed64faff 100644
--- a/components/modal/demo/confirm.ts
+++ b/components/modal/demo/confirm.ts
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
-import { NzModal } from 'ng-zorro-antd/modal';
+import { NzModalService } from 'ng-zorro-antd/modal';
@Component({
selector: 'nz-demo-modal-confirm',
@@ -16,7 +16,7 @@ import { NzModal } from 'ng-zorro-antd/modal';
]
})
export class NzDemoModalConfirmComponent {
- constructor(private modal: NzModal) {}
+ constructor(private modal: NzModalService) {}
showConfirm(): void {
this.modal.confirm({
diff --git a/components/modal/demo/footer.ts b/components/modal/demo/footer.ts
index c2515b522f9..24a6a2c7b78 100644
--- a/components/modal/demo/footer.ts
+++ b/components/modal/demo/footer.ts
@@ -6,7 +6,7 @@ import { Component } from '@angular/core';
- Custom Callback
-
+
`
})
export class NzDemoModalFooterComponent {
diff --git a/components/modal/demo/footer2.ts b/components/modal/demo/footer2.ts
index 983516a26b9..1f6c82a184b 100644
--- a/components/modal/demo/footer2.ts
+++ b/components/modal/demo/footer2.ts
@@ -1,7 +1,7 @@
/* entryComponents: NzModalCustomFooterComponent */
import { Component } from '@angular/core';
-import { NzModal, NzModalRef2 } from 'ng-zorro-antd/modal';
+import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
@Component({
selector: 'nz-demo-modal-footer2',
@@ -14,7 +14,7 @@ import { NzModal, NzModalRef2 } from 'ng-zorro-antd/modal';
-
+
Modal Content
Modal Content
@@ -27,7 +27,7 @@ import { NzModal, NzModalRef2 } from 'ng-zorro-antd/modal';
-
+
`,
styles: []
})
@@ -35,7 +35,7 @@ export class NzDemoModalFooter2Component {
isVisible = false;
isConfirmLoading = false;
- constructor(private modalService: NzModal) {}
+ constructor(private modalService: NzModalService) {}
showModal1(): void {
this.isVisible = true;
@@ -78,7 +78,7 @@ export class NzDemoModalFooter2Component {
`
})
export class NzModalCustomFooterComponent {
- constructor(private modal: NzModalRef2) {}
+ constructor(private modal: NzModalRef) {}
destroyModal(): void {
this.modal.destroy();
diff --git a/components/modal/demo/info.ts b/components/modal/demo/info.ts
index 84937f51848..5a5d19013b8 100644
--- a/components/modal/demo/info.ts
+++ b/components/modal/demo/info.ts
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
-import { NzModal } from 'ng-zorro-antd/modal';
+import { NzModalService } from 'ng-zorro-antd/modal';
@Component({
selector: 'nz-demo-modal-info',
@@ -18,7 +18,7 @@ import { NzModal } from 'ng-zorro-antd/modal';
]
})
export class NzDemoModalInfoComponent {
- constructor(private modal: NzModal) {}
+ constructor(private modal: NzModalService) {}
info(): void {
this.modal.info({
diff --git a/components/modal/demo/locale.ts b/components/modal/demo/locale.ts
index aeb6a31d154..1b1282b02f0 100644
--- a/components/modal/demo/locale.ts
+++ b/components/modal/demo/locale.ts
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
-import { NzModal } from 'ng-zorro-antd/modal';
+import { NzModalService } from 'ng-zorro-antd/modal';
@Component({
selector: 'nz-demo-modal-locale',
@@ -26,7 +26,7 @@ import { NzModal } from 'ng-zorro-antd/modal';
export class NzDemoModalLocaleComponent {
isVisible = false;
- constructor(private modalService: NzModal) {}
+ constructor(private modalService: NzModalService) {}
showModal(): void {
this.isVisible = true;
diff --git a/components/modal/demo/position.ts b/components/modal/demo/position.ts
index 43a4824b0b4..01db401760c 100644
--- a/components/modal/demo/position.ts
+++ b/components/modal/demo/position.ts
@@ -4,7 +4,7 @@ import { Component } from '@angular/core';
selector: 'nz-demo-modal-position',
template: `
- some contents...
some contents...
some contents...
-
+
- some contents...
some contents...
some contents...
-
+
`,
styles: [
`
diff --git a/components/modal/demo/service.ts b/components/modal/demo/service.ts
index 8a789c25a92..c219d3e3b65 100644
--- a/components/modal/demo/service.ts
+++ b/components/modal/demo/service.ts
@@ -1,7 +1,7 @@
-/* entryComponents: NzModalCustomComponent,NzModalCustomComponent */
+/* entryComponents: NzModalCustomComponent */
import { Component, Input, TemplateRef } from '@angular/core';
-import { NzModal, NzModalRef2 } from 'ng-zorro-antd/modal';
+import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
@Component({
selector: 'nz-demo-modal-service',
@@ -35,9 +35,6 @@ import { NzModal, NzModalRef2 } from 'ng-zorro-antd/modal';
Use Component
-
@@ -56,12 +53,12 @@ import { NzModal, NzModalRef2 } from 'ng-zorro-antd/modal';
]
})
export class NzDemoModalServiceComponent {
- tplModal: NzModalRef2;
+ tplModal: NzModalRef;
tplModalButtonLoading = false;
htmlModalVisible = false;
disabled = false;
- constructor(private modal: NzModal) {}
+ constructor(private modal: NzModalService) {}
createModal(): void {
this.modal.create({
@@ -91,29 +88,6 @@ export class NzDemoModalServiceComponent {
}, 1000);
}
- createComponentModal2(): void {
- const modalRef = this.modal.create({
- nzContent: NzModalCustom2Component,
- nzTitle: 'Title',
- nzMaskStyle: {
- color: 'red'
- },
- nzStyle: {
- color: 'red'
- },
- nzClassName: 'my-class-name',
- nzWrapClassName: 'my-wrap-class-name',
- nzZIndex: 1100,
- nzComponentParams: {
- title: 'title',
- subtitle: 'subtitle'
- },
- nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000))
- });
- modalRef.afterOpen.subscribe(console.log);
- modalRef.afterClose.subscribe(console.log);
- }
-
createComponentModal(): void {
const modal = this.modal.create({
nzTitle: 'Modal Title',
@@ -133,27 +107,25 @@ export class NzDemoModalServiceComponent {
}
]
});
-
+ const instance = modal.getContentComponent();
modal.afterOpen.subscribe(() => console.log('[afterOpen] emitted!'));
-
// Return a result when closed
modal.afterClose.subscribe(result => console.log('[afterClose] The result is:', result));
// delay until modal instance created
setTimeout(() => {
- const instance = modal.getContentComponent();
instance.subtitle = 'sub title is changed';
}, 2000);
}
createCustomButtonModal(): void {
- const modal: NzModalRef2 = this.modal.create({
+ const modal: NzModalRef = this.modal.create({
nzTitle: 'custom button demo',
nzContent: 'pass array of button config to nzFooter to create multiple buttons',
nzFooter: [
{
label: 'Close',
- shape: 'default',
+ shape: 'round',
onClick: () => modal.destroy()
},
{
@@ -222,32 +194,7 @@ export class NzModalCustomComponent {
@Input() title: string;
@Input() subtitle: string;
- constructor(private modal: NzModalRef2) {}
-
- destroyModal(): void {
- this.modal.destroy({ data: 'this the result data' });
- }
-}
-
-@Component({
- selector: 'nz-modal-custom-component',
- template: `
- {{ title }}
- {{ subtitle }}
- Content
-
- Content
-
- Content...
- `
-})
-export class NzModalCustom2Component {
- @Input() title: string;
- @Input() subtitle: string;
-
- constructor(private modal: NzModalRef2) {
- console.log(modal);
- }
+ constructor(private modal: NzModalRef) {}
destroyModal(): void {
this.modal.destroy({ data: 'this the result data' });
diff --git a/components/modal/modal-close.component.ts b/components/modal/modal-close.component.ts
index 9c1172b90bf..8b495e5aa0e 100644
--- a/components/modal/modal-close.component.ts
+++ b/components/modal/modal-close.component.ts
@@ -8,7 +8,7 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { ModalConfig } from './nz-modal.type';
+import { ModalOptions } from './modal-types';
@Component({
selector: 'button[nz-modal-close]',
@@ -27,5 +27,5 @@ import { ModalConfig } from './nz-modal.type';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NzModalCloseComponent {
- constructor(public config: ModalConfig) {}
+ constructor(public config: ModalOptions) {}
}
diff --git a/components/modal/nz-modal-config.ts b/components/modal/modal-config.ts
similarity index 100%
rename from components/modal/nz-modal-config.ts
rename to components/modal/modal-config.ts
diff --git a/components/modal/modal-confirm-container.component.ts b/components/modal/modal-confirm-container.component.ts
index 3ea0b0c5508..d04216f511a 100644
--- a/components/modal/modal-confirm-container.component.ts
+++ b/components/modal/modal-confirm-container.component.ts
@@ -24,6 +24,7 @@ import {
Renderer2,
ViewChild
} from '@angular/core';
+import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@@ -31,8 +32,8 @@ import { takeUntil } from 'rxjs/operators';
import { NzI18nService } from 'ng-zorro-antd/i18n';
import { nzModalAnimations } from './modal-animations';
-import { NzModalContainerComponent } from './modal-container.component';
-import { ModalConfig } from './nz-modal.type';
+import { BaseModalContainer } from './modal-container';
+import { ModalOptions } from './modal-types';
@Component({
selector: 'nz-modal-confirm-container',
@@ -44,7 +45,7 @@ import { ModalConfig } from './nz-modal.type';
class="ant-modal"
[class]="config.nzClassName"
[ngStyle]="config.nzStyle"
- [style.width]="config.nzWidth | nzToCssUnit"
+ [style.width]="config?.nzWidth | nzToCssUnit"
>
@@ -107,7 +108,7 @@ import { ModalConfig } from './nz-modal.type';
'(mouseup)': 'onMouseup($event)'
}
})
-export class NzModalConfirmContainerComponent extends NzModalContainerComponent implements OnDestroy {
+export class NzModalConfirmContainerComponent extends BaseModalContainer implements OnDestroy {
@ViewChild(CdkPortalOutlet, { static: true }) portalOutlet: CdkPortalOutlet;
@ViewChild('modalElement', { static: true }) modalElementRef: ElementRef
;
@Output() readonly cancelTriggered = new EventEmitter();
@@ -123,11 +124,12 @@ export class NzModalConfirmContainerComponent extends NzModalContainerComponent
render: Renderer2,
zone: NgZone,
overlayRef: OverlayRef,
- public config: ModalConfig,
+ public config: ModalOptions,
// tslint:disable-next-line:no-any
- @Optional() @Inject(DOCUMENT) document: any
+ @Optional() @Inject(DOCUMENT) document: any,
+ @Optional() @Inject(ANIMATION_MODULE_TYPE) animationType: string
) {
- super(elementRef, focusTrapFactory, cdr, render, zone, overlayRef, config, document);
+ super(elementRef, focusTrapFactory, cdr, render, zone, overlayRef, config, document, animationType);
this.i18n.localeChange.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.locale = this.i18n.getLocaleData('Modal');
});
diff --git a/components/modal/modal-container.component.ts b/components/modal/modal-container.component.ts
index 257849da838..cc5ac5982e3 100644
--- a/components/modal/modal-container.component.ts
+++ b/components/modal/modal-container.component.ts
@@ -6,49 +6,26 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/
-import { AnimationEvent } from '@angular/animations';
-import { FocusTrap, FocusTrapFactory } from '@angular/cdk/a11y';
+import { FocusTrapFactory } from '@angular/cdk/a11y';
import { OverlayRef } from '@angular/cdk/overlay';
-import { BasePortalOutlet, CdkPortalOutlet, ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
+import { CdkPortalOutlet } from '@angular/cdk/portal';
import { DOCUMENT } from '@angular/common';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
- ComponentRef,
ElementRef,
- EmbeddedViewRef,
- EventEmitter,
Inject,
NgZone,
Optional,
Renderer2,
ViewChild
} from '@angular/core';
-
-import { getElementOffset } from 'ng-zorro-antd/core';
+import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
import { nzModalAnimations } from './modal-animations';
-import { NzModalRef2 } from './nz-modal-ref';
-import { ModalConfig } from './nz-modal.type';
-
-export function throwNzModalContentAlreadyAttachedError(): never {
- throw Error('Attempting to attach modal content after content is already attached');
-}
-
-const ZOOM_CLASS_NAME_MAP = {
- enter: 'zoom-enter',
- enterActive: 'zoom-enter-active',
- leave: 'zoom-leave',
- leaveActive: 'zoom-leave-active'
-};
-
-const FADE_CLASS_NAME_MAP = {
- enter: 'fade-enter',
- enterActive: 'fade-enter-active',
- leave: 'fade-leave',
- leaveActive: 'fade-leave-active'
-};
+import { BaseModalContainer } from './modal-container';
+import { ModalOptions } from './modal-types';
@Component({
selector: 'nz-modal-container',
@@ -60,7 +37,7 @@ const FADE_CLASS_NAME_MAP = {
class="ant-modal"
[class]="config.nzClassName"
[ngStyle]="config.nzStyle"
- [style.width]="config.nzWidth | nzToCssUnit"
+ [style.width]="config?.nzWidth | nzToCssUnit"
>
@@ -69,7 +46,13 @@ const FADE_CLASS_NAME_MAP = {
-
+
`,
@@ -91,261 +74,21 @@ const FADE_CLASS_NAME_MAP = {
}
})
// tslint:disable-next-line:no-any
-export class NzModalContainerComponent extends BasePortalOutlet {
+export class NzModalContainerComponent extends BaseModalContainer {
@ViewChild(CdkPortalOutlet, { static: true }) portalOutlet: CdkPortalOutlet;
@ViewChild('modalElement', { static: true }) modalElementRef: ElementRef;
-
- animationStateChanged = new EventEmitter();
- containerClick = new EventEmitter();
- cancelTriggered = new EventEmitter();
- okTriggered = new EventEmitter();
-
- state: 'void' | 'enter' | 'exit' = 'enter';
- document: Document;
- // tslint:disable-next-line:no-any
- modalRef: NzModalRef2;
- isStringContent: boolean = false;
- private elementFocusedBeforeModalWasOpened: HTMLElement | null = null;
- private focusTrap: FocusTrap;
- private latestMousedownTarget: HTMLElement | null = null;
- private oldMaskStyle: { [key: string]: string } | null = null;
-
constructor(
- protected elementRef: ElementRef,
- protected focusTrapFactory: FocusTrapFactory,
- protected cdr: ChangeDetectorRef,
- protected render: Renderer2,
- protected zone: NgZone,
- protected overlayRef: OverlayRef,
- public config: ModalConfig,
+ elementRef: ElementRef,
+ focusTrapFactory: FocusTrapFactory,
+ cdr: ChangeDetectorRef,
+ render: Renderer2,
+ zone: NgZone,
+ overlayRef: OverlayRef,
+ public config: ModalOptions,
// tslint:disable-next-line:no-any
- @Optional() @Inject(DOCUMENT) document: any
+ @Optional() @Inject(DOCUMENT) document: any,
+ @Optional() @Inject(ANIMATION_MODULE_TYPE) animationType: string
) {
- super();
- this.document = document;
- this.isStringContent = typeof config.nzContent === 'string';
- this.setContainer();
- console.log(config);
- }
-
- onMousedown(e: MouseEvent): void {
- this.latestMousedownTarget = (e.target as HTMLElement) || null;
- }
-
- onMouseup(e: MouseEvent): void {
- if (e.target === this.latestMousedownTarget && e.target === this.elementRef.nativeElement) {
- this.containerClick.emit();
- }
- this.latestMousedownTarget = null;
- }
-
- onCloseClick(): void {
- this.cancelTriggered.emit();
- }
-
- onOkClick(): void {
- this.okTriggered.emit();
- }
-
- attachComponentPortal(portal: ComponentPortal): ComponentRef {
- if (this.portalOutlet.hasAttached()) {
- throwNzModalContentAlreadyAttachedError();
- }
- this.savePreviouslyFocusedElement();
- this.setModalTransformOrigin();
- return this.portalOutlet.attachComponentPortal(portal);
- }
-
- attachTemplatePortal(portal: TemplatePortal): EmbeddedViewRef {
- if (this.portalOutlet.hasAttached()) {
- throwNzModalContentAlreadyAttachedError();
- }
- this.savePreviouslyFocusedElement();
- return this.portalOutlet.attachTemplatePortal(portal);
- }
-
- getNativeElement(): HTMLElement {
- return this.elementRef.nativeElement;
- }
-
- private setModalTransformOrigin(): void {
- const modalElement = this.modalElementRef.nativeElement;
- if (this.elementFocusedBeforeModalWasOpened as HTMLElement) {
- const previouslyDOMRect = this.elementFocusedBeforeModalWasOpened!.getBoundingClientRect();
- const lastPosition = getElementOffset(this.elementFocusedBeforeModalWasOpened!);
- const x = lastPosition.left + previouslyDOMRect.width / 2;
- const y = lastPosition.top + previouslyDOMRect.height / 2;
- const transformOrigin = `${x - modalElement.offsetLeft}px ${y - modalElement.offsetTop}px 0px`;
- this.render.setStyle(modalElement, 'transform-origin', transformOrigin);
- }
- }
-
- private savePreviouslyFocusedElement(): void {
- if (this.document) {
- this.elementFocusedBeforeModalWasOpened = this.document.activeElement as HTMLElement;
- if (this.elementRef.nativeElement.focus) {
- Promise.resolve().then(() => this.elementRef.nativeElement.focus());
- }
- }
- }
-
- private trapFocus(): void {
- const element = this.elementRef.nativeElement;
-
- if (!this.focusTrap) {
- this.focusTrap = this.focusTrapFactory.create(element);
- }
-
- if (this.config.nzAutofocus) {
- this.focusTrap.focusInitialElementWhenReady().then();
- } else {
- const activeElement = this.document.activeElement;
- if (activeElement !== element && !element.contains(activeElement)) {
- element.focus();
- }
- }
- }
-
- private restoreFocus(): void {
- const toFocus = this.elementFocusedBeforeModalWasOpened as HTMLElement;
-
- // We need the extra check, because IE can set the `activeElement` to null in some cases.
- if (toFocus && typeof toFocus.focus === 'function') {
- const activeElement = this.document.activeElement as Element;
- const element = this.elementRef.nativeElement;
-
- if (!activeElement || activeElement === this.document.body || activeElement === element || element.contains(activeElement)) {
- toFocus.focus();
- }
- }
-
- if (this.focusTrap) {
- this.focusTrap.destroy();
- }
- }
-
- private setEnterAnimationClass(): void {
- if (this.config.nzNoAnimation) {
- return;
- }
- this.zone.runOutsideAngular(() => {
- // Make sure to set the `TransformOrigin` style before set the modelElement's class names
- this.setModalTransformOrigin();
- const modalElement = this.modalElementRef.nativeElement;
- const backdropElement = this.overlayRef.backdropElement;
- this.render.addClass(modalElement, ZOOM_CLASS_NAME_MAP.enter);
- this.render.addClass(modalElement, ZOOM_CLASS_NAME_MAP.enterActive);
- this.render.addClass(backdropElement, FADE_CLASS_NAME_MAP.enter);
- this.render.addClass(backdropElement, FADE_CLASS_NAME_MAP.enterActive);
- });
- }
-
- private setExitAnimationClass(): void {
- if (this.config.nzNoAnimation) {
- return;
- }
- this.zone.runOutsideAngular(() => {
- const modalElement = this.modalElementRef.nativeElement;
- const backdropElement = this.overlayRef.backdropElement;
- this.render.addClass(modalElement, ZOOM_CLASS_NAME_MAP.leave);
- this.render.addClass(modalElement, ZOOM_CLASS_NAME_MAP.leaveActive);
- this.render.addClass(backdropElement, FADE_CLASS_NAME_MAP.leave);
- this.render.addClass(backdropElement, FADE_CLASS_NAME_MAP.leaveActive);
- });
- }
-
- private cleanAnimationClass(): void {
- if (this.config.nzNoAnimation) {
- return;
- }
- this.zone.runOutsideAngular(() => {
- const backdropElement = this.overlayRef.backdropElement;
- const modalElement = this.modalElementRef.nativeElement;
- this.render.removeClass(modalElement, ZOOM_CLASS_NAME_MAP.enter);
- this.render.removeClass(modalElement, ZOOM_CLASS_NAME_MAP.enterActive);
- this.render.removeClass(modalElement, ZOOM_CLASS_NAME_MAP.leave);
- this.render.removeClass(modalElement, ZOOM_CLASS_NAME_MAP.leaveActive);
- this.render.removeClass(backdropElement, FADE_CLASS_NAME_MAP.enter);
- this.render.removeClass(backdropElement, FADE_CLASS_NAME_MAP.enterActive);
- });
- }
-
- private bindBackdropStyle(): void {
- this.zone.runOutsideAngular(() => {
- if (this.oldMaskStyle) {
- const backdropElement = this.overlayRef.backdropElement;
- const styles = this.oldMaskStyle as { [key: string]: string };
- Object.keys(styles).forEach(key => {
- this.render.removeStyle(backdropElement, key);
- });
- this.oldMaskStyle = null;
- }
-
- if (typeof this.config.nzMaskStyle === 'object' && Object.keys(this.config.nzMaskStyle).length) {
- const backdropElement = this.overlayRef.backdropElement;
- const styles: { [key: string]: string } = { ...this.config.nzMaskStyle };
- Object.keys(styles).forEach(key => {
- this.render.setStyle(backdropElement, key, styles[key]);
- });
- this.oldMaskStyle = styles;
- }
- });
- }
-
- /**
- * Set the container element.
- * @deprecated Not supported.
- * @breaking-change 10.0.0
- */
- private setContainer(): void {
- const container = this.getContainer();
- if (container) {
- this.render.appendChild(container, this.elementRef.nativeElement);
- }
- }
-
- /**
- * Reset the container element.
- * @deprecated Not supported.
- * @breaking-change 10.0.0
- */
- private resetContainer(): void {
- const container = this.getContainer();
- if (container) {
- this.render.appendChild(this.overlayRef.overlayElement, this.elementRef.nativeElement);
- }
- }
-
- private getContainer(): HTMLElement | null {
- const { nzGetContainer } = this.config;
- const container = typeof nzGetContainer === 'function' ? nzGetContainer() : nzGetContainer;
- return container instanceof HTMLElement ? container : null;
- }
-
- onAnimationDone(event: AnimationEvent): void {
- if (event.toState === 'enter') {
- this.setContainer();
- this.trapFocus();
- } else if (event.toState === 'exit') {
- this.restoreFocus();
- }
- this.cleanAnimationClass();
- this.animationStateChanged.emit(event);
- }
-
- onAnimationStart(event: AnimationEvent): void {
- if (event.toState === 'enter') {
- this.setEnterAnimationClass();
- this.bindBackdropStyle();
- } else if (event.toState === 'exit') {
- this.resetContainer();
- this.setExitAnimationClass();
- }
- this.animationStateChanged.emit(event);
- }
-
- startExitAnimation(): void {
- this.state = 'exit';
- this.cdr.markForCheck();
+ super(elementRef, focusTrapFactory, cdr, render, zone, overlayRef, config, document, animationType);
}
}
diff --git a/components/modal/modal-container.ts b/components/modal/modal-container.ts
new file mode 100644
index 00000000000..7076f42a5b9
--- /dev/null
+++ b/components/modal/modal-container.ts
@@ -0,0 +1,298 @@
+/**
+ * @license
+ * Copyright Alibaba.com All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
+ */
+
+import { AnimationEvent } from '@angular/animations';
+import { FocusTrap, FocusTrapFactory } from '@angular/cdk/a11y';
+import { OverlayRef } from '@angular/cdk/overlay';
+import { BasePortalOutlet, CdkPortalOutlet, ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
+import { ChangeDetectorRef, ComponentRef, ElementRef, EmbeddedViewRef, EventEmitter, NgZone, Renderer2 } from '@angular/core';
+
+import { getElementOffset } from 'ng-zorro-antd/core';
+
+import { NzModalRef } from './modal-ref';
+import { ModalOptions } from './modal-types';
+
+export function throwNzModalContentAlreadyAttachedError(): never {
+ throw Error('Attempting to attach modal content after content is already attached');
+}
+
+const ZOOM_CLASS_NAME_MAP = {
+ enter: 'zoom-enter',
+ enterActive: 'zoom-enter-active',
+ leave: 'zoom-leave',
+ leaveActive: 'zoom-leave-active'
+};
+
+const FADE_CLASS_NAME_MAP = {
+ enter: 'fade-enter',
+ enterActive: 'fade-enter-active',
+ leave: 'fade-leave',
+ leaveActive: 'fade-leave-active'
+};
+
+export class BaseModalContainer extends BasePortalOutlet {
+ portalOutlet: CdkPortalOutlet;
+ modalElementRef: ElementRef;
+
+ animationStateChanged = new EventEmitter();
+ containerClick = new EventEmitter();
+ cancelTriggered = new EventEmitter();
+ okTriggered = new EventEmitter();
+
+ state: 'void' | 'enter' | 'exit' = 'enter';
+ document: Document;
+ modalRef: NzModalRef;
+ isStringContent: boolean = false;
+ private elementFocusedBeforeModalWasOpened: HTMLElement | null = null;
+ private focusTrap: FocusTrap;
+ private latestMousedownTarget: HTMLElement | null = null;
+ private oldMaskStyle: { [key: string]: string } | null = null;
+
+ constructor(
+ protected elementRef: ElementRef,
+ protected focusTrapFactory: FocusTrapFactory,
+ protected cdr: ChangeDetectorRef,
+ protected render: Renderer2,
+ protected zone: NgZone,
+ protected overlayRef: OverlayRef,
+ public config: ModalOptions,
+ // tslint:disable-next-line:no-any
+ document?: any,
+ protected animationType?: string
+ ) {
+ super();
+ this.document = document;
+ this.isStringContent = typeof config.nzContent === 'string';
+ this.setContainer();
+ }
+
+ onMousedown(e: MouseEvent): void {
+ this.latestMousedownTarget = (e.target as HTMLElement) || null;
+ }
+
+ onMouseup(e: MouseEvent): void {
+ if (e.target === this.latestMousedownTarget && e.target === this.elementRef.nativeElement) {
+ this.containerClick.emit();
+ }
+ this.latestMousedownTarget = null;
+ }
+
+ onCloseClick(): void {
+ this.cancelTriggered.emit();
+ }
+
+ onOkClick(): void {
+ this.okTriggered.emit();
+ }
+
+ attachComponentPortal(portal: ComponentPortal): ComponentRef {
+ if (this.portalOutlet.hasAttached()) {
+ throwNzModalContentAlreadyAttachedError();
+ }
+ this.savePreviouslyFocusedElement();
+ this.setModalTransformOrigin();
+ return this.portalOutlet.attachComponentPortal(portal);
+ }
+
+ attachTemplatePortal(portal: TemplatePortal): EmbeddedViewRef {
+ if (this.portalOutlet.hasAttached()) {
+ throwNzModalContentAlreadyAttachedError();
+ }
+ this.savePreviouslyFocusedElement();
+ return this.portalOutlet.attachTemplatePortal(portal);
+ }
+
+ getNativeElement(): HTMLElement {
+ return this.elementRef.nativeElement;
+ }
+
+ private animationDisabled(): boolean {
+ return this.config.nzNoAnimation || this.animationType === 'NoopAnimations';
+ }
+
+ private setModalTransformOrigin(): void {
+ const modalElement = this.modalElementRef.nativeElement;
+ if (this.elementFocusedBeforeModalWasOpened as HTMLElement) {
+ const previouslyDOMRect = this.elementFocusedBeforeModalWasOpened!.getBoundingClientRect();
+ const lastPosition = getElementOffset(this.elementFocusedBeforeModalWasOpened!);
+ const x = lastPosition.left + previouslyDOMRect.width / 2;
+ const y = lastPosition.top + previouslyDOMRect.height / 2;
+ const transformOrigin = `${x - modalElement.offsetLeft}px ${y - modalElement.offsetTop}px 0px`;
+ this.render.setStyle(modalElement, 'transform-origin', transformOrigin);
+ }
+ }
+
+ private savePreviouslyFocusedElement(): void {
+ if (this.document) {
+ this.elementFocusedBeforeModalWasOpened = this.document.activeElement as HTMLElement;
+ if (this.elementRef.nativeElement.focus) {
+ Promise.resolve().then(() => this.elementRef.nativeElement.focus());
+ }
+ }
+ }
+
+ private trapFocus(): void {
+ const element = this.elementRef.nativeElement;
+
+ if (!this.focusTrap) {
+ this.focusTrap = this.focusTrapFactory.create(element);
+ }
+
+ if (this.config.nzAutofocus) {
+ this.focusTrap.focusInitialElementWhenReady().then();
+ } else {
+ const activeElement = this.document.activeElement;
+ if (activeElement !== element && !element.contains(activeElement)) {
+ element.focus();
+ }
+ }
+ }
+
+ private restoreFocus(): void {
+ const toFocus = this.elementFocusedBeforeModalWasOpened as HTMLElement;
+
+ // We need the extra check, because IE can set the `activeElement` to null in some cases.
+ if (toFocus && typeof toFocus.focus === 'function') {
+ const activeElement = this.document.activeElement as Element;
+ const element = this.elementRef.nativeElement;
+
+ if (!activeElement || activeElement === this.document.body || activeElement === element || element.contains(activeElement)) {
+ toFocus.focus();
+ }
+ }
+
+ if (this.focusTrap) {
+ this.focusTrap.destroy();
+ }
+ }
+
+ private setEnterAnimationClass(): void {
+ if (this.animationDisabled()) {
+ return;
+ }
+ this.zone.runOutsideAngular(() => {
+ // Make sure to set the `TransformOrigin` style before set the modelElement's class names
+ this.setModalTransformOrigin();
+ const modalElement = this.modalElementRef.nativeElement;
+ const backdropElement = this.overlayRef.backdropElement;
+ this.render.addClass(modalElement, ZOOM_CLASS_NAME_MAP.enter);
+ this.render.addClass(modalElement, ZOOM_CLASS_NAME_MAP.enterActive);
+ this.render.addClass(backdropElement, FADE_CLASS_NAME_MAP.enter);
+ this.render.addClass(backdropElement, FADE_CLASS_NAME_MAP.enterActive);
+ });
+ }
+
+ private setExitAnimationClass(): void {
+ if (this.animationDisabled()) {
+ return;
+ }
+ this.zone.runOutsideAngular(() => {
+ const modalElement = this.modalElementRef.nativeElement;
+ const backdropElement = this.overlayRef.backdropElement;
+ this.render.addClass(modalElement, ZOOM_CLASS_NAME_MAP.leave);
+ this.render.addClass(modalElement, ZOOM_CLASS_NAME_MAP.leaveActive);
+ this.render.addClass(backdropElement, FADE_CLASS_NAME_MAP.leave);
+ this.render.addClass(backdropElement, FADE_CLASS_NAME_MAP.leaveActive);
+ });
+ }
+
+ private cleanAnimationClass(): void {
+ if (this.animationDisabled()) {
+ return;
+ }
+ this.zone.runOutsideAngular(() => {
+ const backdropElement = this.overlayRef.backdropElement;
+ const modalElement = this.modalElementRef.nativeElement;
+ this.render.removeClass(modalElement, ZOOM_CLASS_NAME_MAP.enter);
+ this.render.removeClass(modalElement, ZOOM_CLASS_NAME_MAP.enterActive);
+ this.render.removeClass(modalElement, ZOOM_CLASS_NAME_MAP.leave);
+ this.render.removeClass(modalElement, ZOOM_CLASS_NAME_MAP.leaveActive);
+ this.render.removeClass(backdropElement, FADE_CLASS_NAME_MAP.enter);
+ this.render.removeClass(backdropElement, FADE_CLASS_NAME_MAP.enterActive);
+ });
+ }
+
+ private bindBackdropStyle(): void {
+ this.zone.runOutsideAngular(() => {
+ if (this.oldMaskStyle) {
+ const backdropElement = this.overlayRef.backdropElement;
+ const styles = this.oldMaskStyle as { [key: string]: string };
+ Object.keys(styles).forEach(key => {
+ this.render.removeStyle(backdropElement, key);
+ });
+ this.oldMaskStyle = null;
+ }
+
+ if (typeof this.config.nzMaskStyle === 'object' && Object.keys(this.config.nzMaskStyle).length) {
+ const backdropElement = this.overlayRef.backdropElement;
+ const styles: { [key: string]: string } = { ...this.config.nzMaskStyle };
+ Object.keys(styles).forEach(key => {
+ this.render.setStyle(backdropElement, key, styles[key]);
+ });
+ this.oldMaskStyle = styles;
+ }
+ });
+ }
+
+ /**
+ * Set the container element.
+ * @deprecated Not supported.
+ * @breaking-change 10.0.0
+ */
+ private setContainer(): void {
+ const container = this.getContainer();
+ if (container) {
+ this.render.appendChild(container, this.elementRef.nativeElement);
+ }
+ }
+
+ /**
+ * Reset the container element.
+ * @deprecated Not supported.
+ * @breaking-change 10.0.0
+ */
+ private resetContainer(): void {
+ const container = this.getContainer();
+ if (container) {
+ this.render.appendChild(this.overlayRef.overlayElement, this.elementRef.nativeElement);
+ }
+ }
+
+ private getContainer(): HTMLElement | null {
+ const { nzGetContainer } = this.config;
+ const container = typeof nzGetContainer === 'function' ? nzGetContainer() : nzGetContainer;
+ return container instanceof HTMLElement ? container : null;
+ }
+
+ onAnimationDone(event: AnimationEvent): void {
+ if (event.toState === 'enter') {
+ this.setContainer();
+ this.trapFocus();
+ } else if (event.toState === 'exit') {
+ this.restoreFocus();
+ }
+ this.cleanAnimationClass();
+ this.animationStateChanged.emit(event);
+ }
+
+ onAnimationStart(event: AnimationEvent): void {
+ if (event.toState === 'enter') {
+ this.setEnterAnimationClass();
+ this.bindBackdropStyle();
+ } else if (event.toState === 'exit') {
+ this.resetContainer();
+ this.setExitAnimationClass();
+ }
+ this.animationStateChanged.emit(event);
+ }
+
+ startExitAnimation(): void {
+ this.state = 'exit';
+ this.cdr.markForCheck();
+ }
+}
diff --git a/components/modal/modal-footer.component.ts b/components/modal/modal-footer.component.ts
index 60f099baf8c..8e1288ce9a8 100644
--- a/components/modal/modal-footer.component.ts
+++ b/components/modal/modal-footer.component.ts
@@ -6,15 +6,15 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/
-import { ChangeDetectionStrategy, Component, EventEmitter, OnDestroy, Output } from '@angular/core';
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core';
+import { NzModalRef } from 'ng-zorro-antd';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { isPromise } from 'ng-zorro-antd/core';
import { NzI18nService } from 'ng-zorro-antd/i18n';
-import { NzModalContainerComponent } from './modal-container.component';
-import { ModalButtonOptions, ModalConfig } from './nz-modal.type';
+import { ModalButtonOptions, ModalOptions } from './modal-types';
@Component({
selector: 'div[nz-modal-footer]',
@@ -78,10 +78,10 @@ export class NzModalFooterComponent implements OnDestroy {
locale: { okText?: string; cancelText?: string } = {};
@Output() readonly cancelTriggered = new EventEmitter();
@Output() readonly okTriggered = new EventEmitter();
-
+ @Input() modalRef: NzModalRef;
private destroy$ = new Subject();
- constructor(private i18n: NzI18nService, private modalContainer: NzModalContainerComponent, public config: ModalConfig) {
+ constructor(private i18n: NzI18nService, public config: ModalOptions) {
if (Array.isArray(config.nzFooter)) {
this.buttonsFooter = true;
this.buttons = (config.nzFooter as ModalButtonOptions[]).map(mergeDefaultOption);
@@ -107,7 +107,7 @@ export class NzModalFooterComponent implements OnDestroy {
*/
getButtonCallableProp(options: ModalButtonOptions, prop: keyof ModalButtonOptions): boolean {
const value = options[prop];
- const componentInstance = this.modalContainer.modalRef.getContentComponent();
+ const componentInstance = this.modalRef.getContentComponent();
return typeof value === 'function' ? value.apply(options, componentInstance && [componentInstance]) : value;
}
diff --git a/components/modal/nz-modal-footer.directive.spec.ts b/components/modal/modal-footer.directive.spec.ts
similarity index 95%
rename from components/modal/nz-modal-footer.directive.spec.ts
rename to components/modal/modal-footer.directive.spec.ts
index dbbb9be4b27..73ceabb939b 100644
--- a/components/modal/nz-modal-footer.directive.spec.ts
+++ b/components/modal/modal-footer.directive.spec.ts
@@ -4,8 +4,8 @@ import { async, ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angu
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
-import { NzModalModule } from './nz-modal.module';
-import { NzModalService } from './nz-modal.service';
+import { NzModalModule } from './modal.module';
+import { NzModalService } from './modal.service';
describe('modal footer directive', () => {
let overlayContainer: OverlayContainer;
diff --git a/components/modal/nz-modal-footer.directive.ts b/components/modal/modal-footer.directive.ts
similarity index 78%
rename from components/modal/nz-modal-footer.directive.ts
rename to components/modal/modal-footer.directive.ts
index 3215efd06da..ae4dc5727d7 100644
--- a/components/modal/nz-modal-footer.directive.ts
+++ b/components/modal/modal-footer.directive.ts
@@ -7,14 +7,14 @@
*/
import { Directive, Optional, TemplateRef } from '@angular/core';
-import { NzModalRef2 } from './nz-modal-ref';
+import { NzModalRef } from './modal-ref';
@Directive({
selector: '[nzModalFooter]',
exportAs: 'nzModalFooter'
})
export class NzModalFooterDirective {
- constructor(@Optional() private nzModalRef: NzModalRef2, public templateRef: TemplateRef<{}>) {
+ constructor(@Optional() private nzModalRef: NzModalRef, public templateRef: TemplateRef<{}>) {
if (this.nzModalRef) {
this.nzModalRef.updateConfig({
nzFooter: this.templateRef
diff --git a/components/modal/nz-modal-ref.ts b/components/modal/modal-ref.ts
similarity index 91%
rename from components/modal/nz-modal-ref.ts
rename to components/modal/modal-ref.ts
index 8b969451c2c..05ac56f7336 100644
--- a/components/modal/nz-modal-ref.ts
+++ b/components/modal/modal-ref.ts
@@ -13,8 +13,8 @@ import { filter, take } from 'rxjs/operators';
import { isPromise } from 'ng-zorro-antd/core';
-import { ModalConfig } from 'ng-zorro-antd/modal/nz-modal.type';
-import { NzModalContainerComponent } from './modal-container.component';
+import { ModalOptions } from 'ng-zorro-antd/modal/modal-types';
+import { BaseModalContainer } from './modal-container';
import { NzModalLegacyAPI } from './modal-legacy-api';
export const enum NzModalState {
@@ -29,7 +29,7 @@ export const enum NzTriggerAction {
}
// tslint:disable-next-line:no-any
-export class NzModalRef2 implements NzModalLegacyAPI {
+export class NzModalRef implements NzModalLegacyAPI {
componentInstance: T | null;
result?: R;
state: NzModalState = NzModalState.OPEN;
@@ -38,7 +38,7 @@ export class NzModalRef2 implements NzModalLegacyAPI {
private closeTimeout: number;
- constructor(private overlayRef: OverlayRef, private config: ModalConfig, public containerInstance: NzModalContainerComponent) {
+ constructor(private overlayRef: OverlayRef, private config: ModalOptions, public containerInstance: BaseModalContainer) {
containerInstance.animationStateChanged
.pipe(
filter(event => event.phaseName === 'done' && event.toState === 'enter'),
@@ -150,14 +150,6 @@ export class NzModalRef2 implements NzModalLegacyAPI {
this.state = NzModalState.CLOSING;
}
- updateSize(width: string = '', height: string = ''): this {
- this.getPositionStrategy()
- .width(width)
- .height(height);
- this.overlayRef.updatePosition();
- return this;
- }
-
updatePosition(): this {
const strategy = this.getPositionStrategy();
strategy.centerHorizontally();
@@ -166,7 +158,7 @@ export class NzModalRef2 implements NzModalLegacyAPI {
return this;
}
- updateConfig(config: ModalConfig): void {
+ updateConfig(config: ModalOptions): void {
Object.assign(this.config, config);
}
diff --git a/components/modal/modal-title.component.ts b/components/modal/modal-title.component.ts
index 9aecdba6d89..f242396ba28 100644
--- a/components/modal/modal-title.component.ts
+++ b/components/modal/modal-title.component.ts
@@ -8,7 +8,7 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { ModalConfig } from './nz-modal.type';
+import { ModalOptions } from './modal-types';
@Component({
selector: 'div[nz-modal-title]',
@@ -26,5 +26,5 @@ import { ModalConfig } from './nz-modal.type';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NzModalTitleComponent {
- constructor(public config: ModalConfig) {}
+ constructor(public config: ModalOptions) {}
}
diff --git a/components/modal/nz-modal.type.ts b/components/modal/modal-types.ts
similarity index 62%
rename from components/modal/nz-modal.type.ts
rename to components/modal/modal-types.ts
index 2f5c1b8aa61..22f199a1146 100644
--- a/components/modal/nz-modal.type.ts
+++ b/components/modal/modal-types.ts
@@ -12,7 +12,7 @@ import { NzButtonShape, NzButtonSize, NzButtonType } from 'ng-zorro-antd/button'
export type OnClickCallback = (instance: T) => (false | void | {}) | Promise;
-export type ModalType = 'default' | 'confirm'; // Different modal styles we have supported
+export type ModalTypes = 'default' | 'confirm'; // Different modal styles we have supported
export type ConfirmType = 'confirm' | 'info' | 'success' | 'error' | 'warning'; // Subtypes of Confirm Modal
@@ -23,7 +23,7 @@ export interface StyleObjectLike {
const noopFun = () => void 0;
// tslint:disable-next-line:no-any
-export class ModalConfig implements ModalOptions {
+export class ModalOptions {
nzClosable?: boolean = true;
nzOkLoading?: boolean = false;
nzOkDisabled?: boolean = false;
@@ -38,7 +38,7 @@ export class ModalConfig implements ModalOptions {
nzWidth?: number | string = 520;
nzCloseIcon?: string | TemplateRef = 'close';
nzOkType?: NzButtonType = 'primary';
- nzModalType?: ModalType = 'default';
+ nzModalType?: ModalTypes = 'default';
nzOnCancel?: EventEmitter | OnClickCallback = noopFun;
nzOnOk?: EventEmitter | OnClickCallback = noopFun;
nzComponentParams?: Partial;
@@ -68,52 +68,6 @@ export class ModalConfig implements ModalOptions {
nzIconType?: string = 'question-circle';
}
-// Public options for using by service
-// tslint:disable-next-line:no-any
-export interface ModalOptions {
- nzModalType?: ModalType;
- nzVisible?: boolean;
- nzZIndex?: number;
- nzWidth?: number | string;
- nzWrapClassName?: string;
- nzClassName?: string;
- nzStyle?: object;
- nzIconType?: string; // Confirm Modal ONLY
- nzTitle?: string | TemplateRef<{}>;
- nzCloseIcon?: string | TemplateRef;
- nzContent?: string | TemplateRef<{}> | Type;
- nzComponentParams?: Partial;
- nzClosable?: boolean;
- nzKeyboard?: boolean;
- nzMask?: boolean;
- nzMaskClosable?: boolean;
- nzMaskStyle?: StyleObjectLike;
- nzBodyStyle?: StyleObjectLike;
- nzFooter?: string | TemplateRef<{}> | Array> | null; // Default Modal ONLY
- nzGetContainer?: HTMLElement | OverlayRef | (() => HTMLElement | OverlayRef); // STATIC
- nzAfterOpen?: EventEmitter;
- nzAfterClose?: EventEmitter;
-
- // --- Predefined OK & Cancel buttons
- nzOkText?: string | null;
- nzOkType?: NzButtonType;
- nzOkLoading?: boolean;
- nzOkDisabled?: boolean;
- nzCancelDisabled?: boolean;
- nzOnOk?: EventEmitter | OnClickCallback; // Mixed using ng's Input/Output (Should care of "this" when using OnClickCallback)
- nzCancelText?: string | null;
- nzCancelLoading?: boolean;
- nzNoAnimation?: boolean;
- nzOnCancel?: EventEmitter | OnClickCallback; // Mixed using ng's Input/Output (Should care of "this" when using OnClickCallback)
-}
-
-// tslint:disable-next-line:no-any
-export interface ModalOptionsForService extends ModalOptions {
- // Limitations for using by service
- nzOnOk?: OnClickCallback;
- nzOnCancel?: OnClickCallback;
-}
-
// tslint:disable-next-line:no-any
export interface ModalButtonOptions {
label: string;
@@ -129,7 +83,6 @@ export interface ModalButtonOptions {
disabled?: boolean | ((this: ModalButtonOptions, contentComponentInstance?: T) => boolean);
// tslint:disable-next-line:no-any
onClick?(this: ModalButtonOptions, contentComponentInstance?: T): any | Promise;
-
// tslint:disable-next-line:no-any
[key: string]: any;
}
diff --git a/components/modal/modal.component.ts b/components/modal/modal.component.ts
index efcd7447a14..5ea08d3266c 100644
--- a/components/modal/modal.component.ts
+++ b/components/modal/modal.component.ts
@@ -26,25 +26,25 @@ import { NzButtonType } from 'ng-zorro-antd/button';
import { InputBoolean, NzConfigService, WithConfig } from 'ng-zorro-antd/core';
import { Observable } from 'rxjs';
+import { NzModalFooterDirective } from './modal-footer.directive';
import { NzModalLegacyAPI } from './modal-legacy-api';
-import { NzModal } from './nz-modal';
-import { NzModalFooterDirective } from './nz-modal-footer.directive';
-import { NzModalRef2 } from './nz-modal-ref';
-import { ModalButtonOptions, ModalConfig, ModalType, OnClickCallback, StyleObjectLike } from './nz-modal.type';
+import { NzModalRef } from './modal-ref';
+import { ModalButtonOptions, ModalOptions, ModalTypes, OnClickCallback, StyleObjectLike } from './modal-types';
+import { NzModalService } from './modal.service';
import { getConfigFromComponent } from './utils';
const NZ_CONFIG_COMPONENT_NAME = 'modal';
@Component({
- selector: 'nz-modal2',
- exportAs: 'nzModal2',
+ selector: 'nz-modal',
+ exportAs: 'nzModal',
template: `
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
// tslint:disable-next-line:no-any
-export class NzModal2Component implements OnChanges, NzModalLegacyAPI {
+export class NzModalComponent implements OnChanges, NzModalLegacyAPI {
@Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME, true) @InputBoolean() nzMask: boolean;
@Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME, true) @InputBoolean() nzMaskClosable: boolean;
@Input() @InputBoolean() nzVisible: boolean = false;
@@ -72,7 +72,7 @@ export class NzModal2Component implements OnChanges, NzModalLe
@Input() nzCancelText: string | null;
@Input() nzOkType: NzButtonType = 'primary';
@Input() nzIconType: string = 'question-circle'; // Confirm Modal ONLY
- @Input() nzModalType: ModalType = 'default';
+ @Input() nzModalType: ModalTypes = 'default';
@Input()
@Output()
@@ -92,7 +92,7 @@ export class NzModal2Component implements OnChanges, NzModalLe
this.setFooterWithTemplate(value.templateRef);
}
}
- private modalRef: NzModalRef2 | null = null;
+ private modalRef: NzModalRef | null = null;
get afterOpen(): Observable {
// Observable alias for nzAfterOpen
@@ -104,7 +104,7 @@ export class NzModal2Component implements OnChanges, NzModalLe
return this.nzAfterClose.asObservable();
}
- constructor(public nzConfigService: NzConfigService, private cdr: ChangeDetectorRef, private modal: NzModal) {}
+ constructor(public nzConfigService: NzConfigService, private cdr: ChangeDetectorRef, private modal: NzModalService) {}
open(): void {
if (!this.modalRef) {
@@ -153,7 +153,7 @@ export class NzModal2Component implements OnChanges, NzModalLe
this.cdr.markForCheck();
}
- private getConfig(): ModalConfig {
+ private getConfig(): ModalOptions {
const componentConfig = getConfigFromComponent(this);
if (!this.nzContent) {
componentConfig.nzContent = this.contentTemplateRef;
diff --git a/components/modal/nz-modal.module.ts b/components/modal/modal.module.ts
similarity index 69%
rename from components/modal/nz-modal.module.ts
rename to components/modal/modal.module.ts
index 6636d0e20d7..ab22a969420 100644
--- a/components/modal/nz-modal.module.ts
+++ b/components/modal/modal.module.ts
@@ -20,12 +20,10 @@ import { NzModalCloseComponent } from './modal-close.component';
import { NzModalConfirmContainerComponent } from './modal-confirm-container.component';
import { NzModalContainerComponent } from './modal-container.component';
import { NzModalFooterComponent } from './modal-footer.component';
+import { NzModalFooterDirective } from './modal-footer.directive';
import { NzModalTitleComponent } from './modal-title.component';
-import { NzModal2Component } from './modal.component';
-import { NzModalControlServiceModule } from './nz-modal-control.service.module';
-import { NzModalFooterDirective } from './nz-modal-footer.directive';
-import { NzModalComponent } from './nz-modal.component';
-import { NzModalServiceModule } from './nz-modal.service.module';
+import { NzModalComponent } from './modal.component';
+import { NzModalService } from './modal.service';
@NgModule({
imports: [
@@ -37,11 +35,10 @@ import { NzModalServiceModule } from './nz-modal.service.module';
NzButtonModule,
NzIconModule,
NzPipesModule,
- NzNoAnimationModule,
- NzModalServiceModule,
- NzModalControlServiceModule
+ NzNoAnimationModule
],
- exports: [NzModalComponent, NzModal2Component, NzModalFooterDirective, NzModalContainerComponent, NzModalConfirmContainerComponent],
+ exports: [NzModalComponent, NzModalFooterDirective],
+ providers: [NzModalService],
declarations: [
NzModalComponent,
NzModalFooterDirective,
@@ -50,8 +47,7 @@ import { NzModalServiceModule } from './nz-modal.service.module';
NzModalTitleComponent,
NzModalContainerComponent,
NzModalConfirmContainerComponent,
- NzModal2Component
- ],
- entryComponents: [NzModalComponent, NzModalContainerComponent]
+ NzModalComponent
+ ]
})
export class NzModalModule {}
diff --git a/components/modal/nz-modal.ts b/components/modal/modal.service.ts
similarity index 70%
rename from components/modal/nz-modal.ts
rename to components/modal/modal.service.ts
index f3f42fd25f0..67b8ad69b96 100644
--- a/components/modal/nz-modal.ts
+++ b/components/modal/modal.service.ts
@@ -9,28 +9,27 @@
import { ComponentType, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal, PortalInjector, TemplatePortal } from '@angular/cdk/portal';
import { Injectable, Injector, OnDestroy, Optional, SkipSelf, TemplateRef } from '@angular/core';
-import { IndexableObject, warn } from 'ng-zorro-antd/core';
-import { NzModalConfirmContainerComponent } from 'ng-zorro-antd/modal/modal-confirm-container.component';
-import { applyConfigDefaults, setContentInstanceParams } from 'ng-zorro-antd/modal/utils';
import { defer, Observable, Subject } from 'rxjs';
import { startWith } from 'rxjs/operators';
+import { IndexableObject, warn } from 'ng-zorro-antd/core';
+
+import { NzModalConfirmContainerComponent } from './modal-confirm-container.component';
+import { BaseModalContainer } from './modal-container';
import { NzModalContainerComponent } from './modal-container.component';
-import { NzModalRef2 } from './nz-modal-ref';
-import { NzModalServiceModule } from './nz-modal.service.module';
-import { ConfirmType, ModalConfig } from './nz-modal.type';
+import { NzModalRef } from './modal-ref';
+import { ConfirmType, ModalOptions } from './modal-types';
+import { applyConfigDefaults, setContentInstanceParams } from './utils';
const MODAL_MASK_CLASS_NAME = 'ant-modal-mask';
type ContentType = ComponentType | TemplateRef | string;
-@Injectable({
- providedIn: NzModalServiceModule
-})
-export class NzModal implements OnDestroy {
- private openModalsAtThisLevel: NzModalRef2[] = [];
+@Injectable()
+export class NzModalService implements OnDestroy {
+ private openModalsAtThisLevel: NzModalRef[] = [];
private readonly afterAllClosedAtThisLevel = new Subject();
- get openModals(): NzModalRef2[] {
+ get openModals(): NzModalRef[] {
return this.parentModal ? this.parentModal.openModals : this.openModalsAtThisLevel;
}
@@ -43,31 +42,18 @@ export class NzModal implements OnDestroy {
this.openModals.length ? this._afterAllClosed : this._afterAllClosed.pipe(startWith(undefined))
) as Observable;
- constructor(private overlay: Overlay, private injector: Injector, @Optional() @SkipSelf() private parentModal: NzModal) {}
+ constructor(private overlay: Overlay, private injector: Injector, @Optional() @SkipSelf() private parentModal: NzModalService) {}
// tslint:disable-next-line:no-any
- create(config: ModalConfig): NzModalRef2 {
+ create(config: ModalOptions): NzModalRef {
return this.open(config.nzContent as ComponentType, config);
}
- open(componentOrTemplateRef: ContentType, config?: ModalConfig): NzModalRef2 {
- const configMerged = applyConfigDefaults(config || {}, new ModalConfig());
- const overlayRef = this.createOverlay(configMerged);
- const modalContainer = this.attachModalContainer(overlayRef, configMerged);
- const modalRef = this.attachModalContent(componentOrTemplateRef, modalContainer, overlayRef, configMerged);
- modalContainer.modalRef = modalRef;
-
- this.openModals.push(modalRef);
- modalRef.afterClose.subscribe(() => this.removeOpenModal(modalRef));
-
- return modalRef;
- }
-
closeAll(): void {
this.closeModals(this.openModals);
}
- confirm(options: ModalConfig = {}, confirmType: ConfirmType = 'confirm'): NzModalRef2 {
+ confirm(options: ModalOptions = {}, confirmType: ConfirmType = 'confirm'): NzModalRef {
if ('nzFooter' in options) {
warn(`The Confirm-Modal doesn't support "nzFooter", this property will be ignored.`);
}
@@ -83,30 +69,43 @@ export class NzModal implements OnDestroy {
return this.create(options);
}
- info(options: ModalConfig = {}): NzModalRef2 {
+ info(options: ModalOptions = {}): NzModalRef {
return this.confirmFactory(options, 'info');
}
- success(options: ModalConfig = {}): NzModalRef2 {
+ success(options: ModalOptions = {}): NzModalRef {
return this.confirmFactory(options, 'success');
}
- error(options: ModalConfig = {}): NzModalRef2 {
+ error(options: ModalOptions = {}): NzModalRef {
return this.confirmFactory(options, 'error');
}
- warning(options: ModalConfig = {}): NzModalRef2 {
+ warning(options: ModalOptions = {}): NzModalRef {
return this.confirmFactory(options, 'warning');
}
- private removeOpenModal(modalRef: NzModalRef2): void {
+ private open(componentOrTemplateRef: ContentType, config?: ModalOptions): NzModalRef {
+ const configMerged = applyConfigDefaults(config || {}, new ModalOptions());
+ const overlayRef = this.createOverlay(configMerged);
+ const modalContainer = this.attachModalContainer(overlayRef, configMerged);
+ const modalRef = this.attachModalContent(componentOrTemplateRef, modalContainer, overlayRef, configMerged);
+ modalContainer.modalRef = modalRef;
+
+ this.openModals.push(modalRef);
+ modalRef.afterClose.subscribe(() => this.removeOpenModal(modalRef));
+
+ return modalRef;
+ }
+
+ private removeOpenModal(modalRef: NzModalRef): void {
const index = this.openModals.indexOf(modalRef);
if (index > -1) {
this.openModals.splice(index);
}
}
- private closeModals(dialogs: NzModalRef2[]): void {
+ private closeModals(dialogs: NzModalRef[]): void {
let i = dialogs.length;
while (i--) {
dialogs[i].close();
@@ -116,7 +115,7 @@ export class NzModal implements OnDestroy {
}
}
- private createOverlay(config: ModalConfig): OverlayRef {
+ private createOverlay(config: ModalOptions): OverlayRef {
const overlayConfig = new OverlayConfig({
hasBackdrop: true,
scrollStrategy: this.overlay.scrollStrategies.block(),
@@ -130,37 +129,37 @@ export class NzModal implements OnDestroy {
return this.overlay.create(overlayConfig);
}
- private attachModalContainer(overlayRef: OverlayRef, config: ModalConfig): NzModalContainerComponent {
+ private attachModalContainer(overlayRef: OverlayRef, config: ModalOptions): BaseModalContainer {
const injector = new PortalInjector(
this.injector,
// tslint:disable-next-line:no-any
new WeakMap([
[OverlayRef, overlayRef],
- [ModalConfig, config]
+ [ModalOptions, config]
])
);
- const containerPortal = new ComponentPortal(
+ console.log(config.nzModalType);
+ const ComponentClass =
config.nzModalType === 'confirm'
? // If the mode is `confirm`, use `NzModalConfirmContainerComponent`
NzModalConfirmContainerComponent
: // If the mode is not `confirm`, use `NzModalContainerComponent`
- NzModalContainerComponent,
- undefined,
- injector
- );
- const containerRef = overlayRef.attach(containerPortal);
+ NzModalContainerComponent;
+
+ const containerPortal = new ComponentPortal(ComponentClass, undefined, injector);
+ const containerRef = overlayRef.attach(containerPortal);
return containerRef.instance;
}
private attachModalContent(
componentOrTemplateRef: ContentType,
- modalContainer: NzModalContainerComponent,
+ modalContainer: BaseModalContainer,
overlayRef: OverlayRef,
- config: ModalConfig
- ): NzModalRef2 {
- const modalRef = new NzModalRef2(overlayRef, config, modalContainer);
+ config: ModalOptions
+ ): NzModalRef {
+ const modalRef = new NzModalRef(overlayRef, config, modalContainer);
if (componentOrTemplateRef instanceof TemplateRef) {
modalContainer.attachTemplatePortal(
@@ -168,26 +167,22 @@ export class NzModal implements OnDestroy {
new TemplatePortal(componentOrTemplateRef, null!, { $implicit: modalRef } as any)
);
} else if (typeof componentOrTemplateRef !== 'string') {
- const injector = this.createInjector(modalRef, modalContainer);
+ const injector = this.createInjector(modalRef);
const contentRef = modalContainer.attachComponentPortal(new ComponentPortal(componentOrTemplateRef, undefined, injector));
setContentInstanceParams(contentRef.instance, config.nzComponentParams);
modalRef.componentInstance = contentRef.instance;
}
- modalRef.updateSize('520px').updatePosition();
return modalRef;
}
- private createInjector(modalRef: NzModalRef2, modalContainer: NzModalContainerComponent): PortalInjector {
+ private createInjector(modalRef: NzModalRef): PortalInjector {
// tslint:disable-next-line:no-any
- const injectionTokens = new WeakMap([
- [NzModalContainerComponent, modalContainer],
- [NzModalRef2, modalRef]
- ]);
+ const injectionTokens = new WeakMap([[NzModalRef, modalRef]]);
return new PortalInjector(this.injector, injectionTokens);
}
- private confirmFactory(options: ModalConfig = {}, confirmType: ConfirmType): NzModalRef2 {
+ private confirmFactory(options: ModalOptions = {}, confirmType: ConfirmType): NzModalRef {
const iconMap: IndexableObject = {
info: 'info-circle',
success: 'check-circle',
diff --git a/components/modal/modal.spec.ts b/components/modal/modal.spec.ts
new file mode 100644
index 00000000000..7fc4dcb2701
--- /dev/null
+++ b/components/modal/modal.spec.ts
@@ -0,0 +1 @@
+describe('NzModal', () => {});
diff --git a/components/modal/nz-modal-control.service.module.ts b/components/modal/nz-modal-control.service.module.ts
deleted file mode 100644
index 407ff91cc52..00000000000
--- a/components/modal/nz-modal-control.service.module.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * @license
- * Copyright Alibaba.com All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
- */
-
-import { NgModule } from '@angular/core';
-
-@NgModule()
-export class NzModalControlServiceModule {}
diff --git a/components/modal/nz-modal-control.service.ts b/components/modal/nz-modal-control.service.ts
deleted file mode 100644
index 2a99e364910..00000000000
--- a/components/modal/nz-modal-control.service.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * @license
- * Copyright Alibaba.com All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
- */
-
-import { Injectable, Optional, SkipSelf } from '@angular/core';
-import { Subject, Subscription } from 'rxjs';
-
-import { NzModalControlServiceModule } from './nz-modal-control.service.module';
-import { NzModalRef } from './nz-modal-ref.class';
-
-interface RegisteredMeta {
- modalRef: NzModalRef;
- afterOpenSubscription: Subscription;
- afterCloseSubscription: Subscription;
-}
-
-@Injectable({
- providedIn: NzModalControlServiceModule
-})
-export class NzModalControlService {
- // Track singleton afterAllClose through over the injection tree
- get afterAllClose(): Subject {
- return this.parentService ? this.parentService.afterAllClose : this.rootAfterAllClose!;
- }
-
- // Track singleton openModals array through over the injection tree
- get openModals(): NzModalRef[] {
- return this.parentService ? this.parentService.openModals : this.rootOpenModals!;
- }
-
- private rootOpenModals: NzModalRef[] | null = this.parentService ? null : [];
- private rootAfterAllClose: Subject | null = this.parentService ? null : new Subject();
- private rootRegisteredMetaMap: Map | null = this.parentService ? null : new Map();
-
- private get registeredMetaMap(): Map {
- // Registered modal for later usage
- return this.parentService ? this.parentService.registeredMetaMap : this.rootRegisteredMetaMap!;
- }
-
- constructor(@Optional() @SkipSelf() private parentService: NzModalControlService) {}
-
- // Register a modal to listen its open/close
- registerModal(modalRef: NzModalRef): void {
- if (!this.hasRegistered(modalRef)) {
- const afterOpenSubscription = modalRef.afterOpen.subscribe(() => this.openModals.push(modalRef));
- const afterCloseSubscription = modalRef.afterClose.subscribe(() => this.removeOpenModal(modalRef));
-
- this.registeredMetaMap.set(modalRef, { modalRef, afterOpenSubscription, afterCloseSubscription });
- }
- }
-
- // deregister modals
- deregisterModal(modalRef: NzModalRef): void {
- const registeredMeta = this.registeredMetaMap.get(modalRef);
- if (registeredMeta) {
- // Remove this modal if it is still in the opened modal list (NOTE: it may trigger "afterAllClose")
- this.removeOpenModal(registeredMeta.modalRef);
- registeredMeta.afterOpenSubscription.unsubscribe();
- registeredMeta.afterCloseSubscription.unsubscribe();
- this.registeredMetaMap.delete(modalRef);
- }
- }
-
- hasRegistered(modalRef: NzModalRef): boolean {
- return this.registeredMetaMap.has(modalRef);
- }
-
- // Close all registered opened modals
- closeAll(): void {
- let i = this.openModals.length;
-
- while (i--) {
- this.openModals[i].close();
- }
- }
-
- private removeOpenModal(modalRef: NzModalRef): void {
- const index = this.openModals.indexOf(modalRef);
-
- if (index > -1) {
- this.openModals.splice(index, 1);
-
- if (!this.openModals.length) {
- this.afterAllClose.next();
- }
- }
- }
-}
diff --git a/components/modal/nz-modal-ref.class.ts b/components/modal/nz-modal-ref.class.ts
deleted file mode 100644
index 99b9f65c29d..00000000000
--- a/components/modal/nz-modal-ref.class.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * @license
- * Copyright Alibaba.com All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
- */
-
-import { Observable } from 'rxjs';
-
-import { NzModalComponent } from './nz-modal.component';
-
-/**
- * API class that public to users to handle the modal instance.
- * NzModalRef is aim to avoid accessing to the modal instance directly by users.
- */
-// tslint:disable-next-line:no-any
-export abstract class NzModalRef {
- abstract afterOpen: Observable;
- abstract afterClose: Observable;
-
- abstract open(): void;
- abstract close(result?: R): void;
- abstract destroy(result?: R): void;
-
- /**
- * Trigger the nzOnOk/nzOnCancel by manual
- */
- abstract triggerOk(): void;
- abstract triggerCancel(): void;
-
- // /**
- // * Return the ComponentRef of nzContent when specify nzContent as a Component
- // * Note: this method may return undefined if the Component has not ready yet. (it only available after Modal's ngOnInit)
- // */
- // abstract getContentComponentRef(): ComponentRef<{}>;
-
- /**
- * Return the component instance of nzContent when specify nzContent as a Component
- * Note: this method may return undefined if the Component has not ready yet. (it only available after Modal's ngOnInit)
- */
- abstract getContentComponent(): T;
-
- /**
- * Get the dom element of this Modal
- */
- abstract getElement(): HTMLElement;
-
- /**
- * Get the instance of the Modal itself
- */
- abstract getInstance(): NzModalComponent;
-}
diff --git a/components/modal/nz-modal.component.html b/components/modal/nz-modal.component.html
deleted file mode 100644
index 08d419da643..00000000000
--- a/components/modal/nz-modal.component.html
+++ /dev/null
@@ -1,198 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/components/modal/nz-modal.component.ts b/components/modal/nz-modal.component.ts
deleted file mode 100644
index 79bfa19713a..00000000000
--- a/components/modal/nz-modal.component.ts
+++ /dev/null
@@ -1,575 +0,0 @@
-/**
- * @license
- * Copyright Alibaba.com All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
- */
-
-import { FocusTrap, FocusTrapFactory } from '@angular/cdk/a11y';
-
-import { ESCAPE } from '@angular/cdk/keycodes';
-import { BlockScrollStrategy, Overlay, OverlayKeyboardDispatcher, OverlayRef } from '@angular/cdk/overlay';
-import { DOCUMENT } from '@angular/common';
-import {
- AfterViewInit,
- ChangeDetectionStrategy,
- ChangeDetectorRef,
- Component,
- ComponentFactoryResolver,
- ComponentRef,
- ContentChild,
- ElementRef,
- EventEmitter,
- Inject,
- Injector,
- Input,
- OnChanges,
- OnDestroy,
- OnInit,
- Optional,
- Output,
- SimpleChanges,
- TemplateRef,
- Type,
- ViewChild,
- ViewContainerRef
-} from '@angular/core';
-
-import { fromEvent, Observable, Subject } from 'rxjs';
-import { takeUntil } from 'rxjs/operators';
-
-import { getElementOffset, InputBoolean, isPromise, NzConfigService, warnDeprecation, WithConfig } from 'ng-zorro-antd/core';
-import { NzI18nService } from 'ng-zorro-antd/i18n';
-
-import { NZ_MODAL_CONFIG, NzModalConfig } from './nz-modal-config';
-import { NzModalControlService } from './nz-modal-control.service';
-import { NzModalFooterDirective } from './nz-modal-footer.directive';
-import { NzModalRef } from './nz-modal-ref.class';
-import { ModalButtonOptions, ModalOptions, ModalType, OnClickCallback } from './nz-modal.type';
-
-export const MODAL_ANIMATE_DURATION = 200; // Duration when perform animations (ms)
-export const WRAP_CLASS_NAME = 'ant-modal-wrap';
-
-type AnimationState = 'enter' | 'leave' | null;
-
-const NZ_CONFIG_COMPONENT_NAME = 'modal';
-
-@Component({
- selector: 'nz-modal',
- exportAs: 'nzModal',
- templateUrl: './nz-modal.component.html',
- // Using OnPush for modal caused footer can not to detect changes. we can fix it when 8.x.
- changeDetection: ChangeDetectionStrategy.Default
-})
-
-// tslint:disable-next-line:no-any
-export class NzModalComponent extends NzModalRef
- implements OnInit, OnChanges, AfterViewInit, OnDestroy, ModalOptions {
- @Input() @InputBoolean() nzVisible: boolean = false;
- @Input() @InputBoolean() nzClosable: 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;
-
- // TODO(hsuanxyz): add default value once old API is deprecated.
- @Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME) @InputBoolean() nzMask: boolean;
- @Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME) @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
- @Input() nzGetContainer: HTMLElement | OverlayRef | (() => HTMLElement | OverlayRef) = () => this.overlay.create(); // [STATIC]
- @Input() nzZIndex: number = 1000;
- @Input() nzWidth: number | string = 520;
- @Input() nzWrapClassName: string;
- @Input() nzClassName: string;
- @Input() nzStyle: object;
- @Input() nzTitle: string | TemplateRef<{}>;
- @Input() nzCloseIcon: string | TemplateRef = 'close';
- @Input() nzMaskStyle: object;
- @Input() nzBodyStyle: object;
- @Input() nzOkText: string | null;
- @Input() nzCancelText: string | null;
- @Input() nzOkType: string = 'primary';
- @Input() nzIconType: string = 'question-circle'; // Confirm Modal ONLY
- @Input() nzModalType: ModalType = 'default';
-
- @Input() @Output() readonly nzOnOk: EventEmitter | OnClickCallback = new EventEmitter();
- @Input() @Output() readonly nzOnCancel: EventEmitter | OnClickCallback = new EventEmitter();
-
- @Output() readonly nzAfterOpen = new EventEmitter(); // Trigger when modal open(visible) after animations
- @Output() readonly nzAfterClose = new EventEmitter(); // Trigger when modal leave-animation over
- @Output() readonly nzVisibleChange = new EventEmitter();
-
- @ViewChild('modalContainer', { static: true }) modalContainer: ElementRef;
- @ViewChild('bodyContainer', { static: false, read: ViewContainerRef }) bodyContainer: ViewContainerRef;
- @ViewChild('autoFocusButtonOk', { static: false, read: ElementRef }) autoFocusButtonOk: ElementRef; // Only aim to focus the ok button that needs to be auto focused
-
- @ContentChild(NzModalFooterDirective, { static: false })
- set modalFooter(value: NzModalFooterDirective) {
- if (value && value.templateRef) {
- this.setFooterWithTemplate(value.templateRef);
- }
- }
-
- get afterOpen(): Observable {
- // Observable alias for nzAfterOpen
- return this.nzAfterOpen.asObservable();
- }
-
- get afterClose(): Observable {
- // Observable alias for nzAfterClose
- return this.nzAfterClose.asObservable();
- }
-
- get cancelText(): string {
- return this.nzCancelText || this.locale.cancelText!;
- }
-
- get okText(): string {
- return this.nzOkText || this.locale.okText!;
- }
-
- get hidden(): boolean {
- 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;
- transformOrigin = '0px 0px 0px'; // The origin point that animation based on
-
- private contentComponentRef: ComponentRef; // Handle the reference when using nzContent as Component
- private animationState: AnimationState; // Current animation state
- private container: HTMLElement | OverlayRef;
- private unsubscribe$ = new Subject();
- private previouslyFocusedElement: HTMLElement;
- private focusTrap: FocusTrap;
- private scrollStrategy: BlockScrollStrategy;
- private overlayRef: OverlayRef;
- private dialogMouseDown = false;
- private timeoutId: number;
-
- [key: string]: any; // tslint:disable-line:no-any
-
- constructor(
- public nzConfigService: NzConfigService,
- private overlay: Overlay,
- private overlayKeyboardDispatcher: OverlayKeyboardDispatcher,
- private i18n: NzI18nService,
- private cfr: ComponentFactoryResolver,
- private elementRef: ElementRef,
- private viewContainer: ViewContainerRef,
- private modalControl: NzModalControlService,
- private focusTrapFactory: FocusTrapFactory,
- private cdr: ChangeDetectorRef,
- @Optional() @Inject(NZ_MODAL_CONFIG) private nzModalGlobalConfig: NzModalConfig,
- @Inject(DOCUMENT) private document: any // tslint:disable-line:no-any
- ) {
- super();
- this.scrollStrategy = this.overlay.scrollStrategies.block();
-
- if (this.nzModalGlobalConfig) {
- warnDeprecation('`NZ_MODAL_CONFIG` has been deprecated and will be removed in 9.0.0. Please use global config instead.');
- }
- }
-
- ngOnInit(): void {
- this.i18n.localeChange.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {
- this.locale = this.i18n.getLocaleData('Modal');
- });
-
- if (this.isComponent(this.nzContent)) {
- this.createDynamicComponent(this.nzContent as Type); // Create component along without View
- }
-
- if (this.isModalButtons(this.nzFooter)) {
- // Setup default button options
- this.nzFooter = this.formatModalButtons(this.nzFooter as Array>);
- }
-
- // Place the modal dom to elsewhere
- this.container = typeof this.nzGetContainer === 'function' ? this.nzGetContainer() : this.nzGetContainer;
- if (this.container instanceof HTMLElement) {
- this.container.appendChild(this.elementRef.nativeElement);
- fromEvent(this.document.body, 'keydown')
- .pipe(takeUntil(this.unsubscribe$))
- .subscribe(e => this.keydownListener(e));
- } else if (this.container instanceof OverlayRef) {
- // NOTE: only attach the dom to overlay, the view container is not changed actually
- this.setOverlayRef(this.container);
- this.container.overlayElement.appendChild(this.elementRef.nativeElement);
- }
-
- if (this.overlayRef) {
- this.overlayRef
- .keydownEvents()
- .pipe(takeUntil(this.unsubscribe$))
- .subscribe(e => this.keydownListener(e));
- }
-
- // Register modal when afterOpen/afterClose is stable
- this.modalControl.registerModal(this);
- }
-
- // [NOTE] NOT available when using by service!
- // Because ngOnChanges never be called when using by service,
- // here we can't support "nzContent"(Component) etc. as inputs that initialized dynamically.
- // BUT: User also can change "nzContent" dynamically to trigger UI changes (provided you don't use Component that needs initializations)
- ngOnChanges(changes: SimpleChanges): void {
- if (changes.nzVisible) {
- this.handleVisibleStateChange(this.nzVisible, !changes.nzVisible.firstChange); // Do not trigger animation while initializing
- }
- }
-
- ngAfterViewInit(): void {
- // If using Component, it is the time to attach View while bodyContainer is ready
- if (this.contentComponentRef) {
- this.bodyContainer.insert(this.contentComponentRef.hostView);
- }
-
- if (this.autoFocusButtonOk) {
- (this.autoFocusButtonOk.nativeElement as HTMLButtonElement).focus();
- }
- }
-
- ngOnDestroy(): void {
- // Close self before destructing
- this.changeVisibleFromInside(false).then(() => {
- this.modalControl.deregisterModal(this);
-
- if (this.container instanceof OverlayRef) {
- this.container.dispose();
- }
-
- this.unsubscribe$.next();
- this.unsubscribe$.complete();
- });
- clearTimeout(this.timeoutId);
- }
-
- setFooterWithTemplate(templateRef: TemplateRef<{}>): void {
- this.nzFooter = templateRef;
- this.cdr.markForCheck();
- }
-
- setOverlayRef(overlayRef: OverlayRef): void {
- this.overlayRef = overlayRef;
- }
-
- keydownListener(event: KeyboardEvent): void {
- if (event.keyCode === ESCAPE && this.nzKeyboard) {
- this.onClickOkCancel('cancel');
- }
- }
-
- open(): void {
- this.changeVisibleFromInside(true);
- }
-
- close(result?: R): void {
- this.changeVisibleFromInside(false, result);
- }
-
- destroy(result?: R): void {
- // Destroy equals Close
- this.close(result);
- }
-
- triggerOk(): void {
- this.onClickOkCancel('ok');
- }
-
- triggerCancel(): void {
- this.onClickOkCancel('cancel');
- }
-
- getInstance(): NzModalComponent {
- return this;
- }
-
- getContentComponentRef(): ComponentRef {
- return this.contentComponentRef;
- }
-
- getContentComponent(): T {
- return this.contentComponentRef && this.contentComponentRef.instance;
- }
-
- getElement(): HTMLElement {
- 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(WRAP_CLASS_NAME) &&
- this.nzVisible &&
- !this.dialogMouseDown
- ) {
- this.onClickOkCancel('cancel');
- }
- }
-
- isModalType(type: ModalType): boolean {
- return this.nzModalType === type;
- }
-
- public onClickCloseBtn(): void {
- if (this.nzVisible) {
- this.onClickOkCancel('cancel');
- }
- }
-
- public onClickOkCancel(type: 'ok' | 'cancel'): void {
- const trigger = { ok: this.nzOnOk, cancel: this.nzOnCancel }[type];
- const loadingKey = { ok: 'nzOkLoading', cancel: 'nzCancelLoading' }[type];
- if (trigger instanceof EventEmitter) {
- trigger.emit(this.getContentComponent());
- } else if (typeof trigger === 'function') {
- const result = trigger(this.getContentComponent());
- const caseClose = (doClose: boolean | void | {}) => doClose !== false && this.close(doClose as R); // Users can return "false" to prevent closing by default
- if (isPromise(result)) {
- this[loadingKey] = true;
- const handleThen = (doClose: boolean | void | {}) => {
- this[loadingKey] = false;
- caseClose(doClose);
- };
- result.then(handleThen).catch(handleThen);
- } else {
- caseClose(result);
- }
- }
- }
-
- public isNonEmptyString(value: {}): boolean {
- return typeof value === 'string' && value !== '';
- }
-
- public isTemplateRef(value: {}): boolean {
- return value instanceof TemplateRef;
- }
-
- public isComponent(value: {}): boolean {
- return value instanceof Type;
- }
-
- public isModalButtons(value: string | TemplateRef<{}> | Array> | null): boolean {
- return Array.isArray(value) && value.length > 0;
- }
-
- // Do rest things when visible state changed
- private handleVisibleStateChange(visible: boolean, animation: boolean = true, closeResult?: R): Promise {
- if (visible) {
- // Hide scrollbar at the first time when shown up
- this.scrollStrategy.enable();
- this.savePreviouslyFocusedElement();
- this.trapFocus();
- if (this.container instanceof OverlayRef) {
- this.overlayKeyboardDispatcher.add(this.overlayRef);
- }
- } else {
- if (this.container instanceof OverlayRef) {
- this.overlayKeyboardDispatcher.remove(this.overlayRef);
- }
- }
-
- return Promise.resolve(animation ? this.animateTo(visible) : undefined).then(() => {
- // Emit open/close event after animations over
- if (visible) {
- this.nzAfterOpen.emit();
- } else {
- this.nzAfterClose.emit(closeResult);
- this.restoreFocus();
- this.scrollStrategy.disable();
- // Mark the for check so it can react if the view container is using OnPush change detection.
- this.cdr.markForCheck();
- }
- });
- }
-
- // Lookup a button's property, if the prop is a function, call & then return the result, otherwise, return itself.
- public getButtonCallableProp(options: ModalButtonOptions, prop: string): {} {
- const value = options[prop];
- const args: T[] = [];
- if (this.contentComponentRef) {
- args.push(this.contentComponentRef.instance);
- }
- return typeof value === 'function' ? value.apply(options, args) : value;
- }
-
- // On nzFooter's modal button click
- public onButtonClick(button: ModalButtonOptions): void {
- const result = this.getButtonCallableProp(button, 'onClick'); // Call onClick directly
- if (isPromise(result)) {
- button.loading = true;
- result.then(() => (button.loading = false)).catch(() => (button.loading = false));
- }
- }
-
- // Change nzVisible from inside
- private changeVisibleFromInside(visible: boolean, closeResult?: R): Promise {
- if (this.nzVisible !== visible) {
- // Change nzVisible value immediately
- this.nzVisible = visible;
- this.nzVisibleChange.emit(visible);
- return this.handleVisibleStateChange(visible, true, closeResult);
- }
- return Promise.resolve();
- }
-
- private changeAnimationState(state: AnimationState): void {
- this.animationState = state;
- if (state) {
- this.maskAnimationClassMap = {
- [`fade-${state}`]: true,
- [`fade-${state}-active`]: true
- };
- this.modalAnimationClassMap = {
- [`zoom-${state}`]: true,
- [`zoom-${state}-active`]: true
- };
- } else {
- this.maskAnimationClassMap = this.modalAnimationClassMap = null;
- }
- }
-
- private animateTo(isVisible: boolean): Promise {
- if (isVisible) {
- // Figure out the lastest click position when shows up
- setTimeout(() => this.updateTransformOrigin()); // [NOTE] Using timeout due to the document.click event is fired later than visible change, so if not postponed to next event-loop, we can't get the lastest click position
- }
-
- this.changeAnimationState(isVisible ? 'enter' : 'leave');
- return new Promise(resolve =>
- setTimeout(
- () => {
- // Return when animation is over
- this.changeAnimationState(null);
- resolve();
- },
- this.nzNoAnimation ? 0 : MODAL_ANIMATE_DURATION
- )
- );
- }
-
- private formatModalButtons(buttons: Array>): Array> {
- return buttons.map(button => {
- return {
- ...{
- type: 'default',
- size: 'default',
- autoLoading: true,
- show: true,
- loading: false,
- disabled: false
- },
- ...button
- };
- });
- }
-
- /**
- * Create a component dynamically but not attach to any View (this action will be executed when bodyContainer is ready)
- * @param component Component class
- */
- private createDynamicComponent(component: Type): void {
- const factory = this.cfr.resolveComponentFactory(component);
- const childInjector = Injector.create({
- providers: [{ provide: NzModalRef, useValue: this }],
- parent: this.viewContainer.parentInjector
- });
- this.contentComponentRef = factory.create(childInjector);
- if (this.nzComponentParams) {
- Object.assign(this.contentComponentRef.instance, this.nzComponentParams);
- }
- // Do the first change detection immediately (or we do detection at ngAfterViewInit, multi-changes error will be thrown)
- this.contentComponentRef.changeDetectorRef.detectChanges();
- }
-
- // Update transform-origin to the last click position on document
- private updateTransformOrigin(): void {
- const modalElement = this.modalContainer.nativeElement as HTMLElement;
- if (this.previouslyFocusedElement) {
- const previouslyDOMRect = this.previouslyFocusedElement.getBoundingClientRect();
- const lastPosition = getElementOffset(this.previouslyFocusedElement);
- const x = lastPosition.left + previouslyDOMRect.width / 2;
- const y = lastPosition.top + previouslyDOMRect.height / 2;
- this.transformOrigin = `${x - modalElement.offsetLeft}px ${y - modalElement.offsetTop}px 0px`;
- }
- }
-
- private savePreviouslyFocusedElement(): void {
- if (this.document) {
- this.previouslyFocusedElement = this.document.activeElement as HTMLElement;
- }
- }
-
- private trapFocus(): void {
- if (!this.focusTrap) {
- this.focusTrap = this.focusTrapFactory.create(this.elementRef.nativeElement);
- }
- this.focusTrap.focusInitialElementWhenReady();
- }
-
- private restoreFocus(): void {
- // We need the extra check, because IE can set the `activeElement` to null in some cases.
- if (this.previouslyFocusedElement && typeof this.previouslyFocusedElement.focus === 'function') {
- this.previouslyFocusedElement.focus();
- }
- if (this.focusTrap) {
- this.focusTrap.destroy();
- }
- }
-}
diff --git a/components/modal/nz-modal.service.module.ts b/components/modal/nz-modal.service.module.ts
deleted file mode 100644
index 1fae59bbb8c..00000000000
--- a/components/modal/nz-modal.service.module.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * @license
- * Copyright Alibaba.com All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
- */
-
-import { NgModule } from '@angular/core';
-
-@NgModule()
-export class NzModalServiceModule {}
diff --git a/components/modal/nz-modal.service.ts b/components/modal/nz-modal.service.ts
deleted file mode 100644
index 92014e3c688..00000000000
--- a/components/modal/nz-modal.service.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-/**
- * @license
- * Copyright Alibaba.com All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
- */
-
-import { Overlay, OverlayRef } from '@angular/cdk/overlay';
-import { ComponentPortal } from '@angular/cdk/portal';
-import { ComponentRef, Injectable } from '@angular/core';
-import { Observable } from 'rxjs';
-
-import { IndexableObject, warn } from 'ng-zorro-antd/core';
-
-import { NzModalControlService } from './nz-modal-control.service';
-import { NzModalRef } from './nz-modal-ref.class';
-import { NzModalComponent } from './nz-modal.component';
-import { NzModalServiceModule } from './nz-modal.service.module';
-import { ConfirmType, ModalOptions, ModalOptionsForService } from './nz-modal.type';
-
-// A builder used for managing service creating modals
-export class ModalBuilderForService {
- private modalRef: ComponentRef | null; // Modal ComponentRef, "null" means it has been destroyed
- private overlayRef: OverlayRef;
-
- constructor(private overlay: Overlay, options: ModalOptionsForService = {}) {
- this.createModal();
-
- if (!('nzGetContainer' in options)) {
- // As we use CDK to create modal in service by force, there is no need to use nzGetContainer
- options.nzGetContainer = undefined; // Override nzGetContainer's default value to prevent creating another overlay
- }
-
- this.changeProps(options);
- this.modalRef!.instance.setOverlayRef(this.overlayRef);
- this.modalRef!.instance.open();
- this.modalRef!.instance.nzAfterClose.subscribe(() => this.destroyModal()); // [NOTE] By default, close equals destroy when using as Service
- }
-
- getInstance(): NzModalComponent | null {
- return this.modalRef && this.modalRef.instance;
- }
-
- destroyModal(): void {
- if (this.modalRef) {
- this.overlayRef.dispose();
- this.modalRef = null;
- }
- }
-
- private changeProps(options: ModalOptions): void {
- if (this.modalRef) {
- Object.assign(this.modalRef.instance, options); // DANGER: here not limit user's inputs at runtime
- }
- }
-
- // Create component to ApplicationRef
- private createModal(): void {
- this.overlayRef = this.overlay.create();
- this.modalRef = this.overlayRef.attach(new ComponentPortal(NzModalComponent));
- }
-}
-
-@Injectable({
- providedIn: NzModalServiceModule
-})
-export class NzModalService {
- // Track of the current close modals (we assume invisible is close this time)
- get openModals(): NzModalRef[] {
- return this.modalControl.openModals;
- }
-
- get afterAllClose(): Observable {
- return this.modalControl.afterAllClose.asObservable();
- }
-
- constructor(private overlay: Overlay, private modalControl: NzModalControlService) {}
-
- // Closes all of the currently-open dialogs
- closeAll(): void {
- this.modalControl.closeAll();
- }
-
- create(options: ModalOptionsForService = {}): NzModalRef {
- if (typeof options.nzOnCancel !== 'function') {
- options.nzOnCancel = () => {}; // Leave a empty function to close this modal by default
- }
-
- // NOTE: use NzModalComponent as the NzModalRef by now, we may need archive the real NzModalRef object in the future
- const modalRef = new ModalBuilderForService(this.overlay, options).getInstance()!;
-
- return modalRef;
- }
-
- confirm(options: ModalOptionsForService = {}, confirmType: ConfirmType = 'confirm'): NzModalRef {
- if ('nzFooter' in options) {
- warn(`The Confirm-Modal doesn't support "nzFooter", this property will be ignored.`);
- }
- if (!('nzWidth' in options)) {
- options.nzWidth = 416;
- }
- if (!('nzMaskClosable' in options)) {
- options.nzMaskClosable = false;
- }
- if (typeof options.nzOnOk !== 'function') {
- // NOTE: only support function currently by calling confirm()
- options.nzOnOk = () => {}; // Leave a empty function to close this modal by default
- }
-
- options.nzModalType = 'confirm';
- options.nzClassName = `ant-modal-confirm ant-modal-confirm-${confirmType} ${options.nzClassName || ''}`;
- return this.create(options);
- }
-
- info(options: ModalOptionsForService = {}): NzModalRef {
- return this.simpleConfirm(options, 'info');
- }
-
- success(options: ModalOptionsForService = {}): NzModalRef {
- return this.simpleConfirm(options, 'success');
- }
-
- error(options: ModalOptionsForService = {}): NzModalRef {
- return this.simpleConfirm(options, 'error');
- }
-
- warning(options: ModalOptionsForService = {}): NzModalRef {
- return this.simpleConfirm(options, 'warning');
- }
-
- private simpleConfirm(options: ModalOptionsForService = {}, confirmType: ConfirmType): NzModalRef {
- const iconMap: IndexableObject = {
- info: 'info-circle',
- success: 'check-circle',
- error: 'close-circle',
- warning: 'exclamation-circle'
- };
- if (!('nzIconType' in options)) {
- options.nzIconType = iconMap[confirmType];
- }
- if (!('nzCancelText' in options)) {
- // Remove the Cancel button if the user not specify a Cancel button
- options.nzCancelText = null;
- }
- return this.confirm(options, confirmType);
- }
-}
diff --git a/components/modal/nz-modal.spec.ts b/components/modal/nz-modal.spec.ts
deleted file mode 100644
index 99342e54954..00000000000
--- a/components/modal/nz-modal.spec.ts
+++ /dev/null
@@ -1,1041 +0,0 @@
-/* TODO: Sort out and rewrite for more standardized */
-
-import { ESCAPE } from '@angular/cdk/keycodes';
-import { OverlayContainer } from '@angular/cdk/overlay';
-import { Component, ElementRef, EventEmitter, Input } from '@angular/core';
-import { async, ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';
-import { By } from '@angular/platform-browser';
-import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
-import { NoopAnimationsModule } from '@angular/platform-browser/animations';
-
-import { NzButtonComponent, NzButtonModule } from 'ng-zorro-antd/button';
-import { dispatchFakeEvent, dispatchKeyboardEvent } from 'ng-zorro-antd/core';
-import { NzToCssUnitPipe } from 'ng-zorro-antd/core/pipe/nz-css-unit.pipe';
-import { NzI18nService } from 'ng-zorro-antd/i18n';
-import { NzIconTestModule } from 'ng-zorro-antd/icon/testing';
-import en_US from '../i18n/languages/en_US';
-
-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';
-import { NzModalModule } from './nz-modal.module';
-import { NzModalService } from './nz-modal.service';
-
-let counter = 0;
-describe('modal testing (legacy)', () => {
- describe('demo-async', () => {
- let fixture: ComponentFixture;
- let modalElement: HTMLElement;
- let buttonShow: HTMLButtonElement;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- imports: [NoopAnimationsModule, NzButtonModule, NzModalModule],
- declarations: [NzDemoModalAsyncComponent]
- }).compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(NzDemoModalAsyncComponent);
- modalElement = fixture.debugElement.query(By.directive(NzModalComponent)).nativeElement;
- buttonShow = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;
- });
-
- it('should show and hide after 3000ms with loading', fakeAsync(() => {
- buttonShow.click();
- fixture.detectChanges();
- flush();
- expectModalHidden(modalElement, false);
-
- const buttonOk = getButtonOk(modalElement);
- buttonOk.click(); // Click Ok button
- fixture.detectChanges();
- expect(isButtonLoading(buttonOk)).not.toBeFalsy();
-
- tick(3000 + 10);
- fixture.detectChanges();
- flush();
- fixture.detectChanges(); // In order to trigger ModalInstance's UI updating after finished hiding
- expectModalHidden(modalElement, true);
- }));
- }); // /async
-
- describe('demo-confirm-promise', () => {
- const tempModalId = generateUniqueId(); // Temp unique id to mark the confirm modal that created by service
- let fixture: ComponentFixture;
- let instance: NzDemoModalConfirmPromiseComponent;
- let modalAgent: NzModalRef;
- let buttonShow: HTMLButtonElement;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- imports: [NoopAnimationsModule, NzButtonModule, NzModalModule],
- declarations: [NzDemoModalConfirmPromiseComponent]
- }).compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(NzDemoModalConfirmPromiseComponent);
- instance = fixture.debugElement.componentInstance;
- buttonShow = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;
-
- buttonShow.click();
- fixture.detectChanges();
- modalAgent = instance.confirmModal;
- modalAgent.getElement().classList.add(tempModalId);
- });
-
- it('should open and click Ok to destroy after 1000ms', fakeAsync(() => {
- expectModalDestroyed(tempModalId, false);
-
- getButtonOk(modalAgent.getElement()).click(); // Click Ok button
- fixture.detectChanges();
- tick(1000 + 10);
- fixture.detectChanges();
- flush();
- fixture.detectChanges();
- expectModalDestroyed(tempModalId, true);
- }));
-
- it('should open and destroy immediately when click Cancel', fakeAsync(() => {
- expectModalDestroyed(tempModalId, false);
-
- getButtonClose(modalAgent.getElement()).click(); // Click Close button
- fixture.detectChanges();
- flush();
- fixture.detectChanges();
- expectModalDestroyed(tempModalId, true);
- }));
- }); // /confirm-promise
-
- describe('NormalModal: created by service with most APIs', () => {
- let tempModalId: string; // Temp unique id to mark the confirm modal that created by service
- let fixture: ComponentFixture;
- let instance: TestBasicServiceComponent;
- let modalAgent: NzModalRef;
- let modalElement: HTMLElement;
- let modalInstance: NzModalComponent;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- imports: [NoopAnimationsModule, NzModalModule, NzIconTestModule],
- declarations: [TestBasicServiceComponent]
- }).compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(TestBasicServiceComponent);
- instance = fixture.debugElement.componentInstance;
- modalAgent = instance.basicModal;
- modalElement = modalAgent.getElement();
- tempModalId = generateUniqueId();
- modalElement.classList.add(tempModalId); // Mark with id
- modalInstance = modalAgent.getInstance();
- });
-
- it('should correctly render all basic props', fakeAsync(() => {
- const spy = spyOn(console, 'log');
-
- // [Hack] Codes that can't be covered by normal operations
- // @ts-ignore
- expect(modalInstance.changeVisibleFromInside(true) instanceof Promise).toBe(true);
-
- expect((modalElement.querySelector('.ant-modal-wrap') as HTMLElement).style.zIndex).toBe('1888');
- expect((modalElement.querySelector('.ant-modal-wrap') as HTMLElement).classList.contains('test-wrap-class-name')).toBe(true);
- expect((modalElement.querySelector('.ant-modal') as HTMLElement).style.width).toBe('250px');
- expect((modalElement.querySelector('.ant-modal') as HTMLElement).classList.contains('test-class-name')).toBe(true);
- expect((modalElement.querySelector('.ant-modal') as HTMLElement).style.top).toBe('20pt');
- expect((modalElement.querySelector('.ant-modal-title') as HTMLElement).innerHTML.indexOf('TEST BOLD TITLE')).toBeGreaterThan(
- -1
- );
- // expect((modalElement.querySelector('.ant-modal-footer') as HTMLElement).innerHTML.indexOf('custom html footer: OK
')).toBeGreaterThan(-1);
- expect((modalElement.querySelector('.ant-modal-body') as HTMLElement).innerHTML.indexOf('test html content
')).toBeGreaterThan(
- -1
- );
- expect((modalElement.querySelector('.ant-modal-body') as HTMLElement).style.background).toBe('gray');
- expect(getButtonOk(modalElement).innerHTML.indexOf('custom ok')).toBeGreaterThan(-1);
- expect(getButtonOk(modalElement).classList.contains('ant-btn-primary')).toBe(true);
- expect(isButtonLoading(getButtonOk(modalElement))).toBeFalsy();
- expect(getButtonCancel(modalElement).innerHTML.indexOf('custom cancel')).toBeGreaterThan(-1);
- expect(isButtonLoading(getButtonCancel(modalElement))).not.toBeFalsy();
- expect(modalElement.querySelector('.ant-modal-close')).toBeFalsy();
- expect(modalElement.querySelector('.ant-modal-mask')).toBeFalsy();
- expect(getButtonOk(modalElement).disabled).toBeFalsy();
- expect(getButtonCancel(modalElement).disabled).toBeFalsy();
-
- // click ok button
- getButtonOk(modalElement).click();
- flush();
- expect(console.log).toHaveBeenCalledWith('click ok');
- expectModalDestroyed(tempModalId, false); // shouldn't destroy when ok button returns false
- spy.calls.reset();
- })); // /basic props
-
- it('should be closed when clicking cancel button', fakeAsync(() => {
- const spy = spyOn(console, 'log');
- // change and click mask
- modalInstance.nzMask = true;
- // should show mask
- // TODO: repair this
- // expect((modalElement.querySelector('div.ant-modal-mask') as HTMLElement).style.opacity).toBe('0.4');
- // should not trigger nzOnCancel if click mask
- (modalElement.querySelector('.ant-modal-wrap') as HTMLElement).click();
- expect(console.log).not.toHaveBeenCalledWith('click cancel');
- // change nzMaskClosable to true then click, should be called and destroyed
- modalInstance.nzMaskClosable = true;
- (modalElement.querySelector('.ant-modal-wrap') as HTMLElement).click();
- expect(console.log).toHaveBeenCalledWith('click cancel');
- // second click on mask should not trigger nzOnCancel
- (console.log as jasmine.Spy).calls.reset();
- (modalElement.querySelector('.ant-modal-wrap') as HTMLElement).click();
- expect(console.log).not.toHaveBeenCalledWith('click cancel');
- flush();
- fixture.detectChanges();
- expectModalDestroyed(tempModalId, true); // should be destroyed
- spy.calls.reset();
- }));
-
- it('should be closed when clicking ESC', fakeAsync(() => {
- // click 'ESC' key
- dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
- fixture.detectChanges();
- expectModalDestroyed(tempModalId, false);
-
- modalInstance.nzKeyboard = true;
- dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
- flush();
- fixture.detectChanges();
- expectModalDestroyed(tempModalId, true);
- }));
- });
-
- describe('NormalModal: created by service with vary nzContent and nzFooter', () => {
- const tempModalId = generateUniqueId(); // Temp unique id to mark the confirm modal that created by service
- let fixture: ComponentFixture;
- let instance: TestVaryServiceComponent;
- let modalAgent: NzModalRef;
- let modalElement: HTMLElement;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- imports: [NoopAnimationsModule, NzModalModule],
- declarations: [TestVaryServiceComponent, TestVaryServiceCustomComponent]
- });
- TestBed.overrideModule(BrowserDynamicTestingModule, {
- set: { entryComponents: [TestVaryServiceCustomComponent] }
- }).compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(TestVaryServiceComponent);
- instance = fixture.debugElement.componentInstance;
- modalAgent = instance.createWithVary();
- modalElement = modalAgent.getElement();
- modalElement.classList.add(tempModalId); // Mark with id
- });
-
- it('should change title from in/outside and trigger button', fakeAsync(() => {
- fixture.detectChanges(); // Initial change detecting
-
- const contentComponent = modalAgent.getContentComponent();
- const contentComponentRef = (modalAgent as any).getContentComponentRef(); // tslint:disable-line:no-any
- expect(contentComponent).toBe(contentComponentRef.instance);
- const contentElement = contentComponent.elementRef.nativeElement as HTMLElement;
- // change title from outside
- const firstButton = modalElement.querySelector('.ant-modal-footer button:first-child') as HTMLButtonElement;
- firstButton.click();
- fixture.detectChanges();
- expect(contentComponent.title).toBe('internal title changed');
- expect(isButtonLoading(firstButton)).toBe(false); // stopped immediately
-
- // button loading for Promise
- const lastButton = modalElement.querySelector('.ant-modal-footer button:last-child') as HTMLButtonElement;
- lastButton.click();
- fixture.detectChanges();
- expect(isButtonLoading(lastButton)).toBe(false); // stopped immediately
-
- // destroy from inside
- contentElement.querySelector('button')!.click();
- fixture.detectChanges();
- tick(1000);
- fixture.detectChanges();
- expectModalDestroyed(tempModalId, true);
- })); // /vary with component
- });
-
- describe('ConfirmModal: should apply options correctly', () => {
- let fixture: ComponentFixture;
- let instance: TestConfirmModalComponent;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- imports: [NoopAnimationsModule, NzModalModule],
- declarations: [TestConfirmModalComponent, TestConfirmCustomComponent]
- }).compileComponents();
-
- TestBed.overrideModule(BrowserDynamicTestingModule, {
- set: { entryComponents: [TestConfirmCustomComponent] }
- }).compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(TestConfirmModalComponent);
- instance = fixture.debugElement.componentInstance;
- });
-
- it('should click mask is closable', fakeAsync(() => {
- const modalRef = instance.createMaskClosableConfirm();
- const modalElement = modalRef.getElement();
- fixture.detectChanges();
- expect(modalRef.getInstance().nzMaskClosable).toBe(true);
- const maskElement = modalElement.querySelector('.ant-modal-wrap') as HTMLDivElement;
- maskElement!.click();
- flush();
- fixture.detectChanges();
- expect(instance.maskClosedSpy).toHaveBeenCalled();
- }));
-
- it('boundary detection for options', fakeAsync(() => {
- const spy = spyOn(console, 'warn');
-
- const tempModalId = generateUniqueId();
- const modalAgent = instance.createConfirm() as NzModalRef;
- const modalElement = modalAgent.getElement();
- modalElement.classList.add(tempModalId);
- fixture.detectChanges();
- expect(console.warn).toHaveBeenCalled();
- // nzOnOk: close modal when clicked
- getButtonOk(modalElement).click();
- fixture.detectChanges();
- flush();
- fixture.detectChanges();
- expectModalDestroyed(tempModalId, true);
- spy.calls.reset();
- }));
-
- it('should render other confirm modals', fakeAsync(() => {
- const ids: string[] = instance.createOtherModals();
- fixture.detectChanges();
- flush();
- fixture.detectChanges();
- ids.forEach(id => expectModalDestroyed(id, false));
- }));
-
- it('should disable buttons', fakeAsync(() => {
- const modalRef = instance.createDisabledModal();
- fixture.detectChanges();
- flush();
- fixture.detectChanges();
- const buttons = modalRef.getElement().querySelectorAll('.ant-modal-confirm-btns button') as NodeListOf;
- buttons.forEach(button => expect(button.disabled).toBe(true));
- }));
-
- it('should render content with component', fakeAsync(() => {
- const modalRef = instance.createCustomContentWithComponent();
- const modalElement = modalRef.getElement();
- fixture.detectChanges();
- expect(modalElement.querySelector('.custom-component-in-confirm')).toBeTruthy();
- getButtonOk(modalElement).click();
- fixture.detectChanges();
- flush();
- fixture.detectChanges();
- }));
- });
-
- describe('css-unit.pipe', () => {
- let fixture: ComponentFixture;
- let testElement: HTMLDivElement;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- imports: [NoopAnimationsModule],
- declarations: [NzToCssUnitPipe, TestCssUnitPipeComponent]
- }).compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(TestCssUnitPipeComponent);
- testElement = fixture.debugElement.query(By.css('div')).nativeElement;
- fixture.detectChanges();
- });
-
- it('should "width" & "height" to be 100px', () => {
- // fixture.detectChanges();
- expect(testElement.style.width).toBe('100px');
- expect(testElement.style.height).toBe('100px');
- });
-
- it('should "top" to be 100pt', () => {
- // fixture.detectChanges();
- expect(testElement.style.top).toBe('100pt');
- });
- });
-
- it('#i18n', () => {
- let fixture: ComponentFixture;
-
- const injector = TestBed.configureTestingModule({
- imports: [NoopAnimationsModule, NzButtonModule, NzModalModule],
- declarations: [NzDemoModalAsyncComponent]
- });
- fixture = TestBed.createComponent(NzDemoModalAsyncComponent);
- const comp = fixture.componentInstance as NzDemoModalAsyncComponent;
- comp.showModal();
- fixture.detectChanges();
- injector.get(NzI18nService).setLocale(en_US);
- fixture.detectChanges();
- const cancelText = (fixture.debugElement.query(By.css('nz-modal .ant-btn')).nativeElement as HTMLElement).textContent!.trim();
- expect(cancelText).toBe(en_US.Modal.cancelText);
- const okText = (fixture.debugElement.query(By.css('nz-modal .ant-btn-primary')).nativeElement as HTMLElement).textContent!.trim();
- expect(okText).toBe(en_US.Modal.okText);
- });
-});
-
-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();
- expectModalHidden(inputFixture.debugElement.query(By.css('nz-modal')).nativeElement, true);
- }));
-});
-
-describe('NzModal', () => {
- let modalService: NzModalService;
- let overlayContainer: OverlayContainer;
- let overlayContainerElement: HTMLElement;
-
- beforeEach(fakeAsync(() => {
- TestBed.configureTestingModule({
- imports: [NoopAnimationsModule, NzModalModule, NzIconTestModule],
- declarations: [NzDemoModalBasicComponent, NzDemoModalMaskComponent, ModalByServiceComponent]
- });
-
- TestBed.compileComponents();
- }));
-
- beforeEach(inject([NzModalService, OverlayContainer], (ms: NzModalService, oc: OverlayContainer) => {
- modalService = ms;
- overlayContainer = oc;
- overlayContainerElement = oc.getContainerElement();
- }));
-
- afterEach(() => {
- overlayContainer.ngOnDestroy();
- });
-
- describe('basic usage', () => {
- let fixture: ComponentFixture;
- beforeEach(() => {
- fixture = TestBed.createComponent(NzDemoModalBasicComponent);
- });
-
- it('should destroy normally when the component context is over', fakeAsync(() => {
- fixture.detectChanges();
- tick(1000);
- fixture.detectChanges();
- expect(overlayContainerElement.textContent).toContain('BASIC_MODAL_TITLE');
- fixture.componentInstance.modalAvailable = false;
- fixture.detectChanges();
- tick(1000);
- fixture.detectChanges();
- expect(overlayContainerElement.textContent).not.toContain('BASIC_MODAL_TITLE');
- }));
-
- it('should custom close icon work', fakeAsync(() => {
- fixture.componentInstance.modalAvailable = true;
- fixture.componentInstance.icon = 'close-square';
- fixture.detectChanges();
- tick(1000);
- fixture.detectChanges();
- const closeIcon = overlayContainerElement.querySelector('.ant-modal-close-icon') as HTMLElement;
- expect(closeIcon).toBeTruthy();
- expect(closeIcon.classList).toContain('anticon-close-square');
- }));
- });
-
- describe('created by service', () => {
- let fixture: ComponentFixture;
-
- beforeEach(() => {
- fixture = TestBed.createComponent(ModalByServiceComponent);
- });
- afterEach(fakeAsync(() => {
- // wait all openModals tobe closed to clean up the ModalManager as it is globally static
- document.documentElement!.classList.remove('cdk-global-scrollblock');
- modalService.closeAll();
- fixture.detectChanges();
- tick(1000);
- }));
-
- it('should trigger both afterOpen/nzAfterOpen and have the correct openModals length', fakeAsync(() => {
- const spy = jasmine.createSpy('afterOpen spy');
- const nzAfterOpen = new EventEmitter();
- const modalRef = modalService.create({ nzAfterOpen });
-
- modalRef.afterOpen.subscribe(spy);
- nzAfterOpen.subscribe(spy);
-
- fixture.detectChanges();
- expect(spy).not.toHaveBeenCalled();
-
- tick(600);
- expect(spy).toHaveBeenCalledTimes(2);
- expect(modalService.openModals.indexOf(modalRef)).toBeGreaterThan(-1);
- expect(modalService.openModals.length).toBe(1);
- }));
-
- it('should trigger both afterClose/nzAfterClose and have the correct openModals length', fakeAsync(() => {
- const spy = jasmine.createSpy('afterClose spy');
- const nzAfterClose = new EventEmitter();
- const modalRef = modalService.create({ nzAfterClose });
-
- modalRef.afterClose.subscribe(spy);
- nzAfterClose.subscribe(spy);
-
- fixture.detectChanges();
- tick(600);
- modalRef.close();
- fixture.detectChanges();
- expect(spy).not.toHaveBeenCalled();
-
- tick(600);
- expect(spy).toHaveBeenCalledTimes(2);
- expect(modalService.openModals.indexOf(modalRef)).toBe(-1);
- expect(modalService.openModals.length).toBe(0);
- }));
-
- it('should return/receive with/without result data', fakeAsync(() => {
- const spy = jasmine.createSpy('afterClose without result spy');
- const modalRef = modalService.success();
-
- modalRef.afterClose.subscribe(spy);
- fixture.detectChanges();
- tick(600);
- modalRef.destroy();
- expect(spy).not.toHaveBeenCalled();
- tick(600);
- expect(spy).toHaveBeenCalledWith(undefined);
- }));
-
- it('should return/receive with result data', fakeAsync(() => {
- const result = { data: 'Fake Error' };
- const spy = jasmine.createSpy('afterClose with result spy');
- const modalRef = modalService.error();
-
- fixture.detectChanges();
- tick(600);
- modalRef.destroy(result);
- modalRef.afterClose.subscribe(spy);
- expect(spy).not.toHaveBeenCalled();
- tick(600);
- expect(spy).toHaveBeenCalledWith(result);
- }));
-
- it('should close all opened modals (include non-service modals)', fakeAsync(() => {
- const spy = jasmine.createSpy('afterAllClose spy');
- const modalMethods = ['create', 'info', 'success', 'error', 'confirm'];
- const uniqueId = (name: string) => `__${name}_ID_SUFFIX__`;
- const queryOverlayElement = (name: string) => overlayContainerElement.querySelector(`.${uniqueId(name)}`) as HTMLElement;
-
- modalService.afterAllClose.subscribe(spy);
-
- fixture.componentInstance.nonServiceModalVisible = true; // Show non-service modal
- // @ts-ignore
- modalMethods.forEach(method => modalService[method]({ nzWrapClassName: uniqueId(method) })); // Service modals
-
- fixture.detectChanges();
- tick(600);
- modalMethods.concat('NON_SERVICE').forEach(method => expect(queryOverlayElement(method).style.display).not.toBe('none')); // Cover non-service modal for later checking
- expect(modalService.openModals.length).toBe(6);
-
- modalService.closeAll();
- fixture.detectChanges();
- expect(spy).not.toHaveBeenCalled();
- tick(600);
- expect(spy).toHaveBeenCalled();
- expect(modalService.openModals.length).toBe(0);
- }));
-
- it('should only a confirm button when the type is "info"|"success"|"error"|"warning"', fakeAsync(() => {
- const modalMethods = ['info', 'success', 'error', 'warning'];
- const uniqueId = (name: string) => `__${name}_ID_SUFFIX__`;
- const queryOverlayElement = (name: string) =>
- overlayContainerElement.querySelectorAll(`.${uniqueId(name)} .ant-modal-confirm-btns > button`) as NodeListOf;
-
- fixture.componentInstance.nonServiceModalVisible = false; // Show non-service modal
- // @ts-ignore
- modalMethods.forEach(method => modalService[method]({ nzWrapClassName: uniqueId(method) })); // Service modals
-
- fixture.detectChanges();
- tick(600);
- modalMethods.forEach(method => {
- const buttons = queryOverlayElement(method);
- expect(buttons.length).toBe(1);
- expect(buttons[0]!.classList).toContain('ant-btn-primary');
- }); // Cover non-service modal for later checking
- expect(modalService.openModals.length).toBe(4);
-
- modalService.closeAll();
- fixture.detectChanges();
- tick(600);
- expect(modalService.openModals.length).toBe(0);
- }));
-
- it('should modal not be registered twice', fakeAsync(() => {
- const modalRef = modalService.create();
-
- fixture.detectChanges();
- (modalService as any).modalControl.registerModal(modalRef); // tslint:disable-line:no-any
- tick(600);
- expect(modalService.openModals.length).toBe(1);
- }));
-
- it('should degregister a modal', fakeAsync(() => {
- const modalRef = modalService.create();
- const modalControl = (modalService as any).modalControl as NzModalControlService; // tslint:disable-line:no-any
-
- fixture.detectChanges();
- tick(600);
- expect(modalService.openModals.length).toBe(1);
-
- modalControl.deregisterModal(modalRef);
- expect(modalService.openModals.length).toBe(0);
-
- // Should nothing happened
- modalControl.deregisterModal(modalRef);
- expect(modalService.openModals.length).toBe(0);
- }));
-
- it('should trigger nzOnOk/nzOnCancel', () => {
- const spyOk = jasmine.createSpy('ok spy');
- const spyCancel = jasmine.createSpy('cancel spy');
- const modalRef: NzModalRef = modalService.create({
- nzOnOk: spyOk,
- nzOnCancel: spyCancel
- });
-
- fixture.detectChanges();
-
- modalRef.triggerOk();
- expect(spyOk).toHaveBeenCalled();
-
- modalRef.triggerCancel();
- expect(spyCancel).toHaveBeenCalled();
- });
-
- it('should block body scroll', fakeAsync(() => {
- const forceScrollElement = document.createElement('div');
- document.body.appendChild(forceScrollElement);
- forceScrollElement.style.width = '100px';
- forceScrollElement.style.height = '3000px';
- forceScrollElement.style.background = 'rebeccapurple';
-
- const modalRef = modalService.create();
- tick(600);
- fixture.detectChanges();
-
- expect(document.documentElement!.classList).toContain('cdk-global-scrollblock');
-
- modalRef.close();
- tick(600);
- fixture.detectChanges();
-
- expect(document.documentElement!.classList).not.toContain('cdk-global-scrollblock');
- 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);
- }));
- });
-});
-
-// -------------------------------------------
-// | Testing Components
-// -------------------------------------------
-
-@Component({
- template: `
-
- content
-
- `
-})
-class NzDemoModalBasicComponent {
- modalAvailable = true;
- icon = 'close';
-}
-
-@Component({
- template: `
-
- content
-
- `
-})
-class NzDemoModalMaskComponent {
- isVisible = false;
- handleCancel(): void {
- this.isVisible = false;
- }
-}
-
-@Component({
- template: `
-
- content
-
- `
-})
-class NzDemoModalWithInputComponent {
- modalAvailable = true;
- nzMask = true;
-}
-
-@Component({
- template: `
-
-
- content
-
- `
-})
-class NzDemoModalAsyncComponent {
- isVisible = false;
- isOkLoading = false;
-
- showModal(): void {
- this.isVisible = true;
- }
-
- handleOk(): void {
- this.isOkLoading = true;
- setTimeout(() => {
- this.isVisible = false;
- this.isOkLoading = false;
- }, 3000);
- }
-
- handleCancel(): void {
- this.isVisible = false;
- }
-}
-
-@Component({
- template: `
-
- `
-})
-class NzDemoModalConfirmPromiseComponent {
- confirmModal: NzModalRef; // For testing by now
-
- constructor(private modal: NzModalService) {}
-
- showConfirm(): void {
- this.confirmModal = this.modal.confirm({
- nzTitle: 'Do you Want to delete these items?',
- nzContent: 'When clicked the OK button, this dialog will be closed after 1 second',
- nzOnOk: () =>
- new Promise((resolve, reject) => {
- setTimeout(Math.random() > 0.5 ? resolve : reject, 1000);
- }).catch(() => console.log('Oops errors!'))
- });
- }
-}
-
-@Component({
- template: ``
-})
-class TestBasicServiceComponent {
- basicModal: NzModalRef;
-
- constructor(private modalService: NzModalService) {
- this.modalService.create(); // [Testing Required] Only for coverage temporarily
-
- // Testing for creating modal immediately
- this.basicModal = this.modalService.create({
- nzGetContainer: () => document.body,
- nzZIndex: 1888,
- nzWidth: 250,
- nzWrapClassName: 'test-wrap-class-name',
- nzClassName: 'test-class-name',
- nzStyle: { left: '10px', top: '20pt', border: '2px solid red' },
- nzTitle: 'TEST BOLD TITLE',
- nzContent: 'test html content
',
- nzClosable: false,
- nzKeyboard: false,
- nzMask: false,
- nzMaskClosable: false,
- nzMaskStyle: { opacity: 0.4 },
- nzBodyStyle: { background: 'gray' },
- // nzFooter: 'custom html footer: OK
',
- nzOkText: 'custom ok',
- nzOkType: 'primary',
- nzOkLoading: false,
- nzOkDisabled: false,
- nzCancelDisabled: false,
- nzOnOk: () => {
- console.log('click ok');
- return false;
- },
- nzCancelText: 'custom cancel',
- nzCancelLoading: true,
- nzOnCancel: () => console.log('click cancel')
- });
- }
-}
-
-@Component({
- template: ``
-})
-class TestVaryServiceComponent {
- constructor(private modalService: NzModalService) {}
-
- createWithVary(): NzModalRef {
- const modal = this.modalService.create({
- nzContent: TestVaryServiceCustomComponent,
- nzComponentParams: { title: 'internal title', subtitle: 'subtitle' },
- nzFooter: [
- {
- label: 'change title from outside',
- onClick: componentInstance => {
- componentInstance!.title = 'internal title changed';
- return Promise.resolve();
- }
- },
- {
- label: 'show loading',
- onClick: () => Promise.reject(null)
- }
- ]
- });
-
- return modal;
- }
-}
-
-@Component({
- template: `
- {{ title }}
- {{ subtitle }}
-
- `
-})
-export class TestVaryServiceCustomComponent {
- @Input() title: string;
- @Input() subtitle: string;
-
- constructor(private modal: NzModalRef, public elementRef: ElementRef) {}
-
- destroyModal(): void {
- this.modal.destroy();
- }
-}
-
-@Component({
- template: ``
-})
-export class TestConfirmModalComponent {
- maskClosedSpy = jasmine.createSpy();
- constructor(public modalService: NzModalService) {}
-
- createConfirm(): NzModalRef {
- this.modalService.confirm(); // [Testing Required] Only for coverage temporarily
- this.modalService.confirm({ nzWidth: 100 }); // [Testing Required] Only for coverage temporarily
-
- // Boundary detection for options: nzFooter, nzOnOk
- return this.modalService.confirm({
- nzFooter: 'should warning',
- nzOkText: 'close'
- });
- }
-
- createMaskClosableConfirm(): NzModalRef {
- return this.modalService.confirm({
- nzMaskClosable: true,
- nzOnCancel: () => {
- this.maskClosedSpy();
- }
- });
- }
-
- createOtherModals(): string[] {
- return ['info', 'success', 'error', 'warning'].map(type => {
- const modalId = generateUniqueId();
- // @ts-ignore
- this.modalService[type]({ nzClassName: modalId });
- // @ts-ignore
- this.modalService[type](); // [Testing Required] Only for coverage temporarily
- return modalId;
- });
- }
-
- createCustomContentWithComponent(): NzModalRef {
- return this.modalService.confirm({
- nzContent: TestConfirmCustomComponent
- });
- }
-
- createDisabledModal(): NzModalRef {
- return this.modalService.confirm({
- nzCancelDisabled: true,
- nzOkDisabled: true
- });
- }
-}
-
-@Component({
- template: `
-
- Content
-
- `
-})
-export class TestConfirmCustomComponent {
- constructor() {}
-}
-
-@Component({
- template: `
-
- `
-})
-class TestCssUnitPipeComponent {}
-
-@Component({
- template: `
-
- `,
- providers: [NzModalControlService] // Testing for service with parent service
-})
-export class ModalByServiceComponent {
- nonServiceModalVisible = false;
-}
-
-// -------------------------------------------
-// | Local tool functions
-// -------------------------------------------
-
-function expectModalHidden(modalElement: HTMLElement, hidden: boolean): void {
- const display = (modalElement.querySelector('.ant-modal-wrap') as HTMLElement).style.visibility;
- if (hidden) {
- expect(display).toBe('hidden');
- } else {
- expect(display).not.toBe('hidden');
- }
- expect(modalElement.querySelector('.ant-modal-mask')!.classList.contains('ant-modal-mask-hidden')).toBe(hidden);
-}
-
-function expectModalDestroyed(classId: string, destroyed: boolean): void {
- const element = document.querySelector(`.${classId}`);
- if (destroyed) {
- expect(element).toBeFalsy();
- } else {
- expect(element).not.toBeFalsy();
- }
-}
-
-function generateUniqueId(): string {
- return `testing-uniqueid-${counter++}`;
-}
-
-function getButtonOk(modalElement: HTMLElement): HTMLButtonElement {
- return isConfirmModal(modalElement)
- ? (modalElement.querySelector('.ant-modal-confirm-btns button:last-child') as HTMLButtonElement)
- : (modalElement.querySelector('.ant-modal-footer button:last-child') as HTMLButtonElement);
-}
-
-function getButtonCancel(modalElement: HTMLElement): HTMLButtonElement {
- return isConfirmModal(modalElement)
- ? (modalElement.querySelector('.ant-modal-confirm-btns button:first-child') as HTMLButtonElement)
- : (modalElement.querySelector('.ant-modal-footer button:first-child') as HTMLButtonElement);
-}
-
-function getButtonClose(modalElement: HTMLElement): HTMLButtonElement {
- // For normal modal only
- return modalElement.querySelector('.ant-modal-close') as HTMLButtonElement;
-}
-
-function isConfirmModal(modalElement: HTMLElement): boolean {
- return !!modalElement.querySelector('.ant-modal-confirm');
-}
-
-function isButtonLoading(buttonElement: HTMLButtonElement): boolean {
- return !!buttonElement.querySelector('i.anticon-loading');
-}
diff --git a/components/modal/public-api.ts b/components/modal/public-api.ts
index b6411baee96..0f08654cab0 100644
--- a/components/modal/public-api.ts
+++ b/components/modal/public-api.ts
@@ -6,15 +6,10 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/
-export { NzModalComponent } from './nz-modal.component';
-export { NzModalFooterDirective } from './nz-modal-footer.directive';
-export { NzModalRef } from './nz-modal-ref.class';
-export { NzModalModule } from './nz-modal.module';
-export { NzModalService } from './nz-modal.service';
-export { NzModalServiceModule } from './nz-modal.service.module';
-export { NZ_MODAL_CONFIG, NzModalConfig } from './nz-modal-config';
-export { NzModalControlService } from './nz-modal-control.service';
-export { NzModal } from './nz-modal';
-export { NzModalRef2 } from './nz-modal-ref';
-export { NzModalControlServiceModule } from './nz-modal-control.service.module';
-export * from './nz-modal.type';
+export * from './modal-types';
+export { NzModalService } from './modal.service';
+export { NzModalRef } from './modal-ref';
+export { NZ_MODAL_CONFIG, NzModalConfig } from './modal-config';
+export { NzModalComponent } from './modal.component';
+export { NzModalFooterDirective } from './modal-footer.directive';
+export { NzModalModule } from './modal.module';
diff --git a/components/modal/utils.ts b/components/modal/utils.ts
index 613273b1e63..9f1ca63758c 100644
--- a/components/modal/utils.ts
+++ b/components/modal/utils.ts
@@ -6,10 +6,10 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/
-import { NzModal2Component } from './modal.component';
-import { ModalConfig } from './nz-modal.type';
+import { ModalOptions } from './modal-types';
+import { NzModalComponent } from './modal.component';
-export function applyConfigDefaults(config: ModalConfig, defaultOptions: ModalConfig): ModalConfig {
+export function applyConfigDefaults(config: ModalOptions, defaultOptions: ModalOptions): ModalOptions {
return { ...defaultOptions, ...config };
}
@@ -26,7 +26,7 @@ export function setContentInstanceParams(
Object.assign(instance, params);
}
-export function getConfigFromComponent(component: NzModal2Component): ModalConfig {
+export function getConfigFromComponent(component: NzModalComponent): ModalOptions {
const {
nzMask,
nzMaskClosable,