Skip to content

feat(tree): filtration (#UIM-14) #195

Merged
merged 12 commits into from
Aug 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions packages/cdk/tree/control/base-tree-control.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { SelectionModel } from '@angular/cdk/collections';
import { Observable } from 'rxjs';
import { BehaviorSubject, Observable } from 'rxjs';

import { ITreeControl } from './tree-control';
import { TreeControl } from './tree-control';


/** Base tree control. It has basic toggle/expand/collapse operations on a single data node. */
// todo здесь явно ошибка проектирования, абстрактный класс реализует функционал
/* tslint:disable-next-line:naming-convention */
export abstract class BaseTreeControl<T> implements ITreeControl<T> {
export abstract class BaseTreeControl<T> implements TreeControl<T> {

/** Saved data node for `expandAll` action. */
dataNodes: T[];

/** A selection model with multi-selection to track expansion status. */
expansionModel: SelectionModel<T> = new SelectionModel<T>(true);

filterModel: SelectionModel<T> = new SelectionModel<T>(true);

filterValue = new BehaviorSubject<string>('');

/** Get depth of a given data node, return the level number. This is for flat tree node. */
getLevel: (dataNode: T) => number;

Expand All @@ -35,16 +37,22 @@ export abstract class BaseTreeControl<T> implements ITreeControl<T> {

/** Toggles one single data node's expanded/collapsed state. */
toggle(dataNode: T): void {
if (this.filterValue.value) { return; }

this.expansionModel.toggle(dataNode);
}

/** Expands one single data node. */
expand(dataNode: T): void {
if (this.filterValue.value) { return; }

this.expansionModel.select(dataNode);
}

/** Collapses one single data node. */
collapse(dataNode: T): void {
if (this.filterValue.value) { return; }

this.expansionModel.deselect(dataNode);
}

Expand Down
36 changes: 34 additions & 2 deletions packages/cdk/tree/control/flat-tree-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class FlatTreeControl<T> extends BaseTreeControl<T> {
/**
* Gets a list of the data node's subtree of descendent data nodes.
*
* To make this working, the `dataNodes` of the ITreeControl must be flattened tree nodes
* To make this working, the `dataNodes` of the TreeControl must be flattened tree nodes
* with correct levels.
*/
getDescendants(dataNode: T): T[] {
Expand All @@ -38,10 +38,42 @@ export class FlatTreeControl<T> extends BaseTreeControl<T> {
/**
* Expands all data nodes in the tree.
*
* To make this working, the `dataNodes` variable of the ITreeControl must be set to all flattened
* To make this working, the `dataNodes` variable of the TreeControl must be set to all flattened
* data nodes of the tree.
*/
expandAll(): void {
this.expansionModel.select(...this.dataNodes);
}

getParents(node: any, result: T[]): T[] {
if (node.parent) {
result.unshift(node.parent);

return this.getParents(node.parent, result);
} else {
return result;
}
}

compareFunction(name: string, value: string): boolean {
return RegExp(value, 'gi').test(name);
}

filterNodes(value: string): void {
this.filterModel.clear();

// todo нет возможности управлять параметром имени 'node.name'
const filteredNodes = this.dataNodes.filter((node: any) => this.compareFunction(node.name, value));

const filteredNodesWithTheirParents = new Set();
filteredNodes.forEach((filteredNode) => {
this.getParents(filteredNode, []).forEach((node) => filteredNodesWithTheirParents.add(node));

filteredNodesWithTheirParents.add(filteredNode);
});

this.filterModel.select(...Array.from(filteredNodesWithTheirParents));

this.filterValue.next(value);
}
}
2 changes: 1 addition & 1 deletion packages/cdk/tree/control/nested-tree-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class NestedTreeControl<T> extends BaseTreeControl<T> {
/**
* Expands all dataNodes in the tree.
*
* To make this working, the `dataNodes` variable of the ITreeControl must be set to all root level
* To make this working, the `dataNodes` variable of the TreeControl must be set to all root level
* data nodes of the tree.
*/
expandAll(): void {
Expand Down
9 changes: 6 additions & 3 deletions packages/cdk/tree/control/tree-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ import { Observable } from 'rxjs';


/**
* Tree control interface. User can implement ITreeControl to expand/collapse dataNodes in the tree.
* The CDKTree will use this ITreeControl to expand/collapse a node.
* Tree control interface. User can implement TreeControl to expand/collapse dataNodes in the tree.
* The CDKTree will use this TreeControl to expand/collapse a node.
* User can also use it outside the `<cdk-tree>` to control the expansion status of the tree.
*/
export interface ITreeControl<T> {
// tslint:disable-next-line:naming-convention
export interface TreeControl<T> {
/** The saved tree nodes data for `expandAll` action. */
dataNodes: T[];

/** The expansion model */
expansionModel: SelectionModel<T>;

filterModel: SelectionModel<T>;

/** Get depth of a given data node, return the level number. This is for flat tree node. */
getLevel(dataNode: T): number;

Expand Down
34 changes: 17 additions & 17 deletions packages/cdk/tree/tree._spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { map } from 'rxjs/operators';
import { BaseTreeControl } from './control/base-tree-control';
import { FlatTreeControl } from './control/flat-tree-control';
import { NestedTreeControl } from './control/nested-tree-control';
import { ITreeControl } from './control/tree-control';
import { TreeControl } from './control/tree-control';
import { CdkTreeModule } from './index';
import { CdkTree } from './tree';
import { getTreeControlFunctionsMissingError } from './tree-errors';
Expand Down Expand Up @@ -897,7 +897,7 @@ class FakeDataSource extends DataSource<TestData> {
this._dataChange.next(data);
}

constructor(public treeControl: ITreeControl<TestData>) {
constructor(public treeControl: TreeControl<TestData>) {
super();
for (let i = 0; i < 3; i++) {
this.addData();
Expand Down Expand Up @@ -1044,7 +1044,7 @@ class SimpleCdkTreeApp {
getLevel = (node: TestData) => node.level;
isExpandable = (node: TestData) => node.children.length > 0;

treeControl: ITreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);

dataSource: FakeDataSource | null = new FakeDataSource(this.treeControl);

Expand All @@ -1065,7 +1065,7 @@ class SimpleCdkTreeApp {
class NestedCdkTreeApp {
getChildren = (node: TestData) => node.observableChildren;

treeControl: ITreeControl<TestData> = new NestedTreeControl(this.getChildren);
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);

dataSource: FakeDataSource | null = new FakeDataSource(this.treeControl);

Expand All @@ -1091,7 +1091,7 @@ class WhenNodeNestedCdkTreeApp {

getChildren = (node: TestData) => node.observableChildren;

treeControl: ITreeControl<TestData> = new NestedTreeControl(this.getChildren);
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);

dataSource: FakeDataSource | null = new FakeDataSource(this.treeControl);

Expand All @@ -1116,7 +1116,7 @@ class CdkTreeAppWithToggle {
getLevel = (node: TestData) => node.level;
isExpandable = (node: TestData) => node.children.length > 0;

treeControl: ITreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
dataSource: FakeDataSource | null = new FakeDataSource(this.treeControl);

@ViewChild(CdkTree, {static: false}) tree: CdkTree<TestData>;
Expand All @@ -1140,7 +1140,7 @@ class NestedCdkTreeAppWithToggle {

getChildren = (node: TestData) => node.observableChildren;

treeControl: ITreeControl<TestData> = new NestedTreeControl(this.getChildren);
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);
dataSource: FakeDataSource | null = new FakeDataSource(this.treeControl);

@ViewChild(CdkTree, {static: false}) tree: CdkTree<TestData>;
Expand All @@ -1167,7 +1167,7 @@ class WhenNodeCdkTreeApp {
getLevel = (node: TestData) => node.level;
isExpandable = (node: TestData) => node.children.length > 0;

treeControl: ITreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);

dataSource: FakeDataSource | null = new FakeDataSource(this.treeControl);

Expand All @@ -1189,7 +1189,7 @@ class ArrayDataSourceCdkTreeApp {
getLevel = (node: TestData) => node.level;
isExpandable = (node: TestData) => node.children.length > 0;

treeControl: ITreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);

dataSource: FakeDataSource = new FakeDataSource(this.treeControl);

Expand All @@ -1215,7 +1215,7 @@ class ObservableDataSourceCdkTreeApp {
getLevel = (node: TestData) => node.level;
isExpandable = (node: TestData) => node.children.length > 0;

treeControl: ITreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);

dataSource: FakeDataSource = new FakeDataSource(this.treeControl);

Expand All @@ -1240,7 +1240,7 @@ class ArrayDataSourceNestedCdkTreeApp {

getChildren = (node: TestData) => node.observableChildren;

treeControl: ITreeControl<TestData> = new NestedTreeControl(this.getChildren);
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);

dataSource: FakeDataSource = new FakeDataSource(this.treeControl);

Expand All @@ -1265,7 +1265,7 @@ class ObservableDataSourceNestedCdkTreeApp {

getChildren = (node: TestData) => node.observableChildren;

treeControl: ITreeControl<TestData> = new NestedTreeControl(this.getChildren);
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);

dataSource: FakeDataSource = new FakeDataSource(this.treeControl);

Expand All @@ -1291,7 +1291,7 @@ class NestedCdkErrorTreeApp {

isExpandable = (node: TestData) => node.children.length > 0;

treeControl: ITreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);

dataSource: FakeDataSource | null = new FakeDataSource(this.treeControl);

Expand Down Expand Up @@ -1324,7 +1324,7 @@ class FlatCdkErrorTreeApp {

isExpandable = (node: TestData) => node.children.length > 0;

treeControl: ITreeControl<TestData> = new FakeTreeControl();
treeControl: TreeControl<TestData> = new FakeTreeControl();

dataSource: FakeDataSource | null = new FakeDataSource(this.treeControl);

Expand All @@ -1347,7 +1347,7 @@ class DepthNestedCdkTreeApp {

getChildren = (node: TestData) => node.observableChildren;

treeControl: ITreeControl<TestData> = new NestedTreeControl(this.getChildren);
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);

dataSource: FakeDataSource = new FakeDataSource(this.treeControl);

Expand Down Expand Up @@ -1384,7 +1384,7 @@ class CdkTreeAppWithTrackBy {
getLevel = (node: TestData) => node.level;
isExpandable = (node: TestData) => node.children.length > 0;

treeControl: ITreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
dataSource: FakeDataSource = new FakeDataSource(this.treeControl);

@ViewChild(CdkTree, {static: false}) tree: CdkTree<TestData>;
Expand Down Expand Up @@ -1416,7 +1416,7 @@ class NestedCdkTreeAppWithTrackBy {

getChildren = (node: TestData) => node.observableChildren;

treeControl: ITreeControl<TestData> = new NestedTreeControl(this.getChildren);
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);

dataSource: FakeDataSource = new FakeDataSource(this.treeControl);

Expand Down
4 changes: 2 additions & 2 deletions packages/cdk/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { IFocusableOption } from '@ptsecurity/cdk/a11y';
import { BehaviorSubject, Observable, of as observableOf, Subject, Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { ITreeControl } from './control/tree-control';
import { TreeControl } from './control/tree-control';
import { CdkTreeNodeDef, CdkTreeNodeOutletContext } from './node';
import { CdkTreeNodeOutlet } from './outlet';
import {
Expand Down Expand Up @@ -53,7 +53,7 @@ import {
export class CdkTree<T> implements AfterContentChecked, CollectionViewer, OnDestroy, OnInit {

/** The tree controller */
@Input() treeControl: ITreeControl<T>;
@Input() treeControl: TreeControl<T>;

/**
* Tracking function that will be used to check the differences in data changes. Used similarly
Expand Down
23 changes: 10 additions & 13 deletions packages/mosaic-dev/all/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { McToolTipModule } from '@ptsecurity/mosaic/tooltip';
import { McTreeFlatDataSource, McTreeFlattener, McTreeModule } from '@ptsecurity/mosaic/tree';
import { Observable, of as observableOf } from 'rxjs';

import { FileDatabase, FileFlatNode, FileNode } from '../tree/module';
import { buildFileTree, FileFlatNode, FileNode, DATA_OBJECT } from '../tree/module';

// Depending on whether rollup is used, moment needs to be imported differently.
// Since Moment.js doesn't have a default export, we normally need to import using the `* as`
Expand All @@ -57,8 +57,7 @@ const MAX_PERCENT: number = 100;
selector: 'app',
template: require('./template.html'),
styleUrls: ['./styles.scss'],
encapsulation: ViewEncapsulation.None,
providers: [FileDatabase]
encapsulation: ViewEncapsulation.None
})
export class DemoComponent {
checked: boolean[] = [true, true, false];
Expand Down Expand Up @@ -129,21 +128,19 @@ export class DemoComponent {
dataSource: McTreeFlatDataSource<FileNode, FileFlatNode>;
treeFlattener: McTreeFlattener<FileNode, FileFlatNode>;

constructor(private modalService: McModalService, database: FileDatabase) {
constructor(private modalService: McModalService) {
setInterval(() => {
this.percent = (this.percent + STEP) % (MAX_PERCENT + STEP);
}, INTERVAL);

this.treeFlattener = new McTreeFlattener(
this.transformer, this._getLevel, this._isExpandable, this._getChildren
this.transformer, this.getLevel, this.isExpandable, this.getChildren
);

this.treeControl = new FlatTreeControl<FileFlatNode>(this._getLevel, this._isExpandable);
this.treeControl = new FlatTreeControl<FileFlatNode>(this.getLevel, this.isExpandable);
this.dataSource = new McTreeFlatDataSource(this.treeControl, this.treeFlattener);

database.dataChange.subscribe((data) => {
this.dataSource.data = data;
});
this.dataSource.data = buildFileTree(DATA_OBJECT, 0);
}

showConfirm() {
Expand All @@ -170,7 +167,7 @@ export class DemoComponent {
return flatNode;
}

hasChild(_: number, _nodeData: FileFlatNode) { return _nodeData.expandable; }
hasChild(_: number, nodeData: FileFlatNode) { return nodeData.expandable; }

hasNestedChild(_: number, nodeData: FileNode) {
return !(nodeData.type);
Expand All @@ -180,11 +177,11 @@ export class DemoComponent {
clearInterval(this.intervalId);
}

private _getLevel(node: FileFlatNode) { return node.level; }
private getLevel(node: FileFlatNode) { return node.level; }

private _isExpandable(node: FileFlatNode) { return node.expandable; }
private isExpandable(node: FileFlatNode) { return node.expandable; }

private _getChildren = (node: FileNode): Observable<FileNode[]> => {
private getChildren = (node: FileNode): Observable<FileNode[]> => {
return observableOf(node.children);
}

Expand Down
Loading