import { NgModule, Component, Input, Output, EventEmitter, AfterContentInit, ElementRef, ContentChild, IterableDiffers, ChangeDetectorRef, ContentChildren, QueryList, Inject, forwardRef, OnInit, Renderer2, ViewChild } from '@angular/core'; import { CommonModule } from '@angular/common'; import { TreeNode } from '../common/treenode'; import { Header, Footer, Column } from '../common/shared'; import { PrimeNGSharedModule } from '../common/shared'; import { Subscription } from 'rxjs/Subscription'; import { DomHandler } from '../dom/domhandler'; @Component({ selector: '[pTreeRow]', template: `
{{resolveFieldData(node.data,col.field)}}
` }) export class UITreeRow implements OnInit { @Input() node: TreeNode; @Input() parentNode: TreeNode; @Input() level: number = 0; @Input() labelExpand: string = "展开"; @Input() labelCollapse: string = "折叠"; constructor(@Inject(forwardRef(() => TreeTable)) public treeTable: TreeTable) { } ngOnInit() { this.node.parent = this.parentNode; } toggle(event: Event) { if (this.node.expanded) this.treeTable.onNodeCollapse.emit({ originalEvent: event, node: this.node }); else this.treeTable.onNodeExpand.emit({ originalEvent: event, node: this.node }); this.node.expanded = !this.node.expanded; event.preventDefault(); } isLeaf() { return this.node.leaf == false ? false : !(this.node.children && this.node.children.length); } isSelected() { return this.treeTable.isSelected(this.node); } onRowClick(event: MouseEvent) { this.treeTable.onRowClick(event, this.node); } onRowRightClick(event: MouseEvent) { this.treeTable.onRowRightClick(event, this.node); } rowDblClick(event: MouseEvent) { this.treeTable.onRowDblclick.emit({ originalEvent: event, node: this.node }); } onRowTouchEnd() { this.treeTable.onRowTouchEnd(); } resolveFieldData(data: any, field: string): any { if (data && field) { if (field.indexOf('.') == -1) { return data[field]; } else { let fields: string[] = field.split('.'); let value = data; for (var i = 0, len = fields.length; i < len; ++i) { value = value[fields[i]]; } return value; } } else { return null; } } } @Component({ selector: 'p-treeTable', template: `
{{col.header}}
{{col.footer}}
`, providers: [DomHandler] }) export class TreeTable implements AfterContentInit { @Input() value: TreeNode[]; @Input() selectionMode: string; @Input() selection: any; @Input() style: any; @Input() styleClass: string; @Input() labelExpand: string = "展开"; @Input() labelCollapse: string = "折叠"; @Input() metaKeySelection: boolean = true; @Input() contextMenu: any; @Input() toggleColumnIndex: number = 0; @Input() tableStyle: any; @Input() tableStyleClass: string; @Input() collapsedIcon: string = "ant-table-row-collapsed"; // @Input() collapsedIcon: string = "fa-caret-right"; // @Input() expandedIcon: string = "fa-caret-down"; @Input() expandedIcon: string = "ant-table-row-expanded"; @Output() onRowDblclick: EventEmitter = new EventEmitter(); @Output() selectionChange: EventEmitter = new EventEmitter(); @Output() onNodeSelect: EventEmitter = new EventEmitter(); @Output() onNodeUnselect: EventEmitter = new EventEmitter(); @Output() onNodeExpand: EventEmitter = new EventEmitter(); @Output() onNodeCollapse: EventEmitter = new EventEmitter(); @Output() onContextMenuSelect: EventEmitter = new EventEmitter(); @ContentChild(Header) header: Header; @ContentChild(Footer) footer: Footer; @ContentChildren(Column) cols: QueryList; @ViewChild('tbl') tableViewChild: ElementRef; public rowTouched: boolean; public columns: Column[]; columnsSubscription: Subscription; constructor(public el: ElementRef, public domHandler: DomHandler, public changeDetector: ChangeDetectorRef, public renderer: Renderer2) { } ngAfterContentInit() { this.initColumns(); this.columnsSubscription = this.cols.changes.subscribe(_ => { this.initColumns(); this.changeDetector.markForCheck(); }); } initColumns(): void { this.columns = this.cols.toArray(); } onRowClick(event: MouseEvent, node: TreeNode) { let eventTarget = (event.target); if (eventTarget.className && eventTarget.className.indexOf('ui-treetable-toggler') === 0) { return; } else if (this.selectionMode) { if (node.selectable === false) { return; } let metaSelection = this.rowTouched ? false : this.metaKeySelection; let index = this.findIndexInSelection(node); let selected = (index >= 0); if (this.isCheckboxSelectionMode()) { if (selected) { this.propagateSelectionDown(node, false); if (node.parent) { this.propagateSelectionUp(node.parent, false); } this.selectionChange.emit(this.selection); this.onNodeUnselect.emit({ originalEvent: event, node: node }); } else { this.propagateSelectionDown(node, true); if (node.parent) { this.propagateSelectionUp(node.parent, true); } this.selectionChange.emit(this.selection); this.onNodeSelect.emit({ originalEvent: event, node: node }); } } else { if (metaSelection) { let metaKey = (event.metaKey || event.ctrlKey); if (selected && metaKey) { if (this.isSingleSelectionMode()) { this.selectionChange.emit(null); } else { this.selection = this.selection.filter((val, i) => i != index); this.selectionChange.emit(this.selection); } this.onNodeUnselect.emit({ originalEvent: event, node: node }); } else { if (this.isSingleSelectionMode()) { this.selectionChange.emit(node); } else if (this.isMultipleSelectionMode()) { this.selection = (!metaKey) ? [] : this.selection || []; this.selection = [...this.selection, node]; this.selectionChange.emit(this.selection); } this.onNodeSelect.emit({ originalEvent: event, node: node }); } } else { if (this.isSingleSelectionMode()) { if (selected) { this.selection = null; this.onNodeUnselect.emit({ originalEvent: event, node: node }); } else { this.selection = node; this.onNodeSelect.emit({ originalEvent: event, node: node }); } } else { if (selected) { this.selection = this.selection.filter((val, i) => i != index); this.onNodeUnselect.emit({ originalEvent: event, node: node }); } else { this.selection = [...this.selection || [], node]; this.onNodeSelect.emit({ originalEvent: event, node: node }); } } this.selectionChange.emit(this.selection); } } } this.rowTouched = false; } onRowTouchEnd() { this.rowTouched = true; } onRowRightClick(event: MouseEvent, node: TreeNode) { if (this.contextMenu) { let index = this.findIndexInSelection(node); let selected = (index >= 0); if (!selected) { if (this.isSingleSelectionMode()) { this.selection = node; } else if (this.isMultipleSelectionMode()) { this.selection = [node]; this.selectionChange.emit(this.selection); } this.selectionChange.emit(this.selection); } this.contextMenu.show(event); this.onContextMenuSelect.emit({ originalEvent: event, node: node }); } } findIndexInSelection(node: TreeNode) { let index: number = -1; if (this.selectionMode && this.selection) { if (this.isSingleSelectionMode()) { index = (this.selection == node) ? 0 : - 1; } else { for (let i = 0; i < this.selection.length; i++) { if (this.selection[i] == node) { index = i; break; } } } } return index; } propagateSelectionUp(node: TreeNode, select: boolean) { if (node.children && node.children.length) { let selectedCount: number = 0; let childPartialSelected: boolean = false; for (let child of node.children) { if (this.isSelected(child)) { selectedCount++; } else if (child.partialSelected) { childPartialSelected = true; } } if (select && selectedCount == node.children.length) { this.selection = [...this.selection || [], node]; node.partialSelected = false; } else { if (!select) { let index = this.findIndexInSelection(node); if (index >= 0) { this.selection = this.selection.filter((val, i) => i != index); } } if (childPartialSelected || selectedCount > 0 && selectedCount != node.children.length) node.partialSelected = true; else node.partialSelected = false; } } let parent = node.parent; if (parent) { this.propagateSelectionUp(parent, select); } } propagateSelectionDown(node: TreeNode, select: boolean) { let index = this.findIndexInSelection(node); if (select && index == -1) { this.selection = [...this.selection || [], node]; } else if (!select && index > -1) { this.selection = this.selection.filter((val, i) => i != index); } node.partialSelected = false; if (node.children && node.children.length) { for (let child of node.children) { this.propagateSelectionDown(child, select); } } } isSelected(node: TreeNode) { return this.findIndexInSelection(node) != -1; } isSingleSelectionMode() { return this.selectionMode && this.selectionMode == 'single'; } isMultipleSelectionMode() { return this.selectionMode && this.selectionMode == 'multiple'; } isCheckboxSelectionMode() { return this.selectionMode && this.selectionMode == 'checkbox'; } hasFooter() { if (this.columns)  { let columnsArr = this.cols.toArray(); for (let i = 0; i < columnsArr.length; i++) { if (columnsArr[i].footer) { return true; } } } return false; } } @NgModule({ imports: [CommonModule], exports: [TreeTable, PrimeNGSharedModule], declarations: [TreeTable, UITreeRow] }) export class TreeTableModule { }