ng-devui
Version:
DevUI components based on Angular
797 lines (794 loc) • 103 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Component, Input, HostListener, EventEmitter, forwardRef, ViewChild, Output, HostBinding, NgModule } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil, debounceTime, distinctUntilChanged, filter } from 'rxjs/operators';
import { cloneDeep } from 'lodash-es';
import * as i4 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i5 from '@angular/forms';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import * as i4$1 from 'ng-devui/checkbox';
import { CheckBoxModule } from 'ng-devui/checkbox';
import { __decorate, __metadata } from 'tslib';
import * as i6 from 'ng-devui/dropdown';
import { DropDownAppendToBodyComponent, DropDownModule } from 'ng-devui/dropdown';
import * as i2 from 'ng-devui/i18n';
import * as i3 from 'ng-devui/utils';
import { WithConfig } from 'ng-devui/utils';
import * as i7 from 'ng-devui/tags';
import { TagsModule } from 'ng-devui/tags';
import { SelectModule } from 'ng-devui/select';
class CascaderService {
constructor() {
this._currentValue = [];
this.multipleValue = [];
this.columnList = [];
this.searchResultList = [];
this.canSelectParent = false;
this.isMultiple = false;
this.isLazyLoad = false;
this.lazyloadCache = {};
this.checkboxRelation = { upward: true, downward: true };
this.closeMianDropdown = new Subject();
this.currentValueChange = new Subject();
this.resetStatus = new Subject();
this.openDrawer = new Subject();
this.updateShowText = new Subject();
this.updateTagList = new Subject();
}
set currentValue(value) {
this._currentValue = value.filter((item) => item !== undefined);
this.currentValueChange.next(this._currentValue);
}
get currentValue() {
return this._currentValue;
}
set currentMultipleValue(value) {
this.resetNodeStatus();
this.multipleValue = value;
}
get currentMultipleValue() {
this.multipleValue = [];
this.getMultipleValue([], this.options);
return this.multipleValue;
}
initOptions(options) {
this.columnList = [];
this.options = cloneDeep(options);
// 标记根节点
this.options.forEach((t) => {
t.isRoot = true;
});
this.columnList.push(this.options);
}
openColumn(option, colIndex, islazyLoad, reload = false) {
this.clearTargetActive(this.columnList[colIndex].find((t) => t.active));
option.active = true;
this.columnList.splice(colIndex + 1);
if (option.children && option.children.length) {
this.columnList.push(option.children);
this.openDrawer.next();
}
else if (islazyLoad) {
option._loading = true;
const fn = this.loadChildrenFn(option);
if (fn.then) {
fn.then((res) => {
this.columnList.splice(colIndex + 1); // 防止多个同时懒加载,造成多余的添加
option.children = res || [];
option._loading = false;
this.columnList.push(res || []);
this.openDrawer.next();
if (this.isMultiple) {
this.updateOptionCheckedStatus(option.value, option.checked, true, true, !reload);
}
if (reload) {
if (!this.isMultiple) {
this.updateOptionByValue();
}
this.updateShowText.next();
}
});
}
else {
fn.subscribe((res) => {
this.columnList.splice(colIndex + 1); // 防止多个同时懒加载,造成多余的添加
option.children = res || [];
option._loading = false;
this.columnList.push(res || []);
this.openDrawer.next();
if (this.isMultiple) {
this.updateOptionCheckedStatus(option.value, option.checked, true, true, !reload);
}
if (reload) {
if (!this.isMultiple) {
this.updateOptionByValue();
}
this.updateShowText.next();
}
});
}
}
}
clearTargetActive(option) {
if (!option) {
return;
}
option.active = false;
if (option.children) {
this.clearTargetActive(option.children.find((t) => t.active));
}
}
setCurrentValue() {
this.currentValue = this.columnList.map((listItem) => listItem.find((optionItem) => optionItem.active)?.value);
}
updateOptionByValue() {
this.resetNodeStatus();
this.columnList = [this.options];
for (let index = 0; index < this.currentValue.length; index++) {
const target = this.columnList[index]?.find((listItem) => listItem.value === this.currentValue[index]);
if (target) {
target.active = true;
if (target.children && target.children.length) {
// 有子菜单展开子菜单
this.columnList.push(target.children);
}
else if (this.isLazyLoad) {
// 懒加载没有子菜单的情况下,非叶子节点执行展开,叶子节点执行选中
this.openColumn(target, index, !target.isLeaf, !target.isLeaf);
break;
}
}
else {
break;
}
}
}
lazyloadMultipleChild(target, index) {
if (!this.lazyloadCache[target.value]) {
this.lazyloadCache[target.value] = true;
this.openColumn(target, index, true, true);
}
}
resetNodeStatus(option = this.options) {
option.forEach((item) => {
item.active = false;
item.checked = false;
item.halfChecked = false;
if (item.children) {
this.resetNodeStatus(item.children);
}
});
}
// 在多选模式下,更新节点树的checked状态
updateOptionCheckedStatus(targetValue, checked, upward = true, downward = true, isEmit = true) {
let targetNode = this.options.find((t) => t.value === targetValue);
// 当主下拉列表包含了目标,即目标无父节点
if (targetNode) {
targetNode.checked = checked;
targetNode.halfChecked = false;
if (targetNode.children && downward) {
this.updateChildrenChecked(targetNode, checked, isEmit);
}
}
else {
// 当存在父节点时,需要检查同级节点来确定父节点状态
const parentNode = this.getParentNode(targetValue);
targetNode = parentNode.children.find((t) => t.value === targetValue);
targetNode.checked = checked;
targetNode.halfChecked = false;
if (upward) {
this.updateParentChecked(parentNode, isEmit);
}
if (targetNode.children && downward) {
this.updateChildrenChecked(targetNode, checked, isEmit);
}
}
}
// 子节点按父节点状态更新
updateChildrenChecked(node, checked, isEmit) {
let hasDisable = false;
node.children.forEach((child) => {
if (!child.disabled) {
child.checked = checked;
child.halfChecked = false;
if (child.children && child.children.length) {
if (this.canSelectParent) {
this.updateTagList.next({
isAdd: checked,
option: child,
isEmit,
});
}
this.updateChildrenChecked(child, checked, isEmit);
}
else {
this.updateTagList.next({
isAdd: checked,
option: child,
isEmit,
});
}
}
else {
hasDisable = true;
}
});
if (hasDisable && !this.canSelectParent) {
this.updateParentChecked(node, isEmit);
}
}
// 父节点按所有子节点状态更新
updateParentChecked(node, isEmit) {
const checkedChild = node.children.find((t) => t.checked);
const halfcheckedChild = node.children.find((t) => t.halfChecked);
const uncheckedChild = node.children.find((t) => !t.halfChecked && !t.checked);
if (halfcheckedChild || (checkedChild && uncheckedChild)) {
node.checked = false;
node.halfChecked = true;
}
else if (!checkedChild && !halfcheckedChild) {
node.checked = false;
node.halfChecked = false;
}
else {
node.checked = true;
node.halfChecked = false;
}
if (this.canSelectParent) {
this.updateTagList.next({
isAdd: node.checked,
option: node,
isEmit,
});
}
// 如果此节点非根节点,则继续找它的父节点进行更新
if (!node.isRoot) {
this.updateParentChecked(this.getParentNode(node.value), isEmit);
}
}
// 获取父节点
getParentNode(childValue) {
const queue = [...this.options];
let cur;
while (queue.length) {
cur = queue.shift();
if (cur.children && cur.children.find((t) => t.value === childValue)) {
break;
}
else if (cur.children) {
queue.push(...cur.children);
}
}
return cur;
}
getMultipleValue(value, option) {
const isNoRelation = !this.checkboxRelation.downward || !this.checkboxRelation.upward;
option.forEach((item) => {
const _value = [...value];
_value.push(item.value);
if (item.children && item.children.length && (item.checked || item.halfChecked)) {
this.getMultipleValue(_value, item.children);
if (isNoRelation) {
this.multipleValue.push(_value);
}
}
else if (item.checked) {
this.multipleValue.push(_value);
}
else if (isNoRelation && item.children?.length) {
this.getMultipleValue(_value, item.children);
}
});
}
closeAllDropdown() {
this.closeMianDropdown.next();
}
// 搜索功能
searchByString(str, currentlabel, currentValue = [], list = this.options) {
list.forEach((item) => {
const label = currentlabel ? currentlabel + ' / ' + item.label : item.label;
const valueList = [...currentValue, item.value];
if (item.children && item.children.length) {
this.searchByString(str, label, valueList, item.children);
}
else {
if (!item.disabled && label.toLowerCase().indexOf(str.toLowerCase()) !== -1) {
this.searchResultList.push({
label,
valueList,
checked: item.checked,
});
}
}
});
}
ngOnDestroy() {
this.closeMianDropdown.complete();
this.currentValueChange.complete();
this.updateTagList.complete();
this.resetStatus.complete();
this.openDrawer.complete();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CascaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CascaderService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CascaderService, decorators: [{
type: Injectable
}] });
class CascaderLiComponent {
onClick(event) {
event.stopPropagation();
}
onMouseEnter(event) {
if (this.trigger === 'hover') {
if (this.option.disabled) {
return;
}
this.cascaderSrv.openColumn(this.option, this.colIndex, false);
}
}
constructor(cascaderSrv, cdr) {
this.cascaderSrv = cascaderSrv;
this.cdr = cdr;
this.width = 200;
this.trigger = 'hover';
this.multiple = false;
this.canSelectParent = false;
this.checkboxRelation = { upward: true, downward: true };
this.unsubscribe$ = new Subject();
}
ngOnInit() {
if (this.isLazyLoad) {
this.isLeaf = !!this.option.isLeaf;
}
else { // 当不是懒加载时可以通过children是否为空来判断是否为叶子节点
this.isLeaf = this.option.isLeaf || !(this.option.children && this.option.children.length);
}
this.initObserable();
}
initObserable() {
this.cascaderSrv.resetStatus.pipe(takeUntil(this.unsubscribe$)).subscribe(res => {
this.selected = false;
this.halfCheck = false;
this.active = false;
});
}
clickLeaf() {
if (!this.option.disabled && !this.multiple) {
this.cascaderSrv.openColumn(this.option, this.colIndex, false);
this.option.active = true;
this.cascaderSrv.setCurrentValue();
this.cascaderSrv.closeAllDropdown();
}
}
clickItem() {
if (this.option.disabled) {
return;
}
this.cascaderSrv.openColumn(this.option, this.colIndex, this.isLazyLoad);
if (this.canSelectParent && !this.multiple) {
this.cascaderSrv.setCurrentValue();
}
}
clickCheckbox(event) {
if (this.option.disabled) {
return;
}
event.stopPropagation();
// 如果是半选状态,更新为false,其他状态则更新为与checked相反
const status = !!this.option.halfChecked;
this.cascaderSrv.updateOptionCheckedStatus(this.option.value, this.option.halfChecked ? false : !this.option.checked, this.checkboxRelation.upward, this.checkboxRelation.downward);
if (status) {
this.option.halfChecked = false;
}
if (this.isLeaf || this.canSelectParent) {
this.updateValue(this.option.checked);
}
}
// 阻止checkbox本身的点击事件变化
avoidCheckboxChange() {
return false;
}
updateValue(checked) {
this.cascaderSrv.updateTagList.next({
isAdd: checked,
option: this.option,
isEmit: true
});
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CascaderLiComponent, deps: [{ token: CascaderService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: CascaderLiComponent, selector: "d-cascader-li", inputs: { width: "width", trigger: "trigger", option: "option", multiple: "multiple", canSelectParent: "canSelectParent", colIndex: "colIndex", dropDownItemTemplate: "dropDownItemTemplate", isLazyLoad: "isLazyLoad", checkboxRelation: "checkboxRelation" }, host: { listeners: { "click": "onClick($event)", "mouseenter": "onMouseEnter($event)" } }, ngImport: i0, template: "<li *ngIf=\"!isLeaf\" role=\"menuitem\" [ngClass]=\"{ disabled: option.disabled, 'devui-leaf-active': option.active }\" (click)=\"clickItem()\">\n <div class=\"devui-dropdown-item\">\n <d-checkbox\n *ngIf=\"multiple\"\n class=\"devui-dropdown-item-checkbox\"\n [disabled]=\"option.disabled\"\n [isShowTitle]=\"false\"\n [halfchecked]=\"option.halfChecked\"\n (click)=\"clickCheckbox($event)\"\n [ngModel]=\"option.checked\"\n [beforeChange]=\"avoidCheckboxChange\"\n ></d-checkbox>\n <i *ngIf=\"option.icon\" class=\"icon {{ option.icon }}\"></i>\n <span class=\"dropdown-item-label\">\n <ng-template\n [ngTemplateOutlet]=\"dropDownItemTemplate || defaultDropdownItemTemplate\"\n [ngTemplateOutletContext]=\"{\n label: option.label,\n option: option\n }\"\n >\n </ng-template>\n </span>\n <svg\n *ngIf=\"!option._loading\"\n style=\"float: right\"\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n class=\"icon devui-cascader-icon-right\"\n >\n <g id=\"icon-icon-chevron-right-2\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <g\n id=\"ipd_right\"\n transform=\"translate(8.000000, 8.000000) scale(-1, 1) rotate(-270.000000) translate(-8.000000, -8.000000) translate(3.000000, 5.500000)\"\n fill=\"#71757F\"\n fill-rule=\"nonzero\"\n >\n <path\n d=\"M-0.353553391,-0.353553391 C-0.179987039,-0.527119742 0.0894373624,-0.546404893 0.284305503,-0.411408841 L0.353553391,-0.353553391 L4.999,4.293 L9.64644661,-0.353553391 C9.82001296,-0.527119742 10.0894374,-0.546404893 10.2843055,-0.411408841 L10.3535534,-0.353553391 C10.5271197,-0.179987039 10.5464049,0.0894373624 10.4114088,0.284305503 L10.3535534,0.353553391 L5.35355339,5.35355339 C5.17998704,5.52711974 4.91056264,5.54640489 4.7156945,5.41140884 L4.64644661,5.35355339 L-0.353553391,0.353553391 C-0.548815536,0.158291245 -0.548815536,-0.158291245 -0.353553391,-0.353553391 Z\"\n id=\"\u8DEF\u5F84\"\n ></path>\n </g>\n </g>\n </svg>\n <svg width=\"16px\" height=\"16px\" viewBox=\"0 0 16 16\" style=\"float: right\" class=\"icon devui-cascader-loading\" *ngIf=\"option._loading\">\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M8,1 C8.55228475,1 9,1.44771525 9,2 L9,4 C9,4.55228475 8.55228475,5 8,5 C7.44771525,5 7,4.55228475 7,4 L7,2 C7,1.44771525 7.44771525,1 8,1 Z M8,11 C8.55228475,11 9,11.4477153 9,12 L9,14 C9,14.5522847 8.55228475,15 8,15 C7.44771525,15 7,14.5522847 7,14 L7,12 C7,11.4477153 7.44771525,11 8,11 Z M15,8 C15,8.55228475 14.5522847,9 14,9 L12,9 C11.4477153,9 11,8.55228475 11,8 C11,7.44771525 11.4477153,7 12,7 L14,7 C14.5522847,7 15,7.44771525 15,8 Z M5,8 C5,8.55228475 4.55228475,9 4,9 L2,9 C1.44771525,9 1,8.55228475 1,8 C1,7.44771525 1.44771525,7 2,7 L4,7 C4.55228475,7 5,7.44771525 5,8 Z M12.9497475,3.05025253 C13.3402718,3.44077682 13.3402718,4.0739418 12.9497475,4.46446609 L11.5355339,5.87867966 C11.1450096,6.26920395 10.5118446,6.26920395 10.1213203,5.87867966 C9.73079605,5.48815536 9.73079605,4.85499039 10.1213203,4.46446609 L11.5355339,3.05025253 C11.9260582,2.65972824 12.5592232,2.65972824 12.9497475,3.05025253 Z M5.87867966,10.1213203 C6.26920395,10.5118446 6.26920395,11.1450096 5.87867966,11.5355339 L4.46446609,12.9497475 C4.0739418,13.3402718 3.44077682,13.3402718 3.05025253,12.9497475 C2.65972824,12.5592232 2.65972824,11.9260582 3.05025253,11.5355339 L4.46446609,10.1213203 C4.85499039,9.73079605 5.48815536,9.73079605 5.87867966,10.1213203 Z M12.9497475,12.9497475 C12.5592232,13.3402718 11.9260582,13.3402718 11.5355339,12.9497475 L10.1213203,11.5355339 C9.73079605,11.1450096 9.73079605,10.5118446 10.1213203,10.1213203 C10.5118446,9.73079605 11.1450096,9.73079605 11.5355339,10.1213203 L12.9497475,11.5355339 C13.3402718,11.9260582 13.3402718,12.5592232 12.9497475,12.9497475 Z M5.87867966,5.87867966 C5.48815536,6.26920395 4.85499039,6.26920395 4.46446609,5.87867966 L3.05025253,4.46446609 C2.65972824,4.0739418 2.65972824,3.44077682 3.05025253,3.05025253 C3.44077682,2.65972824 4.0739418,2.65972824 4.46446609,3.05025253 L5.87867966,4.46446609 C6.26920395,4.85499039 6.26920395,5.48815536 5.87867966,5.87867966 Z\"\n fill=\"#293040\"\n ></path>\n </g>\n </svg>\n </div>\n</li>\n\n<li *ngIf=\"isLeaf\" role=\"menuitem\" (click)=\"clickLeaf()\" [ngClass]=\"{ disabled: option.disabled, 'devui-leaf-active': option.active }\">\n <div class=\"devui-dropdown-item\">\n <d-checkbox\n *ngIf=\"multiple\"\n class=\"devui-dropdown-item-checkbox\"\n [disabled]=\"option.disabled\"\n [isShowTitle]=\"false\"\n [halfchecked]=\"option.halfChecked\"\n (click)=\"clickCheckbox($event)\"\n [ngModel]=\"option.checked\"\n (ngModelChange)=\"updateValue($event)\"\n [beforeChange]=\"avoidCheckboxChange\"\n ></d-checkbox>\n <i *ngIf=\"option.icon\" class=\"icon {{ option.icon }}\"></i>\n <span class=\"dropdown-item-label\">\n <ng-template\n [ngTemplateOutlet]=\"dropDownItemTemplate || defaultDropdownItemTemplate\"\n [ngTemplateOutletContext]=\"{\n option: option,\n label: option.label\n }\"\n >\n </ng-template>\n </span>\n </div>\n</li>\n\n<ng-template #defaultDropdownItemTemplate let-label=\"label\">\n <span>{{ label }}</span>\n</ng-template>\n", styles: [".devui-font-size-base{font-size:var(--devui-font-size, 12px)}.devui-font-base{font-size:var(--devui-font-size, 12px);font-weight:var(--devui-font-content-weight, normal);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-modal-title{font-size:var(--devui-font-size-modal-title, 18px)}.devui-font-modal-title{font-size:var(--devui-font-size-modal-title, 18px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-page-title{font-size:var(--devui-font-size-page-title, 16px)}.devui-font-page-title{font-size:var(--devui-font-size-page-title, 16px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-secondary-title{font-size:var(--devui-font-size-card-title, 14px)}.devui-font-secondary-title{font-size:var(--devui-font-size-card-title, 14px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-dropdown-menu{padding-bottom:0}.devui-dropdown-item{height:32px;padding:8px 12px;cursor:pointer;display:flex!important;align-items:center}.devui-dropdown-item .dropdown-item-label{display:inline-block;color:var(--devui-text, #191919);flex:1;width:0;overflow:hidden;text-overflow:ellipsis}.devui-dropdown-item i{color:var(--devui-placeholder, #808080)}.devui-dropdown-item-checkbox{display:inline-block;margin-right:8px}.devui-dropdown-item .icon{font-size:var(--devui-font-size-icon, 16px);margin-right:4px;color:var(--devui-text, #191919);display:inline-block}.devui-dropdown-menu{border-left-color:var(--devui-base-bg, #ffffff)!important;box-shadow:var(--devui-shadow-length-connected-overlay, 0 4px 12px 0) var(--devui-shadow, rgba(0, 0, 0, .16))}.devui-dropdown-open{background-color:var(--devui-list-item-hover-bg, #f2f2f3)}.devui-dropdown-open span,.devui-dropdown-open i{color:var(--devui-link, #0950de)}.devui-leaf-active{background-color:var(--devui-list-item-hover-bg, #f2f2f3)}.devui-dropdown-menu{height:180px;overflow-y:auto}.disabled{background-color:var(--devui-disabled-bg, #f3f3f3)!important}.disabled .devui-dropdown-item{cursor:not-allowed}.disabled .devui-dropdown-item span,.disabled .devui-dropdown-item i{color:var(--devui-disabled-text, #c2c2c2)}.devui-dropdown-item:not(.disabled):active:hover .devui-cascader-icon-right polygon{fill:var(--devui-light-text, #ffffff)}.devui-cascader-loading{animation:spin 2s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host:first-of-type>li{margin-top:0}:host>li{margin-top:4px}:host>li span{transition:color var(--devui-animation-duration-fast, .1s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1)),background-color var(--devui-animation-duration-fast, .1s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1))}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4$1.CheckBoxComponent, selector: "d-checkbox", inputs: ["name", "label", "cssClass", "color", "disabled", "isShowTitle", "title", "labelTemplate", "halfchecked", "showAnimation", "showGlowStyle", "beforeChange"], outputs: ["change"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CascaderLiComponent, decorators: [{
type: Component,
args: [{ selector: 'd-cascader-li', template: "<li *ngIf=\"!isLeaf\" role=\"menuitem\" [ngClass]=\"{ disabled: option.disabled, 'devui-leaf-active': option.active }\" (click)=\"clickItem()\">\n <div class=\"devui-dropdown-item\">\n <d-checkbox\n *ngIf=\"multiple\"\n class=\"devui-dropdown-item-checkbox\"\n [disabled]=\"option.disabled\"\n [isShowTitle]=\"false\"\n [halfchecked]=\"option.halfChecked\"\n (click)=\"clickCheckbox($event)\"\n [ngModel]=\"option.checked\"\n [beforeChange]=\"avoidCheckboxChange\"\n ></d-checkbox>\n <i *ngIf=\"option.icon\" class=\"icon {{ option.icon }}\"></i>\n <span class=\"dropdown-item-label\">\n <ng-template\n [ngTemplateOutlet]=\"dropDownItemTemplate || defaultDropdownItemTemplate\"\n [ngTemplateOutletContext]=\"{\n label: option.label,\n option: option\n }\"\n >\n </ng-template>\n </span>\n <svg\n *ngIf=\"!option._loading\"\n style=\"float: right\"\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n class=\"icon devui-cascader-icon-right\"\n >\n <g id=\"icon-icon-chevron-right-2\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <g\n id=\"ipd_right\"\n transform=\"translate(8.000000, 8.000000) scale(-1, 1) rotate(-270.000000) translate(-8.000000, -8.000000) translate(3.000000, 5.500000)\"\n fill=\"#71757F\"\n fill-rule=\"nonzero\"\n >\n <path\n d=\"M-0.353553391,-0.353553391 C-0.179987039,-0.527119742 0.0894373624,-0.546404893 0.284305503,-0.411408841 L0.353553391,-0.353553391 L4.999,4.293 L9.64644661,-0.353553391 C9.82001296,-0.527119742 10.0894374,-0.546404893 10.2843055,-0.411408841 L10.3535534,-0.353553391 C10.5271197,-0.179987039 10.5464049,0.0894373624 10.4114088,0.284305503 L10.3535534,0.353553391 L5.35355339,5.35355339 C5.17998704,5.52711974 4.91056264,5.54640489 4.7156945,5.41140884 L4.64644661,5.35355339 L-0.353553391,0.353553391 C-0.548815536,0.158291245 -0.548815536,-0.158291245 -0.353553391,-0.353553391 Z\"\n id=\"\u8DEF\u5F84\"\n ></path>\n </g>\n </g>\n </svg>\n <svg width=\"16px\" height=\"16px\" viewBox=\"0 0 16 16\" style=\"float: right\" class=\"icon devui-cascader-loading\" *ngIf=\"option._loading\">\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M8,1 C8.55228475,1 9,1.44771525 9,2 L9,4 C9,4.55228475 8.55228475,5 8,5 C7.44771525,5 7,4.55228475 7,4 L7,2 C7,1.44771525 7.44771525,1 8,1 Z M8,11 C8.55228475,11 9,11.4477153 9,12 L9,14 C9,14.5522847 8.55228475,15 8,15 C7.44771525,15 7,14.5522847 7,14 L7,12 C7,11.4477153 7.44771525,11 8,11 Z M15,8 C15,8.55228475 14.5522847,9 14,9 L12,9 C11.4477153,9 11,8.55228475 11,8 C11,7.44771525 11.4477153,7 12,7 L14,7 C14.5522847,7 15,7.44771525 15,8 Z M5,8 C5,8.55228475 4.55228475,9 4,9 L2,9 C1.44771525,9 1,8.55228475 1,8 C1,7.44771525 1.44771525,7 2,7 L4,7 C4.55228475,7 5,7.44771525 5,8 Z M12.9497475,3.05025253 C13.3402718,3.44077682 13.3402718,4.0739418 12.9497475,4.46446609 L11.5355339,5.87867966 C11.1450096,6.26920395 10.5118446,6.26920395 10.1213203,5.87867966 C9.73079605,5.48815536 9.73079605,4.85499039 10.1213203,4.46446609 L11.5355339,3.05025253 C11.9260582,2.65972824 12.5592232,2.65972824 12.9497475,3.05025253 Z M5.87867966,10.1213203 C6.26920395,10.5118446 6.26920395,11.1450096 5.87867966,11.5355339 L4.46446609,12.9497475 C4.0739418,13.3402718 3.44077682,13.3402718 3.05025253,12.9497475 C2.65972824,12.5592232 2.65972824,11.9260582 3.05025253,11.5355339 L4.46446609,10.1213203 C4.85499039,9.73079605 5.48815536,9.73079605 5.87867966,10.1213203 Z M12.9497475,12.9497475 C12.5592232,13.3402718 11.9260582,13.3402718 11.5355339,12.9497475 L10.1213203,11.5355339 C9.73079605,11.1450096 9.73079605,10.5118446 10.1213203,10.1213203 C10.5118446,9.73079605 11.1450096,9.73079605 11.5355339,10.1213203 L12.9497475,11.5355339 C13.3402718,11.9260582 13.3402718,12.5592232 12.9497475,12.9497475 Z M5.87867966,5.87867966 C5.48815536,6.26920395 4.85499039,6.26920395 4.46446609,5.87867966 L3.05025253,4.46446609 C2.65972824,4.0739418 2.65972824,3.44077682 3.05025253,3.05025253 C3.44077682,2.65972824 4.0739418,2.65972824 4.46446609,3.05025253 L5.87867966,4.46446609 C6.26920395,4.85499039 6.26920395,5.48815536 5.87867966,5.87867966 Z\"\n fill=\"#293040\"\n ></path>\n </g>\n </svg>\n </div>\n</li>\n\n<li *ngIf=\"isLeaf\" role=\"menuitem\" (click)=\"clickLeaf()\" [ngClass]=\"{ disabled: option.disabled, 'devui-leaf-active': option.active }\">\n <div class=\"devui-dropdown-item\">\n <d-checkbox\n *ngIf=\"multiple\"\n class=\"devui-dropdown-item-checkbox\"\n [disabled]=\"option.disabled\"\n [isShowTitle]=\"false\"\n [halfchecked]=\"option.halfChecked\"\n (click)=\"clickCheckbox($event)\"\n [ngModel]=\"option.checked\"\n (ngModelChange)=\"updateValue($event)\"\n [beforeChange]=\"avoidCheckboxChange\"\n ></d-checkbox>\n <i *ngIf=\"option.icon\" class=\"icon {{ option.icon }}\"></i>\n <span class=\"dropdown-item-label\">\n <ng-template\n [ngTemplateOutlet]=\"dropDownItemTemplate || defaultDropdownItemTemplate\"\n [ngTemplateOutletContext]=\"{\n option: option,\n label: option.label\n }\"\n >\n </ng-template>\n </span>\n </div>\n</li>\n\n<ng-template #defaultDropdownItemTemplate let-label=\"label\">\n <span>{{ label }}</span>\n</ng-template>\n", styles: [".devui-font-size-base{font-size:var(--devui-font-size, 12px)}.devui-font-base{font-size:var(--devui-font-size, 12px);font-weight:var(--devui-font-content-weight, normal);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-modal-title{font-size:var(--devui-font-size-modal-title, 18px)}.devui-font-modal-title{font-size:var(--devui-font-size-modal-title, 18px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-page-title{font-size:var(--devui-font-size-page-title, 16px)}.devui-font-page-title{font-size:var(--devui-font-size-page-title, 16px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-font-size-secondary-title{font-size:var(--devui-font-size-card-title, 14px)}.devui-font-secondary-title{font-size:var(--devui-font-size-card-title, 14px);font-weight:var(--devui-font-title-weight, bold);line-height:var(--devui-line-height-base, 1.5)}.devui-dropdown-menu{padding-bottom:0}.devui-dropdown-item{height:32px;padding:8px 12px;cursor:pointer;display:flex!important;align-items:center}.devui-dropdown-item .dropdown-item-label{display:inline-block;color:var(--devui-text, #191919);flex:1;width:0;overflow:hidden;text-overflow:ellipsis}.devui-dropdown-item i{color:var(--devui-placeholder, #808080)}.devui-dropdown-item-checkbox{display:inline-block;margin-right:8px}.devui-dropdown-item .icon{font-size:var(--devui-font-size-icon, 16px);margin-right:4px;color:var(--devui-text, #191919);display:inline-block}.devui-dropdown-menu{border-left-color:var(--devui-base-bg, #ffffff)!important;box-shadow:var(--devui-shadow-length-connected-overlay, 0 4px 12px 0) var(--devui-shadow, rgba(0, 0, 0, .16))}.devui-dropdown-open{background-color:var(--devui-list-item-hover-bg, #f2f2f3)}.devui-dropdown-open span,.devui-dropdown-open i{color:var(--devui-link, #0950de)}.devui-leaf-active{background-color:var(--devui-list-item-hover-bg, #f2f2f3)}.devui-dropdown-menu{height:180px;overflow-y:auto}.disabled{background-color:var(--devui-disabled-bg, #f3f3f3)!important}.disabled .devui-dropdown-item{cursor:not-allowed}.disabled .devui-dropdown-item span,.disabled .devui-dropdown-item i{color:var(--devui-disabled-text, #c2c2c2)}.devui-dropdown-item:not(.disabled):active:hover .devui-cascader-icon-right polygon{fill:var(--devui-light-text, #ffffff)}.devui-cascader-loading{animation:spin 2s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host:first-of-type>li{margin-top:0}:host>li{margin-top:4px}:host>li span{transition:color var(--devui-animation-duration-fast, .1s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1)),background-color var(--devui-animation-duration-fast, .1s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1))}\n"] }]
}], ctorParameters: () => [{ type: CascaderService }, { type: i0.ChangeDetectorRef }], propDecorators: { width: [{
type: Input
}], trigger: [{
type: Input
}], option: [{
type: Input
}], multiple: [{
type: Input
}], canSelectParent: [{
type: Input
}], colIndex: [{
type: Input
}], dropDownItemTemplate: [{
type: Input
}], isLazyLoad: [{
type: Input
}], checkboxRelation: [{
type: Input
}], onClick: [{
type: HostListener,
args: ['click', ['$event']]
}], onMouseEnter: [{
type: HostListener,
args: ['mouseenter', ['$event']]
}] } });
const DEBOUNCE_TIME = 200;
class CascaderComponent {
set loadChildrenFn(fn) {
this.isLazyLoad = !!fn;
if (fn) {
this.cascaderSrv.loadChildrenFn = fn;
}
}
get hasGlowStyle() {
return this.showGlowStyle;
}
get columnList() {
return this.cascaderSrv.columnList;
}
get searchResultList() {
return this.cascaderSrv.searchResultList;
}
constructor(cascaderSrv, i18n, devConfigService) {
this.cascaderSrv = cascaderSrv;
this.i18n = i18n;
this.devConfigService = devConfigService;
this.options = [];
this.width = 200;
this.placeholder = '';
this.trigger = 'hover';
this.disabled = false;
this.multiple = false;
this.showPath = false;
this.allowClear = false;
this.allowSearch = false;
this.canSelectParent = false;
this.checkboxRelation = { upward: true, downward: true };
this.dropdownPanelClass = '';
this.appendToBody = true;
this.tagMaxWidth = '200px';
this.showAnimation = true;
this.styleType = 'default';
this.toggleEvent = new EventEmitter();
this.showGlowStyle = true;
this.subMenuDirections = [
{
originX: 'start',
originY: 'bottom',
overlayX: 'start',
overlayY: 'top',
offsetX: 0,
},
{
originX: 'start',
originY: 'top',
overlayX: 'start',
overlayY: 'bottom',
offsetX: 0,
},
];
this.unsubscribe$ = new Subject();
this.searchValueChange = new Subject();
this.multipleValueList = [];
this.lazyloadValue = [];
this.showSearchInput = false;
this.onChange = Function.prototype;
this.onTouched = Function.prototype;
}
// 获取整颗树的公共方法
getOptionTree() {
return this.cascaderSrv.options;
}
ngOnInit() {
this.dropdownWidth = this.dropdownWidth ? this.dropdownWidth : this.width;
this.cascaderSrv.canSelectParent = this.canSelectParent;
this.cascaderSrv.initOptions(this.options);
this.cascaderSrv.isMultiple = this.multiple;
this.cascaderSrv.isLazyLoad = this.isLazyLoad;
this.cascaderSrv.checkboxRelation = this.checkboxRelation;
this.initObservale();
this.initI18n();
}
ngOnChanges(changes) {
const { options, canSelectParent } = changes;
if (options && !options.firstChange) {
this.cascaderSrv.initOptions(this.options);
}
else if (canSelectParent && !canSelectParent.firstChange) {
this.cascaderSrv.canSelectParent = this.canSelectParent;
}
}
initI18n() {
this.i18nCommonText = this.i18n.getI18nText().common;
this.i18nSubscription = this.i18n.langChange().subscribe((data) => {
this.i18nCommonText = data.common;
});
}
valueChanges(value) {
this.searchValueChange.next(value);
}
chooseSearchResult(option) {
if (option.checked) {
return;
}
if (this.multiple) {
// 多选模式下更新数据后需要刷新dropdown位置和重新聚焦input
option.checked = true;
this.writeValue([...this.cascaderSrv.multipleValue, option.valueList]);
this.onChange(this.cascaderSrv.multipleValue);
this.mainDropdown.updateCdkConnectedOverlayOrigin();
if (this.innerInput) {
this.innerInput.nativeElement.focus();
}
}
else {
this.writeValue(option.valueList);
this.onChange(option.valueList);
this.mainDropdown.isOpen = false;
}
}
initObservale() {
this.cascaderSrv.closeMianDropdown.pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {
if (this.mainDropdown) {
this.mainDropdown.isOpen = false;
}
});
this.cascaderSrv.currentValueChange.pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {
this.writeValue(res);
this.onChange(res);
});
this.cascaderSrv.openDrawer.pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {
this.rePosition();
});
if (this.multiple) {
this.cascaderSrv.updateTagList.pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {
const targetIndex = this.multipleValueList.findIndex((t) => t.value === res.option.value);
if (res.isAdd) {
if (targetIndex === -1) {
this.multipleValueList.push(res.option);
this.updateMultipleValuePathList();
}
}
else if (targetIndex !== -1) {
this.multipleValueList.splice(targetIndex, 1);
}
if (res.isEmit) {
this.onChange(this.cascaderSrv.currentMultipleValue);
}
// 当taglist变化导致input高度变化时,更新相对位置
setTimeout(() => {
this.mainDropdown.updateCdkConnectedOverlayOrigin();
});
});
}
if (this.allowSearch) {
this.searchValueChange
.pipe(takeUntil(this.unsubscribe$), debounceTime(DEBOUNCE_TIME), distinctUntilChanged(), filter((t) => t !== ''))
.subscribe((value) => {
clearTimeout(this.timer);
if (this.mainDropdown && !this.mainDropdown.isOpen) {
this.mainDropdown.isOpen = true;
}
if (this.multiple && this.innerInput) {
this.innerInput.nativeElement.focus();
}
this.cascaderSrv.searchResultList = [];
this.cascaderSrv.searchByString(value);
this.showSearchPanel = true;
});
}
if (this.isLazyLoad) {
this.cascaderSrv.updateShowText.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {
if (this.multiple) {
this.multipleValueList = this.getMultipleValueFromValueList(this.lazyloadValue);
this.cascaderSrv.multipleValue = this.lazyloadValue;
}
else {
this.showTextValue = this.showPath
? this.getPathLabelFormValue(this.cascaderSrv._currentValue)
: this.getLabelFromValue(this.cascaderSrv._currentValue);
}
});
}
}
deleteTag(tagEvent, option) {
tagEvent.event.stopPropagation();
this.cascaderSrv.updateOptionCheckedStatus(option.value, false, this.checkboxRelation.upward, this.checkboxRelation.downward);
this.multipleValueList = this.multipleValueList.filter((t) => t.value !== option.value);
this.onChange(this.cascaderSrv.currentMultipleValue);
// 当taglist变化导致input高度变化时,更新相对位置
setTimeout(() => {
this.mainDropdown.updateCdkConnectedOverlayOrigin();
});
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
writeValue(value) {
if (!this.multiple) {
if (!value) {
this.showTextValue = '';
}
else {
this.showTextValue = this.showPath
? this.getPathLabelFormValue(value)
: this.getLabelFromValue(value);
this.cascaderSrv._currentValue = value;
this.cascaderSrv.updateOptionByValue();
}
}
else {
if (!value) {
this.multipleValueList = [];
}
else {
this.cascaderSrv.currentMultipleValue = value;
this.lazyloadValue = value;
this.multipleValueList = this.getMultipleValueFromValueList(value);
this.updateMultipleValuePathList();
}
}
}
updateMultipleValuePathList() {
if (!this.showPath) {
return;
}
const valueList = this.cascaderSrv.currentMultipleValue;
valueList.forEach((item, index) => {
const value = item[item.length - 1];
const target = this.multipleValueList.find((t) => t.value === value);
if (target) {
target.pathLabel = this.getPathLabelFormValue(item);
}
});
}
// 从路径数组中获取所有tag的值,并让对应checkbox激活
getMultipleValueFromValueList(valueList) {
const targetList = [];
valueList.forEach((value) => {
let cur;
let cacheTarget;
let list = this.cascaderSrv.options;
for (let i = 0; i < value.length; i++) {
cur = list.find((l) => l.value === value[i]);
cacheTarget = cur;
if (this.isLazyLoad && cur && !cur.children?.length && !cur.isLeaf) {
this.cascaderSrv.lazyloadMultipleChild(cur, i);
break;
}
else {
list = (cur && cur.children) || [];
}
}
if (cur && cur.isLeaf) {
targetList.push(cur);
cacheTarget = null;
this.cascaderSrv.updateOptionCheckedStatus(cur.value, true, this.checkboxRelation.upward, this.checkboxRelation.downward);
}
if (cacheTarget) {
targetList.push(cacheTarget);
this.cascaderSrv.updateOptionCheckedStatus(cacheTarget.value, true, this.checkboxRelation.upward, this.checkboxRelation.downward);
}
});
return targetList;
}
// 获取路径末的label
getLabelFromValue(value) {
let cur;
let list = this.cascaderSrv.options;
value.forEach((item) => {
cur = list.find((t) => t.value === item) || '';
list = cur.children || [];
});
return (cur && cur.label) || '';
}
// 将value数组转换为路径字符串
getPathLabelFormValue(value) {
let path = '';
let cur;
let list = this.cascaderSrv.options;
value.forEach((item, index) => {
cur = list.find((t) => t.value === item) || '';
if (cur) {
path = path === '' ? path + cur.label : path + ' / ' + cur.label;
}
else if (this.cascaderSrv.columnList.length === index + 1) {
path = path === '' ? path + item : path + ' / ' + item;
}
list = cur.children || [];
});
return path;
}
clearTags() {
if (this.multiple) {
this.multipleValueList = [];
this.cascaderSrv.resetStatus.next();
this.cascaderSrv.resetNodeStatus();
this.cascaderSrv.currentMultipleValue = [];
}
else {
this.cascaderSrv.currentValue = [];
}
this.onChange([]);
}
onToggle(isOpen) {
this.toggleEvent.emit(isOpen);
if (isOpen && this.multiple) {
this.cascaderSrv.clearTargetActive(this.cascaderSrv.options.find((t) => t.active));
this.cascaderSrv.columnList.splice(1);
if (this.innerInput) {
this.innerInput.nativeElement.focus();
}
}
if (isOpen && !this.multiple && this.allowSearch) {
this.outerInput.nativeElement.focus();
}
if (!isOpen && this.allowSearch) {
if (!this.cascaderSrv.currentValue.length) {
this.showTextValue = null;
}
else {
this.writeValue(this.cascaderSrv.currentValue);
}
// 在动画结束后再设置参数,防止panel中内容突变,动画时间200
this.timer = setTimeout(() => {
this.showSearchPanel = false;
}, 200);
}
if (isOpen) {
this.rePosition();
}
}
// 防止位置超出overlay边界
rePosition() {
if (typeof window === undefined || !this.appendToBody) {
return;
}
setTimeout(() => {
this.dropdownComp.reposition();
const width = this.dropdownComp.overlay.overlayRef?.overlayElement.clientWidth;
const offsetX = this.dropdownComp.overlay.overlayRef?.overlayElement.offsetLeft;
const offsetRight = window.innerWidth - width - offsetX - 20;
this.subMenuDirections.forEach((t) => {
t.offsetX = offsetRight < 0 ? offsetRight : 0;
});
this.dropdownComp.reposition();
}, 0);
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
this.searchValueChange.complete();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CascaderComponent, deps: [{ token: CascaderService }, { token: i2.I18nService }, { token: i3.DevConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: CascaderComponent, selector: "d-cascader", inputs: { options: "options", width: "width", dropdownWidth: "dropdownWidth", placeholder: "placeholder", trigger: "trigger", disabled: "disabled", multiple: "multiple", showPath: "showPath", allowClear: "allowClear", allowSearch: "allowSearch", canSelectParent: "canSelectParent", checkboxRelation: "checkboxRelation", dropDownItemTemplate: "dropDownItemTemplate", dropdownHeaderTemplate: "dropdownHeaderTemplate", hostTemplate: "hostTemplate", dropdownPanelClass: "dropdownPanelClass", appendToBody: "appendToBody", tagMaxWidth: "tagMaxWidth", showAnimation: "showAnimation", styleType: "styleType", loadChildrenFn: "loadChildrenFn", showGlowStyle: "showGlowStyle" }, outputs: { toggleEvent: "toggleEvent" }, host: { properties: { "class.devui-glow-style": "this.hasGlowStyle" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CascaderComponent),
multi: true,
},
CascaderService,
], viewQueries: [{ propertyName: "mainDropdown", first: true, predicate: ["mainDropdown"], descendants: true }, { propertyName: "innerInput", first: true, predicate: ["innerInput"], descendants: true }, { propertyName: "outerInput", first: true, predicate: ["outerInput"], descendants: true }, { propertyName: "dropdownComp", first: true, predicate: DropDownAppendToBodyComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\r\n [ngStyle]=\"{ width: width + 'px' }\"\r\n *ngIf=\"appendToBody\"\r\n dDropDown\r\n appendToBody\r\n [trigger]=\"disabled ? 'manually' : 'click'\"\r\n [closeScope]=\"'blank'\"\r\n #mainDropdown=\"d-dropdown\"\r\n (toggleEvent)=\"onToggle($event)\"\r\n [showAnimation]=\"showAnimation\"\r\n [appendToBodyDirections]=\"subMenuDirections\"\r\n [ngClass]=\"{ 'dropdown-show-clear': allowClear && (showTextValue || multipleValueList.length) }\"\r\n>\r\n <div dDropDownToggle (focus)=\"showSearchInput = true\" [class.devui-gray-style]=\"styleT