UNPKG

@progress/kendo-angular-treeview

Version:
213 lines (212 loc) 8.63 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Directive, EventEmitter, Input, Output } from '@angular/core'; import { ExpandableComponent } from './expandable-component'; import { Subscription, merge } from 'rxjs'; import { map } from 'rxjs/operators'; import { isArrayWithAtLeastOneItem, isBoolean, sameValues } from './utils'; import { isChanged } from '@progress/kendo-angular-common'; import * as i0 from "@angular/core"; import * as i1 from "./expandable-component"; const DEFAULT_FILTER_EXPAND_SETTINGS = { maxAutoExpandResults: -1, expandMatches: false, expandedOnClear: "none" }; /** * A directive which manages the expanded state of the TreeView. * ([see example]({% slug expandedstate_treeview %})). */ export class ExpandDirective { component; /** * @hidden */ set isExpanded(value) { this.component.isExpanded = value; } /** * Defines the item key that will be stored in the `expandedKeys` collection. */ expandKey; /** * Whether or not to auto-expand the nodes leading from the root node to each filter result. * To fine-tune this behavior, pass a [`FilterExpandSettings`]({% slug api_treeview_filterexpandsettings %}) object to this input. * @default false */ expandOnFilter = false; get filterExpandSettings() { const settings = isBoolean(this.expandOnFilter) ? { enabled: this.expandOnFilter } : { ...this.expandOnFilter, enabled: true }; return Object.assign({}, DEFAULT_FILTER_EXPAND_SETTINGS, settings); } /** * Fires when the `expandedKeys` collection was updated. */ expandedKeysChange = new EventEmitter(); /** * Defines the collection that will store the expanded keys. */ expandedKeys; subscriptions = new Subscription(); /** * Reflectes the internal `expandedKeys` state. */ state = new Set(); originalExpandedKeys = new Set(); isFiltered = false; /** * Holds the last emitted `expandedKeys` collection. */ lastChange; constructor(component) { this.component = component; this.subscriptions.add(merge(this.component.expand.pipe(map(e => ({ expand: true, ...e }))), this.component.collapse.pipe(map(e => ({ expand: false, ...e })))).subscribe(this.toggleExpand.bind(this))); if (this.component.filterStateChange) { this.subscriptions.add(this.component.filterStateChange.subscribe(this.handleAutoExpand.bind(this))); } this.component.isExpanded = (dataItem, index) => this.state.has(this.itemKey({ dataItem, index })); } ngOnChanges(changes) { if (isChanged('expandedKeys', changes, false) && changes['expandedKeys'].currentValue !== this.lastChange) { this.state = new Set(changes['expandedKeys'].currentValue); } } ngOnDestroy() { this.subscriptions.unsubscribe(); } /** * @hidden */ itemKey(e) { if (this.expandKey) { if (typeof this.expandKey === "string") { return e.dataItem[this.expandKey]; } if (typeof this.expandKey === "function") { return this.expandKey(e); } } return e.index; } toggleExpand({ index, dataItem, expand }) { const key = this.itemKey({ index, dataItem }); const isExpanded = this.state.has(key); let notify = false; if (isExpanded && !expand) { this.state.delete(key); notify = true; } else if (!isExpanded && expand) { this.state.add(key); notify = true; } if (notify) { this.notify(); } } handleAutoExpand({ nodes, matchCount, term }) { if (!this.filterExpandSettings.enabled) { return; } const { maxAutoExpandResults, expandMatches: autoExpandMatches, expandedOnClear } = this.filterExpandSettings; if (!this.isFiltered) { this.originalExpandedKeys = new Set(this.state); } const exitingFilteredState = this.isFiltered && !term; const maxExceeded = maxAutoExpandResults !== -1 && matchCount > maxAutoExpandResults; const exitAutoExpandedState = exitingFilteredState || maxExceeded; if (exitAutoExpandedState) { switch (expandedOnClear) { case "initial": { if (!sameValues(this.state, this.originalExpandedKeys)) { this.state = this.originalExpandedKeys; this.notify(); } break; } case "all": { this.state = new Set(nodes.reduce((acc, rootNode) => { this.getEveryExpandKey(acc, rootNode); return acc; }, [])); this.notify(); break; } case "unchanged": { break; } case "none": default: { if (this.state.size !== 0) { this.state.clear(); this.notify(); } break; } } this.isFiltered = false; return; } const indicesToExpand = new Set(nodes.reduce((acc, rootNode) => { this.updateExpandedNodes(acc, rootNode, autoExpandMatches); return acc; }, [])); if (!sameValues(this.state, indicesToExpand)) { this.state = indicesToExpand; this.notify(); } this.isFiltered = true; } /** * Fills array with the correct expand keys according to wrapper metadata. */ updateExpandedNodes = (collection, node, autoExpandMatches) => { if (node.containsMatches || node.isMatch && autoExpandMatches && isArrayWithAtLeastOneItem(node.children)) { collection.push(this.itemKey({ dataItem: node.dataItem, index: node.index })); } if (isArrayWithAtLeastOneItem(node.children)) { node.children.forEach(child => { this.updateExpandedNodes(collection, child, autoExpandMatches); }); } }; /** * Fills array with the expand key of every node. */ getEveryExpandKey = (collection, node) => { if (isArrayWithAtLeastOneItem(node.children)) { collection.push(this.itemKey({ dataItem: node.dataItem, index: node.index })); } if (isArrayWithAtLeastOneItem(node.children)) { node.children.forEach(child => { this.getEveryExpandKey(collection, child); }); } }; notify() { this.lastChange = Array.from(this.state); this.expandedKeysChange.emit(this.lastChange); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ExpandDirective, deps: [{ token: i1.ExpandableComponent }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ExpandDirective, isStandalone: true, selector: "[kendoTreeViewExpandable]", inputs: { isExpanded: "isExpanded", expandKey: ["expandBy", "expandKey"], expandOnFilter: "expandOnFilter", expandedKeys: "expandedKeys" }, outputs: { expandedKeysChange: "expandedKeysChange" }, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ExpandDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoTreeViewExpandable]', standalone: true }] }], ctorParameters: function () { return [{ type: i1.ExpandableComponent }]; }, propDecorators: { isExpanded: [{ type: Input }], expandKey: [{ type: Input, args: ["expandBy"] }], expandOnFilter: [{ type: Input }], expandedKeysChange: [{ type: Output }], expandedKeys: [{ type: Input }] } });