/*! * @license * Copyright 2016 Alfresco Software, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { Injectable } from '@angular/core'; import { CollectionViewer, SelectionChange } from '@angular/cdk/collections'; import { BehaviorSubject, merge, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { FlatTreeControl } from '@angular/cdk/tree'; import { TreeBaseNode } from '../models/tree-view.model'; import { TreeViewService } from '../services/tree-view.service'; @Injectable() export class TreeViewDataSource { treeNodes: TreeBaseNode[]; dataChange = new BehaviorSubject([]); childrenSubscription = null; changeSubscription = null; get data(): TreeBaseNode[] { return this.treeNodes; } set data(value: TreeBaseNode[]) { this.treeControl.dataNodes = value; this.dataChange.next(value); } constructor(private treeControl: FlatTreeControl, private treeViewService: TreeViewService) { this.dataChange.subscribe((treeNodes) => this.treeNodes = treeNodes); } connect(collectionViewer: CollectionViewer): Observable { this.changeSubscription = this.treeControl.expansionModel.onChange.subscribe((change) => { if ((change as SelectionChange).added && (change as SelectionChange).added.length > 0) { this.expandTreeNodes(change as SelectionChange); } else if ((change as SelectionChange).removed) { this.reduceTreeNodes(change as SelectionChange); } }); return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data)); } disconnect() { if (this.childrenSubscription) { this.childrenSubscription.unsubscribe(); } if (this.changeSubscription) { this.changeSubscription.unsubscribe(); } } private expandTreeNodes(change: SelectionChange) { change.added.forEach((node) => this.expandNode(node)); } private reduceTreeNodes(change: SelectionChange) { change.removed.slice().reverse().forEach((node) => this.toggleNode(node)); } private expandNode(node: TreeBaseNode) { this.childrenSubscription = this.treeViewService.getTreeNodes(node.nodeId) .subscribe((children) => { const index = this.data.indexOf(node); if (!children || index < 0) { node.expandable = false; return; } const nodes = children.map((actualNode) => { actualNode.level = node.level + 1; return actualNode; }); this.data.splice(index + 1, 0, ...nodes); this.dataChange.next(this.data); }); } toggleNode(node: TreeBaseNode) { const index = this.data.indexOf(node); let count = 0; for (let i = index + 1; i < this.data.length && this.data[i].level > node.level; i++ , count++) { } this.data.splice(index + 1, count); this.dataChange.next(this.data); } }