UNPKG

ng-ytl-zorro-antd

Version:

An enterprise-class UI components based on Ant Design and Angular

279 lines (248 loc) 8.35 kB
import { Component, ElementRef, HostListener, Input, OnDestroy, OnInit, TemplateRef, ViewChild, ViewEncapsulation, } from '@angular/core'; import { NzLocaleService } from '../locale/index'; import { toBoolean } from '../util/convert'; import nzGlobalMonitor from '../util/nz-global-monitor'; import { NzModalSubject } from './nz-modal-subject.service'; interface Position { x: number; y: number; } @Component({ selector : 'nz-confirm', viewProviders: [ NzModalSubject ], encapsulation: ViewEncapsulation.None, template : ` <div [ngClass]="_customClass"> <div [ngClass]="_maskClassMap" [style.zIndex]="_zIndex"></div> <div tabindex="-1" role="dialog" (click)="closeFromMask($event)" class="ant-modal-wrap" [style.zIndex]="_zIndex" [ngStyle]="{ 'display': !_visible && !_animationStatus ? 'none' : 'block' }"> <div #confirm_content role="document" [ngClass]="_bodyClassMap" [ngStyle]="_bodyStyleMap"> <div class="ant-modal-content"> <div class="ant-modal-body"> <div style="zoom: 1; overflow: hidden;"> <div class="ant-confirm-body"> <i [ngClass]="_iconTypeCls"></i> <span class="ant-confirm-title"> <ng-template #defaultTitle>{{ _title }}</ng-template> <ng-template [ngTemplateOutlet]="_titleTpl || defaultTitle"></ng-template> </span> <div class="ant-confirm-content"> <ng-template #defaultContent> <div [innerHTML]="_content"></div> </ng-template> <ng-template [ngTemplateOutlet]="_contentTpl || defaultContent"></ng-template> </div> </div> <div class="ant-confirm-btns"> <ng-template [ngIf]="_cancelText"> <button nz-button [nzType]="'ghost'" [nzSize]="'large'" (click)="subject.next('onCancel')"> <span>{{ _cancelText }}</span> </button> </ng-template> <button nz-button #confirm_ok_btn [nzType]="'primary'" [nzSize]="'large'" [nzSize]="'large'" (click)="subject.next('onOk')" [nzLoading]="_confirmLoading"> <span>{{ _okText }}</span> </button> </div> </div> </div> </div> </div> <div tabindex="0" style="width: 0px; height: 0px; overflow: hidden;">sentinel</div> </div> </div> `, styleUrls : [ './style/index.less' ] }) export class NzConfirmComponent implements OnInit, OnDestroy { private _maskClosable = true; _confirmLoading = false; _visible = false; _prefixCls = 'ant-modal'; _prefixConfirmCls = 'ant-confirm'; _maskClassMap; _bodyClassMap; _bodyStyleMap; _width = '416px'; _zIndex = 1000; _iconTypeCls = 'anticon anticon-question-circle'; _title = ''; _titleTpl: TemplateRef<void>; _content = ''; _contentTpl: TemplateRef<void>; _okText = this._locale.translate('Modal.understood'); _cancelText = ''; _animationStatus = ''; _customClass = ''; _typeCls = `${this._prefixConfirmCls}-confirm`; @ViewChild('confirm_content') private contentEl: ElementRef; @Input() set nzVisible(value: boolean) { const visible = toBoolean(value); if (this._visible === visible) { return; } if (visible) { this.anmiateFade('enter'); this.subject.next('onShow'); // 每次触发点击事件的时候,通过全局监听的类,记录下点击的位置,计算动画的origin setTimeout(() => { this.setStyles({ x: nzGlobalMonitor.lastClickPos.x || 0, y: nzGlobalMonitor.lastClickPos.y || 0 }); }, 10); } else { this.anmiateFade('leave'); this.subject.next('onHide'); } this._visible = visible; // 设置全局的overflow样式 nzGlobalMonitor.setDocumentOverflowHidden(visible); } get nzVisible(): boolean { return this._visible; } @Input() set nzWidth(value: number | string) { this._width = typeof value === 'number' ? value + 'px' : value; } @Input() set nzClass(value: string) { this._customClass = value; } @Input() set nzZIndex(value: number) { this._zIndex = value; } @Input() set nzTitle(value: string | TemplateRef<void>) { // TODO: should guard for string instead, all types are theoretically structural if (value instanceof TemplateRef) { this._titleTpl = value; } else { this._title = value; } } @Input() set nzContent(value: string | TemplateRef<void>) { if (value instanceof TemplateRef) { this._contentTpl = value; } else { this._content = value; } } @Input() set nzMaskClosable(value: boolean) { this._maskClosable = toBoolean(value); } @Input() set nzOkText(value: string) { this._okText = value; } @Input() set nzCancelText(value: string) { this._cancelText = value; } @Input() set nzIconType(value: string) { if (value) { this._iconTypeCls = `anticon anticon-${value}`; } } @Input() set nzConfirmType(value: string) { if (value) { this._typeCls = `${this._prefixConfirmCls}-${value}`; } } @Input() set nzConfirmLoading(value: boolean) { this._confirmLoading = toBoolean(value); } @HostListener('keydown.esc', [ '$event' ]) onEsc(e: KeyboardEvent): void { if (this._maskClosable) { this.subject.next('onCancel'); } } @HostListener('keydown.enter', [ '$event' ]) onEnter(e: KeyboardEvent): void { this.subject.next('onOk'); } setStyles(origin?: { x: number, y: number }): void { const el = this.contentEl.nativeElement; const transformOrigin = origin ? `${origin.x - el.offsetLeft}px ${origin.y - el.offsetTop}px 0px` : ''; this._bodyStyleMap = { 'width' : this._width, 'transform-origin': transformOrigin }; } setClassMap(): void { this._maskClassMap = { [`${this._prefixCls}-mask`] : true, [`${this._prefixCls}-mask-hidden`]: !this._visible && !this._animationStatus, 'fade-enter' : this._animationStatus === 'enter', 'fade-enter-active' : this._animationStatus === 'enter', 'fade-leave' : this._animationStatus === 'leave', 'fade-leave-active' : this._animationStatus === 'leave' }; this._bodyClassMap = { [this._prefixCls] : true, [this._prefixConfirmCls]: true, [this._typeCls] : true, 'zoom-enter' : this._animationStatus === 'enter', 'zoom-enter-active' : this._animationStatus === 'enter', 'zoom-leave' : this._animationStatus === 'leave', 'zoom-leave-active' : this._animationStatus === 'leave' }; } anmiateFade(status: string): void { this._animationStatus = status; this.setClassMap(); setTimeout(_ => { this._animationStatus = ''; this.setClassMap(); this.subject.next(status === 'enter' ? 'onShown' : 'onHidden'); // modal打开后,默认焦点设置到modal上 if (status === 'enter') { this.contentEl.nativeElement.parentNode.focus(); } }, 200); } closeFromMask(e: MouseEvent): void { if (this._maskClosable && (e.target as HTMLElement).getAttribute('role') === 'dialog') { this.subject.next('onCancel'); } } constructor(public subject: NzModalSubject, private _locale: NzLocaleService) { } // 通过createComponent方法创建component时,ngOnInit不会被触发 ngOnInit(): void { this.setClassMap(); this.setStyles(); } ngOnDestroy(): void { if (this._visible) { nzGlobalMonitor.setDocumentOverflowHidden(false); } this.subject.next('onDestroy'); this.subject.unsubscribe(); this.subject = null; } }