UNPKG

@samotics/ngx-treeview

Version:

An Angular treeview component with checkbox

847 lines (833 loc) 51.9 kB
import * as i0 from '@angular/core'; import { EventEmitter, Directive, Input, Output, HostBinding, HostListener, Injectable, Component, ViewChild, Pipe, NgModule } from '@angular/core'; import * as i4 from '@angular/forms'; import { FormsModule } from '@angular/forms'; import * as i5 from '@angular/common'; import { CommonModule } from '@angular/common'; import { isNil, pull, concat, isString, isBoolean, includes } from 'lodash'; class DropdownDirective { constructor() { this.internalOpen = false; this.openChange = new EventEmitter(); } get isOpen() { return this.internalOpen; } onKeyupEsc() { this.close(); } onDocumentClick(event) { if (event.button !== 2 && !this.isEventFromToggle(event)) { this.close(); } } open() { if (!this.internalOpen) { this.internalOpen = true; this.openChange.emit(true); } } close() { if (this.internalOpen) { this.internalOpen = false; this.openChange.emit(false); } } toggle() { if (this.isOpen) { this.close(); } else { this.open(); } } isEventFromToggle(event) { return !isNil(this.toggleElement) && this.toggleElement.contains(event.target); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DropdownDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: DropdownDirective, selector: "[ngxDropdown]", inputs: { internalOpen: ["open", "internalOpen"] }, outputs: { openChange: "openChange" }, host: { listeners: { "keyup.esc": "onKeyupEsc()", "document:click": "onDocumentClick($event)" }, properties: { "class.show": "this.isOpen" } }, exportAs: ["ngxDropdown"], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DropdownDirective, decorators: [{ type: Directive, args: [{ selector: '[ngxDropdown]', exportAs: 'ngxDropdown' }] }], propDecorators: { internalOpen: [{ type: Input, args: ['open'] }], openChange: [{ type: Output }], isOpen: [{ type: HostBinding, args: ['class.show'] }], onKeyupEsc: [{ type: HostListener, args: ['keyup.esc'] }], onDocumentClick: [{ type: HostListener, args: ['document:click', ['$event']] }] } }); class DropdownMenuDirective { constructor(dropdown) { this.dropdown = dropdown; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DropdownMenuDirective, deps: [{ token: DropdownDirective }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: DropdownMenuDirective, selector: "[ngxDropdownMenu]", host: { properties: { "class.dropdown-menu": "true", "class.show": "dropdown.isOpen" } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DropdownMenuDirective, decorators: [{ type: Directive, args: [{ selector: '[ngxDropdownMenu]', host: { '[class.dropdown-menu]': 'true', '[class.show]': 'dropdown.isOpen' } }] }], ctorParameters: () => [{ type: DropdownDirective }] }); class DropdownToggleDirective { constructor(dropdown, elementRef) { this.dropdown = dropdown; dropdown.toggleElement = elementRef.nativeElement; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DropdownToggleDirective, deps: [{ token: DropdownDirective }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: DropdownToggleDirective, selector: "[ngxDropdownToggle]", host: { attributes: { "aria-haspopup": "true" }, listeners: { "click": "dropdown.toggle()" }, properties: { "attr.aria-expanded": "dropdown.isOpen" }, classAttribute: "dropdown-toggle" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DropdownToggleDirective, decorators: [{ type: Directive, args: [{ selector: '[ngxDropdownToggle]', host: { class: 'dropdown-toggle', 'aria-haspopup': 'true', '[attr.aria-expanded]': 'dropdown.isOpen', '(click)': 'dropdown.toggle()' } }] }], ctorParameters: () => [{ type: DropdownDirective }, { type: i0.ElementRef }] }); const TreeviewHelper = { findItem, findItemInList, findParent, removeItem, concatSelection }; function findItem(root, value) { if (isNil(root)) { return undefined; } if (root.value === value) { return root; } if (root.children) { for (const child of root.children) { const foundItem = findItem(child, value); if (foundItem) { return foundItem; } } } return undefined; } function findItemInList(list, value) { if (isNil(list)) { return undefined; } for (const item of list) { const foundItem = findItem(item, value); if (foundItem) { return foundItem; } } return undefined; } function findParent(root, item) { if (isNil(root) || isNil(root.children)) { return undefined; } for (const child of root.children) { if (child === item) { return root; } else { const parent = findParent(child, item); if (parent) { return parent; } } } return undefined; } function removeItem(root, item) { const parent = findParent(root, item); if (parent) { pull(parent.children, item); if (parent.children.length === 0) { parent.children = undefined; } else { parent.correctChecked(); } return true; } return false; } function concatSelection(items, checked, unchecked) { let checkedItems = [...checked]; let uncheckedItems = [...unchecked]; for (const item of items) { const selection = item.getSelection(); checkedItems = concat(checkedItems, selection.checkedItems); uncheckedItems = concat(uncheckedItems, selection.uncheckedItems); } return { checked: checkedItems, unchecked: uncheckedItems }; } class TreeviewItem { constructor(item, autoCorrectChecked = false) { this.internalDisabled = false; this.internalChecked = true; this.internalCollapsed = false; if (isNil(item)) { throw new Error('Item must be defined'); } if (isString(item.text)) { this.text = item.text; } else { throw new Error('A text of item must be string object'); } this.value = item.value; if (isBoolean(item.checked)) { this.checked = item.checked; } if (isBoolean(item.collapsed)) { this.collapsed = item.collapsed; } if (isBoolean(item.disabled)) { this.disabled = item.disabled; } if (!isNil(item.children) && item.children.length > 0) { this.children = item.children.map(child => { if (this.disabled === true) { child.disabled = true; } return new TreeviewItem(child); }); } if (autoCorrectChecked) { this.correctChecked(); } } get checked() { return this.internalChecked; } set checked(value) { if (!this.internalDisabled) { if (this.internalChecked !== value) { this.internalChecked = value; } } } get indeterminate() { return this.checked === undefined; } setCheckedRecursive(value) { if (!this.internalDisabled) { this.internalChecked = value; if (!isNil(this.internalChildren)) { this.internalChildren.forEach(child => child.setCheckedRecursive(value)); } } } get disabled() { return this.internalDisabled; } set disabled(value) { if (this.internalDisabled !== value) { this.internalDisabled = value; if (!isNil(this.internalChildren)) { this.internalChildren.forEach(child => child.disabled = value); } } } get collapsed() { return this.internalCollapsed; } set collapsed(value) { if (this.internalCollapsed !== value) { this.internalCollapsed = value; } } setCollapsedRecursive(value) { this.internalCollapsed = value; if (!isNil(this.internalChildren)) { this.internalChildren.forEach(child => child.setCollapsedRecursive(value)); } } get children() { return this.internalChildren; } set children(value) { if (this.internalChildren !== value) { if (!isNil(value) && value.length === 0) { throw new Error('Children must be not an empty array'); } this.internalChildren = value; if (!isNil(this.internalChildren)) { let checked = null; this.internalChildren.forEach(child => { if (checked === null) { checked = child.checked; } else { if (child.checked !== checked) { checked = undefined; return; } } }); this.internalChecked = checked; } } } getSelection() { let checkedItems = []; let uncheckedItems = []; if (isNil(this.internalChildren)) { if (this.internalChecked) { checkedItems.push(this); } else { uncheckedItems.push(this); } } else { const selection = TreeviewHelper.concatSelection(this.internalChildren, checkedItems, uncheckedItems); checkedItems = selection.checked; uncheckedItems = selection.unchecked; } return { checkedItems, uncheckedItems }; } correctChecked() { this.internalChecked = this.getCorrectChecked(); } getCorrectChecked() { let checked = null; if (!isNil(this.internalChildren)) { for (const child of this.internalChildren) { child.internalChecked = child.getCorrectChecked(); if (checked === null) { checked = child.internalChecked; } else if (checked !== child.internalChecked) { checked = undefined; break; } } } else { checked = this.checked; } return checked; } } class TreeviewI18n { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewI18n, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewI18n }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewI18n, decorators: [{ type: Injectable }] }); class DefaultTreeviewI18n extends TreeviewI18n { getText(selection) { if (selection.uncheckedItems.length === 0) { if (selection.checkedItems.length > 0) { return this.getAllCheckboxText(); } else { return ''; } } switch (selection.checkedItems.length) { case 0: return 'Select options'; case 1: return selection.checkedItems[0].text; default: return `${selection.checkedItems.length} options selected`; } } getAllCheckboxText() { return 'All'; } getFilterPlaceholder() { return 'Filter'; } getFilterNoItemsFoundText() { return 'No items found'; } getTooltipCollapseExpandText(isCollapse) { return isCollapse ? 'Expand' : 'Collapse'; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultTreeviewI18n, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultTreeviewI18n }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultTreeviewI18n, decorators: [{ type: Injectable }] }); class TreeviewConfig { constructor() { this.hasAllCheckBox = true; this.hasFilter = false; this.hasCollapseExpand = false; this.decoupleChildFromParent = false; this.maxHeight = 500; } get hasDivider() { return this.hasFilter || this.hasAllCheckBox || this.hasCollapseExpand; } static create(fields) { const config = new TreeviewConfig(); Object.assign(config, fields); return config; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewConfig }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewConfig, decorators: [{ type: Injectable }] }); class TreeviewEventParser { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewEventParser, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewEventParser }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewEventParser, decorators: [{ type: Injectable }] }); class DefaultTreeviewEventParser extends TreeviewEventParser { getSelectedChange(component) { const checkedItems = component.selection.checkedItems; if (!isNil(checkedItems)) { return checkedItems.map(item => item.value); } return []; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultTreeviewEventParser, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultTreeviewEventParser }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultTreeviewEventParser, decorators: [{ type: Injectable }] }); class DownlineTreeviewEventParser extends TreeviewEventParser { getSelectedChange(component) { const items = component.items; if (!isNil(items)) { let result = []; items.forEach(item => { const links = this.getLinks(item, null); if (!isNil(links)) { result = result.concat(links); } }); return result; } return []; } getLinks(item, parent) { if (!isNil(item.children)) { const link = { item, parent }; let result = []; item.children.forEach(child => { const links = this.getLinks(child, link); if (!isNil(links)) { result = result.concat(links); } }); return result; } if (item.checked) { return [{ item, parent }]; } return null; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DownlineTreeviewEventParser, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DownlineTreeviewEventParser }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DownlineTreeviewEventParser, decorators: [{ type: Injectable }] }); class OrderDownlineTreeviewEventParser extends TreeviewEventParser { constructor() { super(...arguments); this.currentDownlines = []; this.parser = new DownlineTreeviewEventParser(); } getSelectedChange(component) { const newDownlines = this.parser.getSelectedChange(component); if (this.currentDownlines.length === 0) { this.currentDownlines = newDownlines; } else { const intersectDownlines = []; this.currentDownlines.forEach(downline => { let foundIndex = -1; const length = newDownlines.length; for (let i = 0; i < length; i++) { if (downline.item.value === newDownlines[i].item.value) { foundIndex = i; break; } } if (foundIndex !== -1) { intersectDownlines.push(newDownlines[foundIndex]); newDownlines.splice(foundIndex, 1); } }); this.currentDownlines = intersectDownlines.concat(newDownlines); } return this.currentDownlines; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OrderDownlineTreeviewEventParser, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OrderDownlineTreeviewEventParser }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OrderDownlineTreeviewEventParser, decorators: [{ type: Injectable }] }); class TreeviewItemComponent { constructor(defaultConfig) { this.defaultConfig = defaultConfig; this.checkedChange = new EventEmitter(); this.onCollapseExpand = () => { this.item.collapsed = !this.item.collapsed; }; this.onCheckedChange = () => { const checked = this.item.checked; if (!isNil(this.item.children) && !this.config.decoupleChildFromParent) { this.item.children.forEach(child => child.setCheckedRecursive(checked)); } this.checkedChange.emit(checked); }; this.config = this.defaultConfig; } onChildCheckedChange(child, checked) { if (!this.config.decoupleChildFromParent) { let itemChecked = null; for (const childItem of this.item.children) { if (itemChecked === null) { itemChecked = childItem.checked; } else if (itemChecked !== childItem.checked) { itemChecked = undefined; break; } } if (itemChecked === null) { itemChecked = false; } if (this.item.checked !== itemChecked) { this.item.checked = itemChecked; } } this.checkedChange.emit(checked); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewItemComponent, deps: [{ token: TreeviewConfig }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeviewItemComponent, selector: "ngx-treeview-item", inputs: { config: "config", template: "template", item: "item" }, outputs: { checkedChange: "checkedChange" }, ngImport: i0, template: "<div *ngIf=\"item\" class=\"treeview-item\">\n <ng-template [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{item: item, onCollapseExpand: onCollapseExpand, onCheckedChange: onCheckedChange}\">\n </ng-template>\n <div *ngIf=\"!item.collapsed\">\n <ngx-treeview-item [config]=\"config\" *ngFor=\"let child of item.children\" [item]=\"child\" [template]=\"template\"\n (checkedChange)=\"onChildCheckedChange(child, $event)\">\n </ngx-treeview-item>\n </div>\n</div>\n", styles: [":host{display:block}:host .treeview-item{white-space:nowrap}:host .treeview-item .treeview-item{margin-left:2rem}\n"], dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TreeviewItemComponent, selector: "ngx-treeview-item", inputs: ["config", "template", "item"], outputs: ["checkedChange"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewItemComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-treeview-item', template: "<div *ngIf=\"item\" class=\"treeview-item\">\n <ng-template [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{item: item, onCollapseExpand: onCollapseExpand, onCheckedChange: onCheckedChange}\">\n </ng-template>\n <div *ngIf=\"!item.collapsed\">\n <ngx-treeview-item [config]=\"config\" *ngFor=\"let child of item.children\" [item]=\"child\" [template]=\"template\"\n (checkedChange)=\"onChildCheckedChange(child, $event)\">\n </ngx-treeview-item>\n </div>\n</div>\n", styles: [":host{display:block}:host .treeview-item{white-space:nowrap}:host .treeview-item .treeview-item{margin-left:2rem}\n"] }] }], ctorParameters: () => [{ type: TreeviewConfig }], propDecorators: { config: [{ type: Input }], template: [{ type: Input }], item: [{ type: Input }], checkedChange: [{ type: Output }] } }); class FilterTreeviewItem extends TreeviewItem { constructor(item) { super({ text: item.text, value: item.value, disabled: item.disabled, checked: item.checked, collapsed: item.collapsed, children: item.children }); this.refItem = item; } updateRefChecked() { this.children.forEach(child => { if (child instanceof FilterTreeviewItem) { child.updateRefChecked(); } }); let refChecked = this.checked; if (refChecked) { for (const refChild of this.refItem.children) { if (!refChild.checked) { refChecked = false; break; } } } this.refItem.checked = refChecked; } } class TreeviewComponent { constructor(i18n, defaultConfig, eventParser) { this.i18n = i18n; this.defaultConfig = defaultConfig; this.eventParser = eventParser; this.selectedChange = new EventEmitter(); this.filterChange = new EventEmitter(); this.filterText = ''; this.config = this.defaultConfig; this.allItem = new TreeviewItem({ text: 'All', value: undefined }); } get hasFilterItems() { return !isNil(this.filterItems) && this.filterItems.length > 0; } get maxHeight() { return `${this.config.maxHeight}`; } ngOnInit() { this.createHeaderTemplateContext(); this.generateSelection(); } ngOnChanges(changes) { const itemsSimpleChange = changes.items; if (!isNil(itemsSimpleChange) && !isNil(this.items)) { this.updateFilterItems(); this.updateCollapsedOfAll(); this.raiseSelectedChange(); } } onAllCollapseExpand() { this.allItem.collapsed = !this.allItem.collapsed; this.filterItems.forEach(item => item.setCollapsedRecursive(this.allItem.collapsed)); } onFilterTextChange(text) { this.filterText = text; this.filterChange.emit(text); this.updateFilterItems(); } onAllCheckedChange() { const checked = this.allItem.checked; this.filterItems.forEach(item => { item.setCheckedRecursive(checked); if (item instanceof FilterTreeviewItem) { item.updateRefChecked(); } }); this.raiseSelectedChange(); } onItemCheckedChange(item, checked) { if (item instanceof FilterTreeviewItem) { item.updateRefChecked(); } this.updateCheckedOfAll(); this.raiseSelectedChange(); } raiseSelectedChange() { this.generateSelection(); const values = this.eventParser.getSelectedChange(this); setTimeout(() => { this.selectedChange.emit(values); }); } createHeaderTemplateContext() { this.headerTemplateContext = { config: this.config, item: this.allItem, onCheckedChange: () => this.onAllCheckedChange(), onCollapseExpand: () => this.onAllCollapseExpand(), onFilterTextChange: (text) => this.onFilterTextChange(text) }; } generateSelection() { let checkedItems = []; let uncheckedItems = []; if (!isNil(this.items)) { const selection = TreeviewHelper.concatSelection(this.items, checkedItems, uncheckedItems); checkedItems = selection.checked; uncheckedItems = selection.unchecked; } this.selection = { checkedItems, uncheckedItems }; } updateFilterItems() { if (this.filterText !== '') { const filterItems = []; const filterText = this.filterText.toLowerCase(); this.items.forEach(item => { const newItem = this.filterItem(item, filterText); if (!isNil(newItem)) { filterItems.push(newItem); } }); this.filterItems = filterItems; } else { this.filterItems = this.items; } this.updateCheckedOfAll(); } filterItem(item, filterText) { const isMatch = includes(item.text.toLowerCase(), filterText); if (isMatch) { return item; } else { if (!isNil(item.children)) { const children = []; item.children.forEach(child => { const newChild = this.filterItem(child, filterText); if (!isNil(newChild)) { children.push(newChild); } }); if (children.length > 0) { const newItem = new FilterTreeviewItem(item); newItem.collapsed = false; newItem.children = children; return newItem; } } } return undefined; } updateCheckedOfAll() { let itemChecked = null; for (const filterItem of this.filterItems) { if (itemChecked === null) { itemChecked = filterItem.checked; } else if (itemChecked !== filterItem.checked) { itemChecked = undefined; break; } } if (itemChecked === null) { itemChecked = false; } this.allItem.checked = itemChecked; } updateCollapsedOfAll() { let hasItemExpanded = false; for (const filterItem of this.filterItems) { if (!filterItem.collapsed) { hasItemExpanded = true; break; } } this.allItem.collapsed = !hasItemExpanded; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewComponent, deps: [{ token: TreeviewI18n }, { token: TreeviewConfig }, { token: TreeviewEventParser }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeviewComponent, selector: "ngx-treeview", inputs: { headerTemplate: "headerTemplate", itemTemplate: "itemTemplate", items: "items", config: "config" }, outputs: { selectedChange: "selectedChange", filterChange: "filterChange" }, usesOnChanges: true, ngImport: i0, template: "<ng-template #defaultItemTemplate let-item=\"item\" let-onCollapseExpand=\"onCollapseExpand\"\n let-onCheckedChange=\"onCheckedChange\">\n <div class=\"form-inline row-item\">\n <i *ngIf=\"item.children\" (click)=\"onCollapseExpand()\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\">\n <svg *ngSwitchCase=\"true\" width=\"0.8rem\" height=\"0.8rem\" viewBox=\"0 0 16 16\" class=\"bi bi-caret-right-fill\"\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12.14 8.753l-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z\" />\n </svg>\n <svg *ngSwitchCase=\"false\" width=\"0.8rem\" height=\"0.8rem\" viewBox=\"0 0 16 16\" class=\"bi bi-caret-down-fill\"\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M7.247 11.14L2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z\" />\n </svg>\n </i>\n <div class=\"form-check\">\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"item.checked\" (ngModelChange)=\"onCheckedChange()\"\n [disabled]=\"item.disabled\" [indeterminate]=\"item.indeterminate\" />\n <label class=\"form-check-label\" (click)=\"item.checked = !item.checked; onCheckedChange()\">\n {{item.text}}\n </label>\n </div>\n </div>\n</ng-template>\n<ng-template #defaultHeaderTemplate let-config=\"config\" let-item=\"item\" let-onCollapseExpand=\"onCollapseExpand\"\n let-onCheckedChange=\"onCheckedChange\" let-onFilterTextChange=\"onFilterTextChange\">\n <div *ngIf=\"config.hasFilter\" class=\"row row-filter\">\n <div class=\"col-12\">\n <input class=\"form-control\" type=\"text\" [placeholder]=\"i18n.getFilterPlaceholder()\" [(ngModel)]=\"filterText\"\n (ngModelChange)=\"onFilterTextChange($event)\" />\n </div>\n </div>\n <div *ngIf=\"hasFilterItems\">\n <div *ngIf=\"config.hasAllCheckBox || config.hasCollapseExpand\" class=\"row row-all\">\n <div class=\"col-12\">\n <div class=\"form-check form-check-inline\" *ngIf=\"config.hasAllCheckBox\">\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"item.checked\" (ngModelChange)=\"onCheckedChange()\"\n [indeterminate]=\"item.indeterminate\" />\n <label class=\"form-check-label\" (click)=\"item.checked = !item.checked; onCheckedChange()\">\n {{i18n.getAllCheckboxText()}}\n </label>\n </div>\n <label *ngIf=\"config.hasCollapseExpand\" class=\"float-right form-check-label\" (click)=\"onCollapseExpand()\">\n <i [title]=\"i18n.getTooltipCollapseExpandText(item.collapsed)\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\">\n <svg *ngSwitchCase=\"true\" width=\"1em\" height=\"1em\" viewBox=\"0 0 16 16\" class=\"bi bi-arrows-angle-expand\"\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\"\n d=\"M1.5 10.036a.5.5 0 0 1 .5.5v3.5h3.5a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5z\" />\n <path fill-rule=\"evenodd\"\n d=\"M6.354 9.646a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0zm8.5-8.5a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0z\" />\n <path fill-rule=\"evenodd\"\n d=\"M10.036 1.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 1 1-1 0V2h-3.5a.5.5 0 0 1-.5-.5z\" />\n </svg>\n <svg *ngSwitchCase=\"false\" width=\"1em\" height=\"1em\" viewBox=\"0 0 16 16\" class=\"bi bi-arrows-angle-contract\"\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\"\n d=\"M9.5 2.036a.5.5 0 0 1 .5.5v3.5h3.5a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5z\" />\n <path fill-rule=\"evenodd\"\n d=\"M14.354 1.646a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 1 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0zm-7.5 7.5a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0z\" />\n <path fill-rule=\"evenodd\"\n d=\"M2.036 9.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V10h-3.5a.5.5 0 0 1-.5-.5z\" />\n </svg>\n </i>\n </label>\n </div>\n </div>\n <div *ngIf=\"config.hasDivider\" class=\"dropdown-divider\"></div>\n </div>\n</ng-template>\n<div class=\"treeview-header\">\n <ng-template [ngTemplateOutlet]=\"headerTemplate || defaultHeaderTemplate\"\n [ngTemplateOutletContext]=\"headerTemplateContext\">\n </ng-template>\n</div>\n<div [ngSwitch]=\"hasFilterItems\">\n <div *ngSwitchCase=\"true\" class=\"treeview-container\" [style.max-height.px]=\"maxHeight\">\n <ngx-treeview-item *ngFor=\"let item of filterItems\" [config]=\"config\" [item]=\"item\"\n [template]=\"itemTemplate || defaultItemTemplate\" (checkedChange)=\"onItemCheckedChange(item, $event)\">\n </ngx-treeview-item>\n </div>\n <div *ngSwitchCase=\"false\" class=\"treeview-text\">\n {{i18n.getFilterNoItemsFoundText()}}\n </div>\n</div>\n", styles: [":host .treeview-header .row-filter{margin-bottom:.5rem}:host .treeview-header .row-all .bi{cursor:pointer}:host .treeview-container .row-item{margin-bottom:.3rem;flex-wrap:nowrap}:host .treeview-container .row-item .bi{cursor:pointer;margin-right:.3rem}.treeview-container{overflow-y:auto;padding-right:.3rem}.treeview-text{padding:.3rem 0;white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: TreeviewItemComponent, selector: "ngx-treeview-item", inputs: ["config", "template", "item"], outputs: ["checkedChange"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-treeview', template: "<ng-template #defaultItemTemplate let-item=\"item\" let-onCollapseExpand=\"onCollapseExpand\"\n let-onCheckedChange=\"onCheckedChange\">\n <div class=\"form-inline row-item\">\n <i *ngIf=\"item.children\" (click)=\"onCollapseExpand()\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\">\n <svg *ngSwitchCase=\"true\" width=\"0.8rem\" height=\"0.8rem\" viewBox=\"0 0 16 16\" class=\"bi bi-caret-right-fill\"\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12.14 8.753l-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z\" />\n </svg>\n <svg *ngSwitchCase=\"false\" width=\"0.8rem\" height=\"0.8rem\" viewBox=\"0 0 16 16\" class=\"bi bi-caret-down-fill\"\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M7.247 11.14L2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z\" />\n </svg>\n </i>\n <div class=\"form-check\">\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"item.checked\" (ngModelChange)=\"onCheckedChange()\"\n [disabled]=\"item.disabled\" [indeterminate]=\"item.indeterminate\" />\n <label class=\"form-check-label\" (click)=\"item.checked = !item.checked; onCheckedChange()\">\n {{item.text}}\n </label>\n </div>\n </div>\n</ng-template>\n<ng-template #defaultHeaderTemplate let-config=\"config\" let-item=\"item\" let-onCollapseExpand=\"onCollapseExpand\"\n let-onCheckedChange=\"onCheckedChange\" let-onFilterTextChange=\"onFilterTextChange\">\n <div *ngIf=\"config.hasFilter\" class=\"row row-filter\">\n <div class=\"col-12\">\n <input class=\"form-control\" type=\"text\" [placeholder]=\"i18n.getFilterPlaceholder()\" [(ngModel)]=\"filterText\"\n (ngModelChange)=\"onFilterTextChange($event)\" />\n </div>\n </div>\n <div *ngIf=\"hasFilterItems\">\n <div *ngIf=\"config.hasAllCheckBox || config.hasCollapseExpand\" class=\"row row-all\">\n <div class=\"col-12\">\n <div class=\"form-check form-check-inline\" *ngIf=\"config.hasAllCheckBox\">\n <input type=\"checkbox\" class=\"form-check-input\" [(ngModel)]=\"item.checked\" (ngModelChange)=\"onCheckedChange()\"\n [indeterminate]=\"item.indeterminate\" />\n <label class=\"form-check-label\" (click)=\"item.checked = !item.checked; onCheckedChange()\">\n {{i18n.getAllCheckboxText()}}\n </label>\n </div>\n <label *ngIf=\"config.hasCollapseExpand\" class=\"float-right form-check-label\" (click)=\"onCollapseExpand()\">\n <i [title]=\"i18n.getTooltipCollapseExpandText(item.collapsed)\" aria-hidden=\"true\" [ngSwitch]=\"item.collapsed\">\n <svg *ngSwitchCase=\"true\" width=\"1em\" height=\"1em\" viewBox=\"0 0 16 16\" class=\"bi bi-arrows-angle-expand\"\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\"\n d=\"M1.5 10.036a.5.5 0 0 1 .5.5v3.5h3.5a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5z\" />\n <path fill-rule=\"evenodd\"\n d=\"M6.354 9.646a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0zm8.5-8.5a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0z\" />\n <path fill-rule=\"evenodd\"\n d=\"M10.036 1.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 1 1-1 0V2h-3.5a.5.5 0 0 1-.5-.5z\" />\n </svg>\n <svg *ngSwitchCase=\"false\" width=\"1em\" height=\"1em\" viewBox=\"0 0 16 16\" class=\"bi bi-arrows-angle-contract\"\n fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\"\n d=\"M9.5 2.036a.5.5 0 0 1 .5.5v3.5h3.5a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5z\" />\n <path fill-rule=\"evenodd\"\n d=\"M14.354 1.646a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 1 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0zm-7.5 7.5a.5.5 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708l4.5-4.5a.5.5 0 0 1 .708 0z\" />\n <path fill-rule=\"evenodd\"\n d=\"M2.036 9.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V10h-3.5a.5.5 0 0 1-.5-.5z\" />\n </svg>\n </i>\n </label>\n </div>\n </div>\n <div *ngIf=\"config.hasDivider\" class=\"dropdown-divider\"></div>\n </div>\n</ng-template>\n<div class=\"treeview-header\">\n <ng-template [ngTemplateOutlet]=\"headerTemplate || defaultHeaderTemplate\"\n [ngTemplateOutletContext]=\"headerTemplateContext\">\n </ng-template>\n</div>\n<div [ngSwitch]=\"hasFilterItems\">\n <div *ngSwitchCase=\"true\" class=\"treeview-container\" [style.max-height.px]=\"maxHeight\">\n <ngx-treeview-item *ngFor=\"let item of filterItems\" [config]=\"config\" [item]=\"item\"\n [template]=\"itemTemplate || defaultItemTemplate\" (checkedChange)=\"onItemCheckedChange(item, $event)\">\n </ngx-treeview-item>\n </div>\n <div *ngSwitchCase=\"false\" class=\"treeview-text\">\n {{i18n.getFilterNoItemsFoundText()}}\n </div>\n</div>\n", styles: [":host .treeview-header .row-filter{margin-bottom:.5rem}:host .treeview-header .row-all .bi{cursor:pointer}:host .treeview-container .row-item{margin-bottom:.3rem;flex-wrap:nowrap}:host .treeview-container .row-item .bi{cursor:pointer;margin-right:.3rem}.treeview-container{overflow-y:auto;padding-right:.3rem}.treeview-text{padding:.3rem 0;white-space:nowrap}\n"] }] }], ctorParameters: () => [{ type: TreeviewI18n }, { type: TreeviewConfig }, { type: TreeviewEventParser }], propDecorators: { headerTemplate: [{ type: Input }], itemTemplate: [{ type: Input }], items: [{ type: Input }], config: [{ type: Input }], selectedChange: [{ type: Output }], filterChange: [{ type: Output }] } }); class DropdownTreeviewComponent { constructor(i18n, defaultConfig) { this.i18n = i18n; this.defaultConfig = defaultConfig; this.buttonClass = 'btn-outline-secondary'; this.selectedChange = new EventEmitter(true); this.filterChange = new EventEmitter(); this.config = this.defaultConfig; } onSelectedChange(values) { this.buttonLabel = this.i18n.getText(this.treeviewComponent.selection); this.selectedChange.emit(values); } onFilterChange(text) { this.filterChange.emit(text); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DropdownTreeviewComponent, deps: [{ token: TreeviewI18n }, { token: TreeviewConfig }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DropdownTreeviewComponent, selector: "ngx-dropdown-treeview", inputs: { buttonClass: "buttonClass", headerTemplate: "headerTemplate", itemTemplate: "itemTemplate", items: "items", config: "config" }, outputs: { selectedChange: "selectedChange", filterChange: "filterChange" }, viewQueries: [{ propertyName: "treeviewComponent", first: true, predicate: TreeviewComponent, descendants: true }], ngImport: i0, template: "<div class=\"dropdown\" ngxDropdown>\n <button class=\"btn\" [ngClass]=\"buttonClass\" type=\"button\" role=\"button\" ngxDropdownToggle>\n {{buttonLabel}}\n </button>\n <div ngxDropdownMenu aria-labelledby=\"dropdownMenu\" (click)=\"$event.stopPropagation()\">\n <div class=\"dropdown-container\">\n <ngx-treeview [config]=\"config\" [headerTemplate]=\"headerTemplate\" [items]=\"items\" [itemTemplate]=\"itemTemplate\"\n (selectedChange)=\"onSelectedChange($event)\" (filterChange)=\"onFilterChange($event)\">\n </ngx-treeview>\n </div>\n </div>\n</div>\n", styles: [".dropdown{width:100%;display:inline-block}.dropdown button{width:100%;margin-right:.9rem;text-align:left;overflow:hidden;padding-right:30px;text-overflow:ellipsis}.dropdown button:after{position:absolute;right:.6rem;margin-top:.6rem}.dropdown .dropdown-menu .dropdown-container{padding:0 .6rem}\n"], dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: TreeviewComponent, selector: "ngx-treeview", inputs: ["headerTemplate", "itemTemplate", "items", "config"], outputs: ["selectedChange", "filterChange"] }, { kind: "directive", type: DropdownDirective, selector: "[ngxDropdown]", inputs: ["open"], outputs: ["openChange"], exportAs: ["ngxDropdown"] }, { kind: "directive", type: DropdownMenuDirective, selector: "[ngxDropdownMenu]" }, { kind: "directive", type: DropdownToggleDirective, selector: "[ngxDropdownToggle]" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DropdownTreeviewComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-dropdown-treeview', template: "<div class=\"dropdown\" ngxDropdown>\n <button class=\"btn\" [ngClass]=\"buttonClass\" type=\"button\" role=\"button\" ngxDropdownToggle>\n {{buttonLabel}}\n </button>\n <div ngxDropdownMenu aria-labelledby=\"dropdownMenu\" (click)=\"$event.stopPropagation()\">\n <div class=\"dropdown-container\">\n <ngx-treeview [config]=\"config\" [headerTemplate]=\"headerTemplate\" [items]=\"items\" [itemTemplate]=\"itemTemplate\"\n (selectedChange)=\"onSelectedChange($event)\" (filterChange)=\"onFilterChange($event)\">\n </ngx-treeview>\n </div>\n </div>\n</div>\n", styles: [".dropdown{width:100%;display:inline-block}.dropdown button{width:100%;margin-right:.9rem;text-align:left;overflow:hidden;padding-right:30px;text-overflow:ellipsis}.dropdown button:after{position:absolute;right:.6rem;margin-top:.6rem}.dropdown .dropdown-menu .dropdown-container{padding:0 .6rem}\n"] }] }], ctorParameters: () => [{ type: TreeviewI18n }, { type: TreeviewConfig }], propDecorators: { buttonClass: [{ type: Input }], headerTemplate: [{ type: Input }], itemTemplate: [{ type: Input }], items: [{ type: Input }], config: [{ type: Input }], selectedChange: [{ type: Output }], filterChange: [{ type: Output }], treeviewComponent: [{ type: ViewChild, args: [TreeviewComponent, { static: false }] }] } }); class TreeviewPipe { transform(objects, textField) { if (isNil(objects)) { return undefined; } return objects.map(object => new TreeviewItem({ text: object[textField], value: object })); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); } static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: TreeviewPipe, name: "ngxTreeview" }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewPipe, decorators: [{ type: Pipe, args: [{ name: 'ngxTreeview' }] }] }); class TreeviewModule { static forRoot() { return { ngModule: TreeviewModule, providers: [ TreeviewConfig, { provide: TreeviewI18n, useClass: DefaultTreeviewI18n }, { provide: TreeviewEventParser, useClass: DefaultTreeviewEventParser } ] }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeviewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: TreeviewModule, declarations: [TreeviewComponent, TreeviewItemComponent, TreeviewPipe, DropdownDirective, DropdownMenuDirective, DropdownToggleDirective,