UNPKG

ng-zorro-antd

Version:

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

597 lines (589 loc) 19.6 kB
import { NzIconModule } from 'ng-zorro-antd/icon'; import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms'; import { __decorate, __metadata } from 'tslib'; import { DOWN_ARROW, ENTER, ESCAPE, LEFT_ARROW, RIGHT_ARROW, TAB, UP_ARROW } from '@angular/cdk/keycodes'; import { ConnectionPositionPair, Overlay, OverlayConfig, OverlayModule } from '@angular/cdk/overlay'; import { TemplatePortal } from '@angular/cdk/portal'; import { DOCUMENT, CommonModule } from '@angular/common'; import { Directive, forwardRef, ElementRef, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, Inject, Input, Optional, Output, TemplateRef, ViewChild, ViewContainerRef, NgModule } from '@angular/core'; import { fromEvent, merge } from 'rxjs'; import { getCaretCoordinates, getMentions, DEFAULT_MENTION_POSITIONS, InputBoolean } from 'ng-zorro-antd/core'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NzMentionSuggestionDirective { } NzMentionSuggestionDirective.decorators = [ { type: Directive, args: [{ selector: '[nzMentionSuggestion]', exportAs: 'nzMentionSuggestion' },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ const NZ_MENTION_TRIGGER_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef((/** * @return {?} */ () => NzMentionTriggerDirective)), multi: true }; class NzMentionTriggerDirective { /** * @param {?} el */ constructor(el) { this.el = el; this.onFocusin = new EventEmitter(); this.onBlur = new EventEmitter(); this.onInput = new EventEmitter(); this.onKeydown = new EventEmitter(); this.onClick = new EventEmitter(); } /** * @return {?} */ ngOnDestroy() { this.completeEvents(); } /** * @return {?} */ completeEvents() { this.onFocusin.complete(); this.onBlur.complete(); this.onInput.complete(); this.onKeydown.complete(); this.onClick.complete(); } /** * @param {?=} caretPos * @return {?} */ focus(caretPos) { this.el.nativeElement.focus(); this.el.nativeElement.setSelectionRange(caretPos, caretPos); } /** * @param {?} mention * @return {?} */ insertMention(mention) { /** @type {?} */ const value = this.el.nativeElement.value; /** @type {?} */ const insertValue = mention.mention.trim() + ' '; /** @type {?} */ const newValue = [ value.slice(0, mention.startPos + 1), insertValue, value.slice(mention.endPos, value.length) ].join(''); this.el.nativeElement.value = newValue; this.focus(mention.startPos + insertValue.length + 1); this.onChange(newValue); this.value = newValue; } /** * @param {?} value * @return {?} */ writeValue(value) { this.value = value; if (typeof value === 'string') { this.el.nativeElement.value = value; } else { this.el.nativeElement.value = ''; } } /** * @param {?} fn * @return {?} */ registerOnChange(fn) { this.onChange = fn; } /** * @param {?} fn * @return {?} */ registerOnTouched(fn) { this.onTouched = fn; } } NzMentionTriggerDirective.decorators = [ { type: Directive, args: [{ selector: 'input[nzMentionTrigger], textarea[nzMentionTrigger]', exportAs: 'nzMentionTrigger', providers: [NZ_MENTION_TRIGGER_ACCESSOR], host: { autocomplete: 'off', '(focusin)': 'onFocusin.emit()', '(blur)': 'onBlur.emit()', '(input)': 'onInput.emit($event)', '(keydown)': 'onKeydown.emit($event)', '(click)': 'onClick.emit($event)' } },] } ]; /** @nocollapse */ NzMentionTriggerDirective.ctorParameters = () => [ { type: ElementRef } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NzMentionComponent { /** * @param {?} ngDocument * @param {?} changeDetectorRef * @param {?} overlay * @param {?} viewContainerRef */ constructor(ngDocument, // tslint:disable-line:no-any changeDetectorRef, overlay, viewContainerRef) { this.ngDocument = ngDocument; this.changeDetectorRef = changeDetectorRef; this.overlay = overlay; this.viewContainerRef = viewContainerRef; this.nzValueWith = (/** * @param {?} value * @return {?} */ value => value); // tslint:disable-line:no-any // tslint:disable-line:no-any this.nzPrefix = '@'; this.nzLoading = false; this.nzNotFoundContent = '无匹配结果,轻敲空格完成输入'; this.nzPlacement = 'bottom'; this.nzSuggestions = []; this.nzOnSelect = new EventEmitter(); this.nzOnSearchChange = new EventEmitter(); this.isOpen = false; this.filteredSuggestions = []; this.suggestionTemplate = null; // tslint:disable-line:no-any // tslint:disable-line:no-any this.activeIndex = -1; this.previousValue = null; } /** * @param {?} value * @return {?} */ set suggestionChild(value) { if (value) { this.suggestionTemplate = value; } } /** * @private * @return {?} */ get triggerNativeElement() { return this.trigger.el.nativeElement; } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { if (changes.hasOwnProperty('nzSuggestions')) { if (this.isOpen) { this.previousValue = null; this.activeIndex = -1; this.resetDropdown(false); } } } /** * @return {?} */ ngAfterContentInit() { this.bindTriggerEvents(); } /** * @return {?} */ ngOnDestroy() { this.closeDropdown(); } /** * @return {?} */ closeDropdown() { if (this.overlayRef && this.overlayRef.hasAttached()) { this.overlayRef.detach(); this.overlayBackdropClickSubscription.unsubscribe(); this.isOpen = false; this.changeDetectorRef.markForCheck(); } } /** * @return {?} */ openDropdown() { this.attachOverlay(); this.isOpen = true; this.changeDetectorRef.markForCheck(); } /** * @return {?} */ getMentions() { return getMentions(this.trigger.value, this.nzPrefix); } /** * @param {?} suggestion * @return {?} */ selectSuggestion(suggestion) { /** @type {?} */ const value = this.nzValueWith(suggestion); this.trigger.insertMention({ mention: value, startPos: this.cursorMentionStart, endPos: this.cursorMentionEnd }); this.nzOnSelect.emit(suggestion); this.closeDropdown(); this.activeIndex = -1; } /** * @private * @param {?} event * @return {?} */ handleInput(event) { /** @type {?} */ const target = (/** @type {?} */ (event.target)); this.trigger.onChange(target.value); this.trigger.value = target.value; this.resetDropdown(); } /** * @private * @param {?} event * @return {?} */ handleKeydown(event) { /** @type {?} */ const keyCode = event.keyCode; if (this.isOpen && keyCode === ENTER && this.activeIndex !== -1 && this.filteredSuggestions.length) { this.selectSuggestion(this.filteredSuggestions[this.activeIndex]); event.preventDefault(); } else if (keyCode === LEFT_ARROW || keyCode === RIGHT_ARROW) { this.resetDropdown(); event.stopPropagation(); } else { if (this.isOpen && (keyCode === TAB || keyCode === ESCAPE)) { this.closeDropdown(); return; } if (this.isOpen && keyCode === UP_ARROW) { this.setPreviousItemActive(); event.preventDefault(); event.stopPropagation(); } if (this.isOpen && keyCode === DOWN_ARROW) { this.setNextItemActive(); event.preventDefault(); event.stopPropagation(); } } } /** * @private * @return {?} */ handleClick() { this.resetDropdown(); } /** * @private * @return {?} */ bindTriggerEvents() { this.trigger.onInput.subscribe((/** * @param {?} e * @return {?} */ (e) => this.handleInput(e))); this.trigger.onKeydown.subscribe((/** * @param {?} e * @return {?} */ (e) => this.handleKeydown(e))); this.trigger.onClick.subscribe((/** * @return {?} */ () => this.handleClick())); } /** * @private * @param {?} value * @param {?} emit * @return {?} */ suggestionsFilter(value, emit) { /** @type {?} */ const suggestions = value.substring(1); if (this.previousValue === value) { return; } this.previousValue = value; if (emit) { this.nzOnSearchChange.emit({ value: (/** @type {?} */ (this.cursorMention)).substring(1), prefix: (/** @type {?} */ (this.cursorMention))[0] }); } /** @type {?} */ const searchValue = suggestions.toLowerCase(); this.filteredSuggestions = this.nzSuggestions.filter((/** * @param {?} suggestion * @return {?} */ suggestion => this.nzValueWith(suggestion) .toLowerCase() .includes(searchValue))); } /** * @private * @param {?=} emit * @return {?} */ resetDropdown(emit = true) { this.resetCursorMention(); if (typeof this.cursorMention !== 'string' || !this.canOpen()) { this.closeDropdown(); return; } this.suggestionsFilter(this.cursorMention, emit); /** @type {?} */ const activeIndex = this.filteredSuggestions.indexOf(this.cursorMention.substring(1)); this.activeIndex = activeIndex >= 0 ? activeIndex : 0; this.openDropdown(); } /** * @private * @return {?} */ setNextItemActive() { this.activeIndex = this.activeIndex + 1 <= this.filteredSuggestions.length - 1 ? this.activeIndex + 1 : 0; this.changeDetectorRef.markForCheck(); } /** * @private * @return {?} */ setPreviousItemActive() { this.activeIndex = this.activeIndex - 1 < 0 ? this.filteredSuggestions.length - 1 : this.activeIndex - 1; this.changeDetectorRef.markForCheck(); } /** * @private * @return {?} */ canOpen() { /** @type {?} */ const element = this.triggerNativeElement; return !element.readOnly && !element.disabled; } /** * @private * @return {?} */ resetCursorMention() { /** @type {?} */ const value = this.triggerNativeElement.value.replace(/[\r\n]/g, ' ') || ''; /** @type {?} */ const selectionStart = (/** @type {?} */ (this.triggerNativeElement.selectionStart)); /** @type {?} */ const prefix = typeof this.nzPrefix === 'string' ? [this.nzPrefix] : this.nzPrefix; /** @type {?} */ let i = prefix.length; while (i >= 0) { /** @type {?} */ const startPos = value.lastIndexOf(prefix[i], selectionStart); /** @type {?} */ const endPos = value.indexOf(' ', selectionStart) > -1 ? value.indexOf(' ', selectionStart) : value.length; /** @type {?} */ const mention = value.substring(startPos, endPos); if ((startPos > 0 && value[startPos - 1] !== ' ') || startPos < 0 || mention.includes(prefix[i], 1) || mention.includes(' ')) { this.cursorMention = null; this.cursorMentionStart = -1; this.cursorMentionEnd = -1; } else { this.cursorMention = mention; this.cursorMentionStart = startPos; this.cursorMentionEnd = endPos; return; } i--; } } /** * @private * @return {?} */ updatePositions() { /** @type {?} */ const coordinates = getCaretCoordinates(this.triggerNativeElement, this.cursorMentionStart); /** @type {?} */ const top = coordinates.top - this.triggerNativeElement.getBoundingClientRect().height - this.triggerNativeElement.scrollTop + (this.nzPlacement === 'bottom' ? coordinates.height : 0); /** @type {?} */ const left = coordinates.left - this.triggerNativeElement.scrollLeft; this.positionStrategy.withDefaultOffsetX(left).withDefaultOffsetY(top); if (this.nzPlacement === 'bottom') { this.positionStrategy.withPositions([DEFAULT_MENTION_POSITIONS[0]]); } if (this.nzPlacement === 'top') { this.positionStrategy.withPositions([DEFAULT_MENTION_POSITIONS[1]]); } this.positionStrategy.apply(); } /** * @private * @return {?} */ subscribeOverlayBackdropClick() { return merge(fromEvent(this.ngDocument, 'click'), fromEvent(this.ngDocument, 'touchend')).subscribe((/** * @param {?} event * @return {?} */ (event) => { /** @type {?} */ const clickTarget = (/** @type {?} */ (event.target)); if (clickTarget !== this.trigger.el.nativeElement && this.isOpen) { this.closeDropdown(); } })); } /** * @private * @return {?} */ attachOverlay() { if (!this.overlayRef) { this.portal = new TemplatePortal(this.suggestionsTemp, this.viewContainerRef); this.overlayRef = this.overlay.create(this.getOverlayConfig()); } if (this.overlayRef && !this.overlayRef.hasAttached()) { this.overlayRef.attach(this.portal); this.overlayBackdropClickSubscription = this.subscribeOverlayBackdropClick(); } this.updatePositions(); } /** * @private * @return {?} */ getOverlayConfig() { return new OverlayConfig({ positionStrategy: this.getOverlayPosition(), scrollStrategy: this.overlay.scrollStrategies.reposition() }); } /** * @private * @return {?} */ getOverlayPosition() { /** @type {?} */ const positions = [ new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }), new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'bottom' }) ]; this.positionStrategy = this.overlay .position() .flexibleConnectedTo(this.trigger.el) .withPositions(positions) .withFlexibleDimensions(false) .withPush(false); return this.positionStrategy; } } NzMentionComponent.decorators = [ { type: Component, args: [{ selector: 'nz-mention', exportAs: 'nzMention', template: "<ng-content></ng-content>\n<ng-template #suggestions>\n <ul class=\"ant-mention-dropdown\">\n <li class=\"ant-mention-dropdown-item\"\n *ngFor=\"let suggestion of filteredSuggestions; let i = index\"\n [class.focus]=\"i === activeIndex\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"selectSuggestion(suggestion)\">\n <ng-container *ngIf=\"suggestionTemplate else defaultSuggestion\">\n <ng-container *ngTemplateOutlet=\"suggestionTemplate; context: {$implicit: suggestion}\"></ng-container>\n </ng-container>\n <ng-template #defaultSuggestion>{{ nzValueWith(suggestion) }}</ng-template>\n </li>\n <li class=\"ant-mention-dropdown-notfound ant-mention-dropdown-item\"\n *ngIf=\"filteredSuggestions.length === 0\">\n <span *ngIf=\"nzLoading\"><i nz-icon type=\"loading\"></i></span>\n <span *ngIf=\"!nzLoading\">{{ nzNotFoundContent }}</span>\n </li>\n </ul>\n</ng-template>\n", preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, styles: [` .ant-mention-dropdown { top: 100%; left: 0; position: relative; width: 100%; margin-top: 4px; margin-bottom: 4px; } `] }] } ]; /** @nocollapse */ NzMentionComponent.ctorParameters = () => [ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT,] }] }, { type: ChangeDetectorRef }, { type: Overlay }, { type: ViewContainerRef } ]; NzMentionComponent.propDecorators = { nzValueWith: [{ type: Input }], nzPrefix: [{ type: Input }], nzLoading: [{ type: Input }], nzNotFoundContent: [{ type: Input }], nzPlacement: [{ type: Input }], nzSuggestions: [{ type: Input }], nzOnSelect: [{ type: Output }], nzOnSearchChange: [{ type: Output }], trigger: [{ type: ContentChild, args: [NzMentionTriggerDirective,] }], suggestionsTemp: [{ type: ViewChild, args: [TemplateRef,] }], suggestionChild: [{ type: ContentChild, args: [NzMentionSuggestionDirective, { read: TemplateRef },] }] }; __decorate([ InputBoolean(), __metadata("design:type", Object) ], NzMentionComponent.prototype, "nzLoading", void 0); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ const COMPONENTS = [NzMentionComponent, NzMentionTriggerDirective, NzMentionSuggestionDirective]; class NzMentionModule { } NzMentionModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule, FormsModule, OverlayModule, NzIconModule], declarations: [...COMPONENTS], exports: [...COMPONENTS] },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { NzMentionModule, NzMentionComponent, NZ_MENTION_TRIGGER_ACCESSOR, NzMentionTriggerDirective, NzMentionSuggestionDirective }; //# sourceMappingURL=ng-zorro-antd-mention.js.map