ng-devui
Version:
DevUI components based on Angular
803 lines (796 loc) • 50 kB
JavaScript
import { __decorate, __metadata } from 'tslib';
import * as i5 from '@angular/cdk/overlay';
import { CdkConnectedOverlay, CdkOverlayOrigin, OverlayModule } from '@angular/cdk/overlay';
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, Component, Input, Output, ViewChild, forwardRef, Directive, HostBinding, HostListener, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import * as i3 from 'ng-devui/i18n';
import * as i2$1 from 'ng-devui/position';
import { PositioningModule } from 'ng-devui/position';
import * as i4 from 'ng-devui/utils';
import { fadeInOut, removeClassFromOrigin, AppendToBodyDirectionsConfig, addClassToOrigin, WithConfig, LazyLoadModule, HighlightModule } from 'ng-devui/utils';
import { Subject, of, fromEvent } from 'rxjs';
import { takeUntil, map, filter, debounceTime, tap, switchMap } from 'rxjs/operators';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i5$1 from 'ng-devui/loading';
import { LoadingModule } from 'ng-devui/loading';
class AutoCompleteConfig {
constructor() {
this.autoComplete = {
delay: 300,
minLength: 1,
itemTemplate: null,
noResultItemTemplate: null,
formatter: (item) => (item ? item.label || item.toString() : ''),
valueParser: (item) => (item ? item.label || item.toString() : ''),
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteConfig, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteConfig, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class AutoCompletePopupComponent {
constructor(autoCompleteConfig, elementRef) {
this.autoCompleteConfig = autoCompleteConfig;
this.elementRef = elementRef;
this.maxHeight = 300;
this.disabled = false;
this.customViewDirection = 'bottom';
this.isSearching = false;
this.appendToBody = false;
this.cdkOverlayOffsetY = 0;
this.showAnimation = true;
this.hoverItem = new EventEmitter();
this.activeIndex = 0;
this.hoverIndex = 0;
this.labelMinHeight = 20; // position.top小于20px时候,表示光标在第一行
this.showLoading = false;
this.popPosition = 'bottom';
this.onChange = (_) => null;
this.onTouched = () => null;
this.formatter = this.autoCompleteConfig.autoComplete.formatter;
}
writeValue(obj) {
this.value = obj;
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
onSelect(event, item) {
if (this.disabledKey && item && item[this.disabledKey]) {
event.preventDefault();
event.stopPropagation();
return;
}
if (this.overview === 'single') {
// 单选场景和单行场景不需要冒泡
event.preventDefault();
event.stopPropagation();
}
this.value = item;
this.onTouched();
this.onChange({ type: 'select', value: this.value });
}
selectCurrentItem(event) {
this.activeIndex = this.hoverIndex;
this.onSelect(event, this.source[this.hoverIndex]);
}
onActiveIndexChange(index) {
this.activeIndex = index;
}
reset() {
this.activeIndex = 0;
this.hoverIndex = 0;
}
scrollToActive(index) {
const that = this;
setTimeout(() => {
const scrollIndex = index === undefined ? this.activeIndex : index;
const selectIndex = scrollIndex;
const scrollPane = that.dropdownUl.nativeElement.children[selectIndex];
if (scrollPane.scrollIntoViewIfNeeded) {
scrollPane.scrollIntoViewIfNeeded(false);
}
else {
const containerInfo = that.dropdownUl.nativeElement.getBoundingClientRect();
const elementInfo = scrollPane.getBoundingClientRect();
if (elementInfo.bottom > containerInfo.bottom || elementInfo.top < containerInfo.top) {
scrollPane.scrollIntoView(false);
}
}
});
}
next() {
if (this.isOpen && this.source && this.source.length) {
if (this.hoverIndex === this.source.length - 1) {
this.hoverIndex = 0;
this.scrollToActive(this.hoverIndex);
return;
}
this.hoverIndex = this.hoverIndex + 1;
this.scrollToActive(this.hoverIndex);
}
}
prev() {
if (this.isOpen && this.source && this.source.length) {
if (this.hoverIndex === 0) {
this.hoverIndex = this.source.length - 1;
this.scrollToActive(this.hoverIndex);
return;
}
this.hoverIndex = this.hoverIndex - 1;
this.scrollToActive(this.hoverIndex);
}
}
trackByFn(index, item) {
return index;
}
animationEnd($event) {
if (!this.isOpen && this.selectMenuElement) {
const targetElement = this.selectMenuElement.nativeElement;
setTimeout(() => {
targetElement.style.display = 'none';
});
}
}
loadMoreEvent($event) {
this.showLoading = true;
this.onChange({ type: 'loadMore', value: this });
}
loadFinish($event) {
this.showLoading = false;
}
onPositionChange(position) {
this.popPosition = position.connectionPair.originY;
}
onMouseOver(event, item) {
this.hoverItem.emit(item);
}
hidePopup() { }
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompletePopupComponent, deps: [{ token: AutoCompleteConfig }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AutoCompletePopupComponent, selector: "d-auto-complete-popup", inputs: { width: "width", cssClass: "cssClass", maxHeight: "maxHeight", disabled: "disabled", disabledKey: "disabledKey", source: "source", position: "position", isOpen: "isOpen", term: "term", popTipsText: "popTipsText", overview: "overview", itemTemplate: "itemTemplate", noResultItemTemplate: "noResultItemTemplate", customViewTemplate: "customViewTemplate", customViewDirection: "customViewDirection", searchingTemplate: "searchingTemplate", isSearching: "isSearching", formatter: "formatter", dropdown: "dropdown", selectWidth: "selectWidth", enableLazyLoad: "enableLazyLoad", appendToBody: "appendToBody", cdkOverlayOffsetY: "cdkOverlayOffsetY", origin: "origin", showAnimation: "showAnimation" }, outputs: { hoverItem: "hoverItem" }, viewQueries: [{ propertyName: "selectMenuElement", first: true, predicate: ["selectMenuElement"], descendants: true }, { propertyName: "dropdownUl", first: true, predicate: ["dropdownUl"], descendants: true }, { propertyName: "connectedOverlay", first: true, predicate: CdkConnectedOverlay, descendants: true }], ngImport: i0, template: "<ng-container *ngIf=\"appendToBody\">\n <ng-template\n cdk-connected-overlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayWidth]=\"width\"\n [cdkConnectedOverlayOpen]=\"isOpen && !disabled\"\n [cdkConnectedOverlayOffsetY]=\"cdkOverlayOffsetY\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n (positionChange)=\"onPositionChange($event)\"\n (detach)=\"isOpen && hidePopup()\"\n >\n <ng-template [ngTemplateOutlet]=\"popTpl\"> </ng-template>\n </ng-template>\n</ng-container>\n\n<ng-container *ngIf=\"!appendToBody\">\n <ng-template [ngTemplateOutlet]=\"popTpl\"> </ng-template>\n</ng-container>\n\n<ng-template #popTpl>\n <div\n class=\"devui-dropdown-menu\"\n [ngClass]=\"{\n 'devui-dropdown-menu-cdk': appendToBody,\n 'devui-custom-right': customViewTemplate && customViewDirection === 'right',\n 'devui-custom-left': customViewTemplate && customViewDirection === 'left',\n 'devui-custom-top': customViewTemplate && customViewDirection === 'top'\n }\"\n [style.display]=\"isOpen && (source?.length || noResultItemTemplate) && !disabled ? 'inline-block' : 'none'\"\n [style.top]=\"overview === 'multiline' ? (position?.top < labelMinHeight ? '50%' : '100%') : '100%'\"\n [style.left]=\"overview === 'multiline' ? position?.left + 'px' : '0'\"\n [@fadeInOut]=\"isOpen && !disabled ? (appendToBody ? popPosition : 'bottom') : 'void'\"\n (@fadeInOut.done)=\"animationEnd($event)\"\n [@.disabled]=\"!showAnimation\"\n #selectMenuElement\n dLoading\n [showLoading]=\"showLoading\"\n [backdrop]=\"true\"\n >\n <ul\n class=\"devui-list-unstyled devui-scrollbar scroll-height devui-dropdown-menu-wrap devui-auto-complete-list\"\n [style.maxHeight]=\"maxHeight + 'px'\"\n dLazyLoad\n [enableLazyLoad]=\"enableLazyLoad\"\n (loadMore)=\"loadMoreEvent($event)\"\n #dropdownUl\n >\n <ng-container *ngIf=\"!isSearching || !searchingTemplate\">\n <li *ngIf=\"popTipsText && popTipsText.length > 0\" class=\"devui-popup-tips\">\n {{ popTipsText }}\n </li>\n <li\n *ngFor=\"let item of source; let $index = index; trackBy: trackByFn\"\n class=\"devui-dropdown-item\"\n [title]=\"formatter(item)\"\n [ngClass]=\"{\n selected: $index == activeIndex,\n 'devui-dropdown-bg': $index == hoverIndex,\n disabled: disabledKey && item[disabledKey]\n }\"\n (click)=\"onSelect($event, item)\"\n (mouseover)=\"onMouseOver($event, item)\"\n >\n <ng-template\n [ngTemplateOutlet]=\"itemTemplate || defaultItemTemplate\"\n [ngTemplateOutletContext]=\"{\n formatter: formatter,\n term: term,\n source: source,\n item: item,\n $index: $index\n }\"\n >\n </ng-template>\n </li>\n <div class=\"devui-no-data-tip\" *ngIf=\"!source?.length && noResultItemTemplate\">\n <ng-template [ngTemplateOutlet]=\"noResultItemTemplate\" [ngTemplateOutletContext]=\"{ term: term, source: source }\"> </ng-template>\n </div>\n </ng-container>\n <div class=\"devui-no-data-tip\" *ngIf=\"isSearching && searchingTemplate\">\n <ng-template [ngTemplateOutlet]=\"searchingTemplate\" [ngTemplateOutletContext]=\"{ term: term }\"> </ng-template>\n </div>\n </ul>\n <ng-container *ngIf=\"customViewTemplate\">\n <div class=\"devui-select-custom-area\">\n <ng-template [ngTemplateOutlet]=\"customViewTemplate\" [ngTemplateOutletContext]=\"{ $implicit: this }\"></ng-template>\n </div>\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #defaultItemTemplate let-item=\"item\" let-term=\"term\">\n <d-highlight [value]=\"formatter(item)\" [term]=\"term\"></d-highlight>\n</ng-template>\n", styles: [".devui-dropdown-menu{width:100%;display:block}.devui-dropdown-menu.devui-custom-right,.devui-dropdown-menu.devui-custom-left,.devui-dropdown-menu.devui-custom-top{min-width:400px;display:flex!important}.devui-dropdown-menu.devui-custom-right>.devui-dropdown-menu-wrap,.devui-dropdown-menu.devui-custom-left>.devui-dropdown-menu-wrap,.devui-dropdown-menu.devui-custom-top>.devui-dropdown-menu-wrap{display:inline-block}.devui-dropdown-menu.devui-custom-right>.devui-dropdown-menu-wrap>.devui-no-data-tip,.devui-dropdown-menu.devui-custom-left>.devui-dropdown-menu-wrap>.devui-no-data-tip,.devui-dropdown-menu.devui-custom-top>.devui-dropdown-menu-wrap>.devui-no-data-tip{padding:12px}.devui-dropdown-menu.devui-custom-right>.devui-select-custom-area,.devui-dropdown-menu.devui-custom-left>.devui-select-custom-area,.devui-dropdown-menu.devui-custom-top>.devui-select-custom-area{display:inline-block;overflow:auto}.devui-dropdown-menu.devui-custom-right:not(.devui-custom-top)>.devui-dropdown-menu-wrap,.devui-dropdown-menu.devui-custom-left:not(.devui-custom-top)>.devui-dropdown-menu-wrap,.devui-dropdown-menu.devui-custom-top:not(.devui-custom-top)>.devui-dropdown-menu-wrap{width:calc(50% - 1px)}.devui-dropdown-menu.devui-custom-right:not(.devui-custom-top)>.devui-select-custom-area,.devui-dropdown-menu.devui-custom-left:not(.devui-custom-top)>.devui-select-custom-area,.devui-dropdown-menu.devui-custom-top:not(.devui-custom-top)>.devui-select-custom-area{width:50%}.devui-dropdown-menu.devui-custom-right>.devui-select-custom-area:before,.devui-dropdown-menu.devui-custom-left>.devui-select-custom-area:before,.devui-dropdown-menu.devui-custom-top>.devui-select-custom-area:before{display:none}.devui-dropdown-menu.devui-custom-top{flex-direction:column-reverse}.devui-dropdown-menu.devui-custom-left>.devui-select-custom-area{border-right:1px solid var(--devui-dividing-line, #f0f0f0);order:-1}.devui-dropdown-menu.devui-custom-right>.devui-select-custom-area{border-left:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-dropdown-menu.devui-custom-top>.devui-select-custom-area{border-bottom:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-select-custom-area:before{display:block;content:\"\";width:calc(100% - 20px);margin:0 10px;height:1px;border-top:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-dropdown-menu-cdk{position:static}ul.devui-list-unstyled{margin:0}.devui-popup-tips{color:var(--devui-text-weak, #333333);padding:4px 12px}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i5.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i4.LazyLoadDirective, selector: "[dLazyLoad]", inputs: ["enableLazyLoad", "contentMode", "target", "imgLoadSrc", "direction"], outputs: ["loadMore"] }, { kind: "directive", type: i5$1.LoadingDirective, selector: "[dLoading]", inputs: ["backdrop", "message", "positionType", "showLoading", "view", "zIndex", "loading", "loadingStyle", "loadingTemplateRef"], exportAs: ["dLoading"] }, { kind: "component", type: i4.HighlightComponent, selector: "d-highlight", inputs: ["value", "term", "highlightClass"] }], animations: [fadeInOut] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompletePopupComponent, decorators: [{
type: Component,
args: [{ selector: 'd-auto-complete-popup', animations: [fadeInOut], preserveWhitespaces: false, template: "<ng-container *ngIf=\"appendToBody\">\n <ng-template\n cdk-connected-overlay\n [cdkConnectedOverlayOrigin]=\"origin\"\n [cdkConnectedOverlayWidth]=\"width\"\n [cdkConnectedOverlayOpen]=\"isOpen && !disabled\"\n [cdkConnectedOverlayOffsetY]=\"cdkOverlayOffsetY\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n (positionChange)=\"onPositionChange($event)\"\n (detach)=\"isOpen && hidePopup()\"\n >\n <ng-template [ngTemplateOutlet]=\"popTpl\"> </ng-template>\n </ng-template>\n</ng-container>\n\n<ng-container *ngIf=\"!appendToBody\">\n <ng-template [ngTemplateOutlet]=\"popTpl\"> </ng-template>\n</ng-container>\n\n<ng-template #popTpl>\n <div\n class=\"devui-dropdown-menu\"\n [ngClass]=\"{\n 'devui-dropdown-menu-cdk': appendToBody,\n 'devui-custom-right': customViewTemplate && customViewDirection === 'right',\n 'devui-custom-left': customViewTemplate && customViewDirection === 'left',\n 'devui-custom-top': customViewTemplate && customViewDirection === 'top'\n }\"\n [style.display]=\"isOpen && (source?.length || noResultItemTemplate) && !disabled ? 'inline-block' : 'none'\"\n [style.top]=\"overview === 'multiline' ? (position?.top < labelMinHeight ? '50%' : '100%') : '100%'\"\n [style.left]=\"overview === 'multiline' ? position?.left + 'px' : '0'\"\n [@fadeInOut]=\"isOpen && !disabled ? (appendToBody ? popPosition : 'bottom') : 'void'\"\n (@fadeInOut.done)=\"animationEnd($event)\"\n [@.disabled]=\"!showAnimation\"\n #selectMenuElement\n dLoading\n [showLoading]=\"showLoading\"\n [backdrop]=\"true\"\n >\n <ul\n class=\"devui-list-unstyled devui-scrollbar scroll-height devui-dropdown-menu-wrap devui-auto-complete-list\"\n [style.maxHeight]=\"maxHeight + 'px'\"\n dLazyLoad\n [enableLazyLoad]=\"enableLazyLoad\"\n (loadMore)=\"loadMoreEvent($event)\"\n #dropdownUl\n >\n <ng-container *ngIf=\"!isSearching || !searchingTemplate\">\n <li *ngIf=\"popTipsText && popTipsText.length > 0\" class=\"devui-popup-tips\">\n {{ popTipsText }}\n </li>\n <li\n *ngFor=\"let item of source; let $index = index; trackBy: trackByFn\"\n class=\"devui-dropdown-item\"\n [title]=\"formatter(item)\"\n [ngClass]=\"{\n selected: $index == activeIndex,\n 'devui-dropdown-bg': $index == hoverIndex,\n disabled: disabledKey && item[disabledKey]\n }\"\n (click)=\"onSelect($event, item)\"\n (mouseover)=\"onMouseOver($event, item)\"\n >\n <ng-template\n [ngTemplateOutlet]=\"itemTemplate || defaultItemTemplate\"\n [ngTemplateOutletContext]=\"{\n formatter: formatter,\n term: term,\n source: source,\n item: item,\n $index: $index\n }\"\n >\n </ng-template>\n </li>\n <div class=\"devui-no-data-tip\" *ngIf=\"!source?.length && noResultItemTemplate\">\n <ng-template [ngTemplateOutlet]=\"noResultItemTemplate\" [ngTemplateOutletContext]=\"{ term: term, source: source }\"> </ng-template>\n </div>\n </ng-container>\n <div class=\"devui-no-data-tip\" *ngIf=\"isSearching && searchingTemplate\">\n <ng-template [ngTemplateOutlet]=\"searchingTemplate\" [ngTemplateOutletContext]=\"{ term: term }\"> </ng-template>\n </div>\n </ul>\n <ng-container *ngIf=\"customViewTemplate\">\n <div class=\"devui-select-custom-area\">\n <ng-template [ngTemplateOutlet]=\"customViewTemplate\" [ngTemplateOutletContext]=\"{ $implicit: this }\"></ng-template>\n </div>\n </ng-container>\n </div>\n</ng-template>\n\n<ng-template #defaultItemTemplate let-item=\"item\" let-term=\"term\">\n <d-highlight [value]=\"formatter(item)\" [term]=\"term\"></d-highlight>\n</ng-template>\n", styles: [".devui-dropdown-menu{width:100%;display:block}.devui-dropdown-menu.devui-custom-right,.devui-dropdown-menu.devui-custom-left,.devui-dropdown-menu.devui-custom-top{min-width:400px;display:flex!important}.devui-dropdown-menu.devui-custom-right>.devui-dropdown-menu-wrap,.devui-dropdown-menu.devui-custom-left>.devui-dropdown-menu-wrap,.devui-dropdown-menu.devui-custom-top>.devui-dropdown-menu-wrap{display:inline-block}.devui-dropdown-menu.devui-custom-right>.devui-dropdown-menu-wrap>.devui-no-data-tip,.devui-dropdown-menu.devui-custom-left>.devui-dropdown-menu-wrap>.devui-no-data-tip,.devui-dropdown-menu.devui-custom-top>.devui-dropdown-menu-wrap>.devui-no-data-tip{padding:12px}.devui-dropdown-menu.devui-custom-right>.devui-select-custom-area,.devui-dropdown-menu.devui-custom-left>.devui-select-custom-area,.devui-dropdown-menu.devui-custom-top>.devui-select-custom-area{display:inline-block;overflow:auto}.devui-dropdown-menu.devui-custom-right:not(.devui-custom-top)>.devui-dropdown-menu-wrap,.devui-dropdown-menu.devui-custom-left:not(.devui-custom-top)>.devui-dropdown-menu-wrap,.devui-dropdown-menu.devui-custom-top:not(.devui-custom-top)>.devui-dropdown-menu-wrap{width:calc(50% - 1px)}.devui-dropdown-menu.devui-custom-right:not(.devui-custom-top)>.devui-select-custom-area,.devui-dropdown-menu.devui-custom-left:not(.devui-custom-top)>.devui-select-custom-area,.devui-dropdown-menu.devui-custom-top:not(.devui-custom-top)>.devui-select-custom-area{width:50%}.devui-dropdown-menu.devui-custom-right>.devui-select-custom-area:before,.devui-dropdown-menu.devui-custom-left>.devui-select-custom-area:before,.devui-dropdown-menu.devui-custom-top>.devui-select-custom-area:before{display:none}.devui-dropdown-menu.devui-custom-top{flex-direction:column-reverse}.devui-dropdown-menu.devui-custom-left>.devui-select-custom-area{border-right:1px solid var(--devui-dividing-line, #f0f0f0);order:-1}.devui-dropdown-menu.devui-custom-right>.devui-select-custom-area{border-left:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-dropdown-menu.devui-custom-top>.devui-select-custom-area{border-bottom:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-select-custom-area:before{display:block;content:\"\";width:calc(100% - 20px);margin:0 10px;height:1px;border-top:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-dropdown-menu-cdk{position:static}ul.devui-list-unstyled{margin:0}.devui-popup-tips{color:var(--devui-text-weak, #333333);padding:4px 12px}\n"] }]
}], ctorParameters: () => [{ type: AutoCompleteConfig }, { type: i0.ElementRef }], propDecorators: { width: [{
type: Input
}], cssClass: [{
type: Input
}], maxHeight: [{
type: Input
}], disabled: [{
type: Input
}], disabledKey: [{
type: Input
}], source: [{
type: Input
}], position: [{
type: Input
}], isOpen: [{
type: Input
}], term: [{
type: Input
}], popTipsText: [{
type: Input
}], overview: [{
type: Input
}], itemTemplate: [{
type: Input
}], noResultItemTemplate: [{
type: Input
}], customViewTemplate: [{
type: Input
}], customViewDirection: [{
type: Input
}], searchingTemplate: [{
type: Input
}], isSearching: [{
type: Input
}], formatter: [{
type: Input
}], dropdown: [{
type: Input
}], selectWidth: [{
type: Input
}], enableLazyLoad: [{
type: Input
}], appendToBody: [{
type: Input
}], cdkOverlayOffsetY: [{
type: Input
}], origin: [{
type: Input
}], showAnimation: [{
type: Input
}], hoverItem: [{
type: Output
}], selectMenuElement: [{
type: ViewChild,
args: ['selectMenuElement']
}], dropdownUl: [{
type: ViewChild,
args: ['dropdownUl']
}], connectedOverlay: [{
type: ViewChild,
args: [CdkConnectedOverlay]
}] } });
class AutoCompleteDirective {
get hasGlowStyle() {
return this.showGlowStyle;
}
set isSearching(isSearching) {
if (this.popupRef && this.searchingTemplate) {
const pop = this.popupRef.instance;
pop.isSearching = isSearching;
pop.searchingTemplate = this.searchingTemplate;
if (isSearching) {
pop.isOpen = true;
}
}
}
constructor(autoCompleteConfig, elementRef, viewContainerRef, componentFactoryResolver, renderer, injector, positionService, changeDetectorRef, i18n, devConfigService, scrollStrategyOption) {
this.autoCompleteConfig = autoCompleteConfig;
this.elementRef = elementRef;
this.viewContainerRef = viewContainerRef;
this.componentFactoryResolver = componentFactoryResolver;
this.renderer = renderer;
this.injector = injector;
this.positionService = positionService;
this.changeDetectorRef = changeDetectorRef;
this.i18n = i18n;
this.devConfigService = devConfigService;
this.scrollStrategyOption = scrollStrategyOption;
this.autocomplete = 'off';
this.autocapitalize = 'off';
this.autocorrect = 'off';
this.delay = 300;
this.showGlowStyle = true;
this.appendToBody = false;
this.appendToBodyDirections = ['rightDown', 'leftDown', 'rightUp', 'leftUp'];
this.cdkOverlayOffsetY = 0; // 内部使用不开放
this.sceneType = '';
this.tipsText = ''; // 提示文字
this.maxHeight = 300;
this.showAnimation = true;
/**
* 【可选】启用数据懒加载,默认不启用
*/
this.enableLazyLoad = false;
this.retainInputValue = false;
this.allowEmptyValueSearch = false; // 在value为空时,是否允许进行搜索
this.customViewDirection = 'bottom';
this.loadMore = new EventEmitter();
this.selectValue = new EventEmitter();
this.transInputFocusEmit = new EventEmitter(); // input状态传给父组件函数
/**
* @deprecated
*/
this.changeDropDownStatus = new EventEmitter();
this.toggleChange = new EventEmitter();
this.hoverItem = new EventEmitter();
this.KEYBOARD_EVENT_NOT_REFRESH = ['escape', 'enter', 'arrowup', 'arrowdown', /* ie 10 edge */ 'esc', 'up', 'down'];
this.popTipsText = '';
this.focus = false;
this.SELECT_TYPES = ['select', 'select-extend'];
this.destroy$ = new Subject();
this.onChange = (_) => null;
this.onTouched = () => null;
this.hidePopup = () => {
if (this.popupRef) {
this.popupRef.instance.isOpen = false;
removeClassFromOrigin(this.elementRef);
this.changeDropDownStatus.emit(false);
this.toggleChange.emit(false);
}
};
this.scrollStrategy = this.scrollStrategyOption.reposition();
}
ngOnInit() {
this.init();
this.setI18nText();
this.valueChanges = this.registerInputEvent(this.elementRef);
// 调用时机:input keyup
this.subscription = this.valueChanges.subscribe((source) => this.onSourceChange(source));
// 动态的创建了popup组件,
const factory = this.componentFactoryResolver.resolveComponentFactory(AutoCompletePopupComponent);
this.popupRef = this.viewContainerRef.createComponent(factory, this.viewContainerRef.length, this.injector);
this.popupRef.instance.hoverItem.subscribe((item) => this.hoverItem.emit(item));
this.fillPopup(this.source);
if (!this.searchFn) {
this.searchFn = (term) => {
return of(this.source.filter((item) => this.formatter(item).toLowerCase().indexOf(term.toLowerCase()) !== -1));
};
}
// 调用时机:选中回车或者鼠标单击下拉选项
this.popupRef.instance.registerOnChange((item) => {
if (item.type === 'loadMore') {
this.loadMore.emit(item.value);
return;
}
this.writeValue(item.value);
this.onChange(item.value);
this.hidePopup();
this.selectValue.emit(item.value);
if (this.overview && this.overview !== 'single') {
setTimeout(() => {
// 这里稍微延迟一下,等待光标的位置发生变化,好重新获取光标的位置
this.restLatestSource();
}, 0);
}
});
this.setPositions();
}
ngOnChanges(changes) {
const { appendToBodyDirections, appendToBodyScrollStrategy, source } = changes;
const globalScrollStrategy = this.devConfigService.getConfigForApi('appendToBodyScrollStrategy');
if (source && this.popupRef) {
this.fillPopup(this.source);
}
if (appendToBodyDirections) {
this.setPositions();
}
if (this.appendToBodyScrollStrategy && (appendToBodyScrollStrategy || globalScrollStrategy)) {
const func = this.scrollStrategyOption[this.appendToBodyScrollStrategy];
this.scrollStrategy = func();
if (this.popupRef) {
this.popupRef.instance.scrollStrategy = this.scrollStrategy;
}
}
}
init() {
this.minLength = this.minLength ?? this.autoCompleteConfig.autoComplete.minLength;
this.itemTemplate = this.itemTemplate || this.autoCompleteConfig.autoComplete.itemTemplate;
this.noResultItemTemplate = this.noResultItemTemplate || this.autoCompleteConfig.autoComplete.noResultItemTemplate;
this.formatter = this.formatter || this.autoCompleteConfig.autoComplete.formatter;
this.valueParser = this.valueParser || this.autoCompleteConfig.autoComplete.valueParser;
}
setPositions() {
if (this.popupRef) {
this.popupRef.instance.overlayPositions =
this.appendToBodyDirections && this.appendToBodyDirections.length > 0
? this.appendToBodyDirections
.map((position) => {
if (typeof position === 'string') {
return AppendToBodyDirectionsConfig[position];
}
else {
return position;
}
})
.filter((position) => position !== undefined)
: undefined;
}
}
setI18nText() {
this.i18nText = this.i18n.getI18nText().autoComplete;
this.i18n
.langChange()
.pipe(takeUntil(this.destroy$))
.subscribe((data) => {
this.i18nText = data.autoComplete;
});
}
restLatestSource() {
if (this.latestSource && this.latestSource.length > 0) {
this.writeValue('');
this.clearInputValue();
this.showLatestSource();
}
}
// 调用时机:input keyup
onSourceChange(source) {
if (!this.elementRef.nativeElement.value) {
if (!this.SELECT_TYPES.includes(this.sceneType) && !this.allowEmptyValueSearch) {
// 下拉场景不展示最近输入
this.showLatestSource();
}
else {
this.showSource(source, true, true);
}
}
else {
this.showSource(source, true, true);
}
}
showLatestSource() {
let tempSource = [];
if (this.latestSource && this.latestSource.length > 0) {
this.searchFn('').subscribe((source) => {
const t = this.latestSource;
tempSource = t.filter((data) => {
if (!data.label) {
return source.find((item) => item === data);
}
else {
return source.find((item) => item.label === data.label);
}
});
const pop = this.popupRef.instance;
pop.reset();
this.popTipsText = this.i18nText.latestInput;
this.fillPopup(tempSource);
this.openPopup();
this.changeDetectorRef.markForCheck();
this.updatePosition();
});
}
if (tempSource.length <= 0) {
this.hidePopup();
}
}
showSource(source, setOpen, isReset) {
if ((source && source.length) || this.noResultItemTemplate) {
const pop = this.popupRef.instance;
if (isReset) {
pop.reset();
}
this.popTipsText = this.tipsText || '';
this.fillPopup(source, this.value);
if (setOpen) {
this.openPopup(isReset ? 0 : -1);
}
this.changeDetectorRef.markForCheck();
this.updatePosition();
}
else {
this.hidePopup();
}
}
updatePosition() {
if (this.appendToBody) {
setTimeout(() => {
if (this.popupRef.instance.connectedOverlay && this.popupRef.instance.connectedOverlay.overlayRef) {
this.popupRef.instance.connectedOverlay.overlayRef.updatePosition();
}
});
}
}
openPopup(activeIndex) {
const index = activeIndex >= 0 ? activeIndex : this.popupRef.instance.activeIndex;
this.popupRef.instance.activeIndex = index;
this.popupRef.instance.hoverIndex = index;
this.popupRef.instance.disabled = this.disabled;
if (!this.popupRef.instance.isOpen) {
this.popupRef.instance.isOpen = true;
addClassToOrigin(this.elementRef);
this.changeDropDownStatus.emit(true);
this.toggleChange.emit(true);
}
}
writeValue(obj) {
this.value = this.valueParser(obj) || '';
if (!this.retainInputValue) {
this.writeInputValue(this.value);
}
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
this.renderer.setProperty(this.elementRef.nativeElement, 'disabled', isDisabled);
if (this.popupRef) {
this.popupRef.instance.setDisabledState(isDisabled);
}
}
ngOnDestroy() {
this.unSubscription();
this.destroy$.next();
this.destroy$.complete();
}
onFocus($event) {
this.focus = true;
this.transInputFocusEmit.emit({
focus: true,
popupRef: this.popupRef,
});
if (this.sceneType === 'select') {
this.searchValue(this.value ?? '', false);
}
}
onBlur($event) {
this.focus = false;
this.onTouched();
}
onEscKeyup($event) {
this.hidePopup();
}
onEnterKeyDown($event) {
if (!this.popupRef.instance.source?.length || !this.popupRef.instance.isOpen) {
return;
}
if (this.popupRef) {
this.popupRef.instance.selectCurrentItem($event);
}
}
onArrowUpKeyDown($event) {
if (this.popupRef) {
$event.preventDefault();
$event.stopPropagation();
this.popupRef.instance.prev();
}
}
onArrowDownKeyDown($event) {
if (this.popupRef) {
$event.preventDefault();
$event.stopPropagation();
this.popupRef.instance.next();
}
}
onDocumentClick($event) {
if (this.focus) {
this.transInputFocusEmit.emit({
focus: this.focus,
popupRef: this.popupRef,
});
}
// TODO: sceneType为'select'时,自定义了太多处理,十分不优雅,需要合一化
const hostElement = this.elementRef.nativeElement;
const isInside = hostElement.contains($event.target);
const isSelect = this.SELECT_TYPES.includes(this.sceneType);
const value = this.elementRef.nativeElement.value;
if (this.popupRef && this.popupRef.instance.isOpen) {
if ((!isInside && isSelect) || !isSelect) {
this.hidePopup();
}
if (!isInside) {
this.transInputFocusEmit.emit({
focus: false,
popupRef: this.popupRef,
});
}
}
else if (isInside && !isSelect) {
if (!value && !this.allowEmptyValueSearch) {
this.showLatestSource();
}
else {
this.searchValue(value, true);
}
}
}
searchValue(value, isOpen) {
this.searchFn(value).subscribe((source) => {
const searchStr = this.formatter(value) ?? '';
if (searchStr) {
const activeIndex = source.map((item) => this.formatter(item).toLowerCase()).indexOf(searchStr.toLowerCase());
this.popupRef.instance.activeIndex = activeIndex > -1 ? activeIndex : 0;
}
this.showSource(source, isOpen, false);
});
}
fillPopup(source, term) {
this.position = this.positionService.position(this.elementRef.nativeElement);
const pop = this.popupRef.instance;
pop.source = source;
pop.maxHeight = this.maxHeight;
pop.term = term;
pop.disabledKey = this.disabledKey;
pop.enableLazyLoad = this.enableLazyLoad;
pop.disabled = this.disabled;
pop.scrollStrategy = this.scrollStrategy;
pop.hidePopup = this.hidePopup;
if (this.appendToBody) {
pop.appendToBody = true;
pop.origin = new CdkOverlayOrigin(this.elementRef);
pop.width = this.dAutoCompleteWidth ? this.dAutoCompleteWidth : this.elementRef.nativeElement.offsetWidth;
pop.cdkOverlayOffsetY = this.cdkOverlayOffsetY;
}
else {
pop.appendToBody = false;
}
[
'formatter',
'itemTemplate',
'noResultItemTemplate',
'cssClass',
'dropdown',
'popTipsText',
'position',
'overview',
'showAnimation',
'customViewTemplate',
'customViewDirection',
].forEach((key) => {
if (this[key] !== undefined) {
pop[key] = this[key];
}
});
}
writeInputValue(value) {
this.renderer.setProperty(this.elementRef.nativeElement, 'value', value);
}
clearInputValue() {
this.renderer.setProperty(this.elementRef.nativeElement, 'value', '');
}
unSubscription() {
if (this.subscription) {
this.subscription.unsubscribe();
this.subscription = null;
}
}
onTermChange(term) {
this.value = term;
if (this.popupRef) {
this.popupRef.instance.term = term;
}
this.onChange(term);
}
registerInputEvent(elementRef) {
return fromEvent(elementRef.nativeElement, 'input').pipe(map((e) => e.target.value), filter((term) => !this.disabled && this.searchFn && term.length >= 0), debounceTime(this.delay), tap((term) => this.onTermChange(term)), switchMap((term) => this.searchFn(term, this)));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteDirective, deps: [{ token: AutoCompleteConfig }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: i0.ComponentFactoryResolver }, { token: i0.Renderer2 }, { token: i0.Injector }, { token: i2$1.PositionService }, { token: i0.ChangeDetectorRef }, { token: i3.I18nService }, { token: i4.DevConfigService }, { token: i5.ScrollStrategyOptions }], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: AutoCompleteDirective, selector: "[dAutoComplete]", inputs: { disabled: "disabled", cssClass: "cssClass", delay: "delay", showGlowStyle: "showGlowStyle", minLength: "minLength", itemTemplate: "itemTemplate", noResultItemTemplate: "noResultItemTemplate", searchingTemplate: "searchingTemplate", isSearching: "isSearching", appendToBody: "appendToBody", appendToBodyDirections: "appendToBodyDirections", appendToBodyScrollStrategy: "appendToBodyScrollStrategy", cdkOverlayOffsetY: "cdkOverlayOffsetY", dAutoCompleteWidth: "dAutoCompleteWidth", formatter: "formatter", sceneType: "sceneType", tipsText: "tipsText", overview: "overview", latestSource: "latestSource", source: "source", valueParser: "valueParser", searchFn: "searchFn", dropdown: "dropdown", maxHeight: "maxHeight", disabledKey: "disabledKey", showAnimation: "showAnimation", enableLazyLoad: "enableLazyLoad", retainInputValue: "retainInputValue", allowEmptyValueSearch: "allowEmptyValueSearch", customViewTemplate: "customViewTemplate", customViewDirection: "customViewDirection" }, outputs: { loadMore: "loadMore", selectValue: "selectValue", transInputFocusEmit: "transInputFocusEmit", changeDropDownStatus: "changeDropDownStatus", toggleChange: "toggleChange", hoverItem: "hoverItem" }, host: { listeners: { "focus": "onFocus($event)", "blur": "onBlur($event)", "keydown.esc": "onEscKeyup($event)", "keydown.Enter": "onEnterKeyDown($event)", "keydown.ArrowUp": "onArrowUpKeyDown($event)", "keydown.ArrowDown": "onArrowDownKeyDown($event)", "document:click": "onDocumentClick($event)" }, properties: { "attr.autocomplete": "this.autocomplete", "attr.autocapitalize": "this.autocapitalize", "attr.autocorrect": "this.autocorrect", "class.devui-glow-style": "this.hasGlowStyle" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AutoCompleteDirective),
multi: true,
},
], exportAs: ["autoComplete"], usesOnChanges: true, ngImport: i0 }); }
}
__decorate([
WithConfig(),
__metadata("design:type", Object)
], AutoCompleteDirective.prototype, "showGlowStyle", void 0);
__decorate([
WithConfig(),
__metadata("design:type", String)
], AutoCompleteDirective.prototype, "appendToBodyScrollStrategy", void 0);
__decorate([
WithConfig(),
__metadata("design:type", Object)
], AutoCompleteDirective.prototype, "showAnimation", void 0);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteDirective, decorators: [{
type: Directive,
args: [{
selector: '[dAutoComplete]',
exportAs: 'autoComplete',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AutoCompleteDirective),
multi: true,
},
],
}]
}], ctorParameters: () => [{ type: AutoCompleteConfig }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i0.ComponentFactoryResolver }, { type: i0.Renderer2 }, { type: i0.Injector }, { type: i2$1.PositionService }, { type: i0.ChangeDetectorRef }, { type: i3.I18nService }, { type: i4.DevConfigService }, { type: i5.ScrollStrategyOptions }], propDecorators: { autocomplete: [{
type: HostBinding,
args: ['attr.autocomplete']
}], autocapitalize: [{
type: HostBinding,
args: ['attr.autocapitalize']
}], autocorrect: [{
type: HostBinding,
args: ['attr.autocorrect']
}], disabled: [{
type: Input
}], cssClass: [{
type: Input
}], delay: [{
type: Input
}], showGlowStyle: [{
type: Input
}], hasGlowStyle: [{
type: HostBinding,
args: ['class.devui-glow-style']
}], minLength: [{
type: Input
}], itemTemplate: [{
type: Input
}], noResultItemTemplate: [{
type: Input
}], searchingTemplate: [{
type: Input
}], isSearching: [{
type: Input
}], appendToBody: [{
type: Input
}], appendToBodyDirections: [{
type: Input
}], appendToBodyScrollStrategy: [{
type: Input
}], cdkOverlayOffsetY: [{
type: Input
}], dAutoCompleteWidth: [{
type: Input
}], formatter: [{
type: Input
}], sceneType: [{
type: Input
}], tipsText: [{
type: Input
}], overview: [{
type: Input
}], latestSource: [{
type: Input
}], source: [{
type: Input
}], valueParser: [{
type: Input
}], searchFn: [{
type: Input
}], dropdown: [{
type: Input
}], maxHeight: [{
type: Input
}], disabledKey: [{
type: Input
}], showAnimation: [{
type: Input
}], enableLazyLoad: [{
type: Input
}], retainInputValue: [{
type: Input
}], allowEmptyValueSearch: [{
type: Input
}], customViewTemplate: [{
type: Input
}], customViewDirection: [{
type: Input
}], loadMore: [{
type: Output
}], selectValue: [{
type: Output
}], transInputFocusEmit: [{
type: Output
}], changeDropDownStatus: [{
type: Output
}], toggleChange: [{
type: Output
}], hoverItem: [{
type: Output
}], onFocus: [{
type: HostListener,
args: ['focus', ['$event']]
}], onBlur: [{
type: HostListener,
args: ['blur', ['$event']]
}], onEscKeyup: [{
type: HostListener,
args: ['keydown.esc', ['$event']]
}], onEnterKeyDown: [{
type: HostListener,
args: ['keydown.Enter', ['$event']]
}], onArrowUpKeyDown: [{
type: HostListener,
args: ['keydown.ArrowUp', ['$event']]
}], onArrowDownKeyDown: [{
type: HostListener,
args: ['keydown.ArrowDown', ['$event']]
}], onDocumentClick: [{
type: HostListener,
args: ['document:click', ['$event']]
}] } });
class AutoCompleteModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteModule, declarations: [AutoCompleteDirective, AutoCompletePopupComponent], imports: [CommonModule, FormsModule, OverlayModule, LazyLoadModule, LoadingModule, PositioningModule, HighlightModule], exports: [AutoCompleteDirective, AutoCompletePopupComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteModule, providers: [AutoCompleteConfig], imports: [CommonModule, FormsModule, OverlayModule, LazyLoadModule, LoadingModule, PositioningModule, HighlightModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AutoCompleteModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, FormsModule, OverlayModule, LazyLoadModule, LoadingModule, PositioningModule, HighlightModule],
exports: [AutoCompleteDirective, AutoCompletePopupComponent],
declarations: [AutoCompleteDirective, AutoCompletePopupComponent],
providers: [AutoCompleteConfig],
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { AutoCompleteConfig, AutoCompleteDirective, AutoCompleteModule, AutoCompletePopupComponent };
//# sourceMappingURL=ng-devui-auto-complete.mjs.map