-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(docs): adding checklist tree example (#UIM-391) (#429)
8x
- Loading branch information
Showing
5 changed files
with
275 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
...s/mosaic-examples/mosaic/tree/tree-multiple-checklist/tree-multiple-checklist-example.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.tree-example-checkbox { | ||
margin-right: 8px; | ||
} |
21 changes: 21 additions & 0 deletions
21
.../mosaic-examples/mosaic/tree/tree-multiple-checklist/tree-multiple-checklist-example.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<mc-tree-selection | ||
[(ngModel)]="modelValue" | ||
[dataSource]="dataSource" | ||
[treeControl]="treeControl"> | ||
|
||
<mc-tree-option *mcTreeNodeDef="let node" mcTreeNodePadding [disabled]="node.name === 'tests'"> | ||
<mc-checkbox class= "tree-example-checkbox" [disabled]="node.name === 'tests'" | ||
[checked]="checklistSelection.isSelected(node)" | ||
(change)="fileSelectionToggle(node)"></mc-checkbox> | ||
<span [innerHTML]="treeControl.getViewValue(node)"></span> | ||
</mc-tree-option> | ||
|
||
<mc-tree-option *mcTreeNodeDef="let node; when: hasChild" mcTreeNodePadding> | ||
<mc-tree-node-toggle [node]="node"></mc-tree-node-toggle> | ||
<mc-checkbox class= "tree-example-checkbox" | ||
[checked]="descendantsAllSelected(node)" | ||
[indeterminate]="descendantsPartiallySelected(node)" | ||
(change)="fileSelectionToggle(node)"></mc-checkbox> | ||
<span [innerHTML]="treeControl.getViewValue(node)"></span> | ||
</mc-tree-option> | ||
</mc-tree-selection> |
241 changes: 241 additions & 0 deletions
241
...es/mosaic-examples/mosaic/tree/tree-multiple-checklist/tree-multiple-checklist-example.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
/* tslint:disable:no-reserved-keywords object-literal-key-quotes */ | ||
import { SelectionModel } from '@angular/cdk/collections'; | ||
import { Component } from '@angular/core'; | ||
import { FlatTreeControl } from '@ptsecurity/cdk/tree'; | ||
import { McTreeFlatDataSource, McTreeFlattener } from '@ptsecurity/mosaic/tree'; | ||
|
||
|
||
export class FileNode { | ||
children: FileNode[]; | ||
name: string; | ||
type: any; | ||
} | ||
|
||
/** Flat node with expandable and level information */ | ||
export class FileFlatNode { | ||
name: string; | ||
type: any; | ||
level: number; | ||
expandable: boolean; | ||
parent: any; | ||
} | ||
|
||
/** | ||
* Build the file structure tree. The `value` is the Json object, or a sub-tree of a Json object. | ||
* The return value is the list of `FileNode`. | ||
*/ | ||
export function buildFileTree(value: any, level: number): FileNode[] { | ||
const data: any[] = []; | ||
|
||
for (const k of Object.keys(value)) { | ||
const v = value[k]; | ||
const node = new FileNode(); | ||
|
||
node.name = `${k}`; | ||
if (v === null || v === undefined) { | ||
// no action | ||
} else if (typeof v === 'object') { | ||
node.children = buildFileTree(v, level + 1); | ||
} else { | ||
node.type = v; | ||
} | ||
|
||
data.push(node); | ||
} | ||
|
||
return data; | ||
} | ||
|
||
export const DATA_OBJECT = { | ||
docs: 'app', | ||
src: { | ||
cdk: { | ||
a11ly: { | ||
'aria-describer': { | ||
'aria-describer': 'ts', | ||
'aria-describer.spec': 'ts', | ||
'aria-reference': 'ts', | ||
'aria-reference.spec': 'ts' | ||
}, | ||
'focus-monitor': { | ||
'focus-monitor': 'ts', | ||
'focus-monitor.spec': 'ts' | ||
} | ||
} | ||
}, | ||
documentation: { | ||
source: '', | ||
tools: '' | ||
}, | ||
mosaic: { | ||
autocomplete: '', | ||
button: '', | ||
'button-toggle': '', | ||
index: 'ts', | ||
package: 'json', | ||
version: 'ts' | ||
}, | ||
'mosaic-dev': { | ||
alert: '', | ||
badge: '' | ||
}, | ||
'mosaic-examples': '', | ||
'mosaic-moment-adapter': '', | ||
README: 'md', | ||
'tsconfig.build': 'json', | ||
wallabyTest: 'ts' | ||
}, | ||
scripts: { | ||
deploy: { | ||
'cleanup-preview': 'ts', | ||
'publish-artifacts': 'sh', | ||
'publish-docs': 'sh', | ||
'publish-docs-preview': 'ts' | ||
}, | ||
'tsconfig.deploy': 'json' | ||
}, | ||
tests: '' | ||
}; | ||
|
||
/** | ||
* @title Checklist tree | ||
*/ | ||
@Component({ | ||
selector: 'tree-multiple-checklist-example', | ||
templateUrl: 'tree-multiple-checklist-example.html', | ||
styleUrls: ['tree-multiple-checklist-example.css'] | ||
}) | ||
export class TreeMultipleChecklistExample { | ||
treeControl: FlatTreeControl<FileFlatNode>; | ||
treeFlattener: McTreeFlattener<FileNode, FileFlatNode>; | ||
|
||
dataSource: McTreeFlatDataSource<FileNode, FileFlatNode>; | ||
|
||
modelValue: any = []; | ||
|
||
/** The selection for checklist */ | ||
checklistSelection = new SelectionModel<FileFlatNode>(true /* multiple */); | ||
|
||
constructor() { | ||
this.treeFlattener = new McTreeFlattener( | ||
this.transformer, this.getLevel, this.isExpandable, this.getChildren | ||
); | ||
|
||
this.treeControl = new FlatTreeControl<FileFlatNode>( | ||
this.getLevel, this.isExpandable, this.getValue, this.getViewValue | ||
); | ||
this.dataSource = new McTreeFlatDataSource(this.treeControl, this.treeFlattener); | ||
|
||
this.dataSource.data = buildFileTree(DATA_OBJECT, 0); | ||
} | ||
|
||
hasChild(_: number, nodeData: FileFlatNode) { return nodeData.expandable; } | ||
|
||
/** Whether all the descendants of the node are selected. */ | ||
descendantsAllSelected(node: FileFlatNode): boolean { | ||
const descendants = this.treeControl.getDescendants(node); | ||
|
||
return descendants.every((child) => this.checklistSelection.isSelected(child)); | ||
} | ||
|
||
/** Whether part of the descendants are selected */ | ||
descendantsPartiallySelected(node: FileFlatNode): boolean { | ||
const descendants = this.treeControl.getDescendants(node); | ||
const result = descendants.some((child) => this.checklistSelection.isSelected(child)); | ||
|
||
return result && !this.descendantsAllSelected(node); | ||
} | ||
|
||
/** Toggle the to-do item selection. Select/deselect all the descendants node */ | ||
fileSelectionToggle(node: FileFlatNode): void { | ||
this.checklistSelection.toggle(node); | ||
const descendants = this.treeControl.getDescendants(node); | ||
this.checklistSelection.isSelected(node) | ||
? this.checklistSelection.select(...descendants) | ||
: this.checklistSelection.deselect(...descendants); | ||
|
||
// Force update for the parent | ||
descendants.every((child) => | ||
this.checklistSelection.isSelected(child) | ||
); | ||
this.checkAllParentsSelection(node); | ||
} | ||
|
||
/* Checks all the parents when a leaf node is selected/unselected */ | ||
checkAllParentsSelection(node: FileFlatNode): void { | ||
let parent: FileFlatNode | null = this.getParentNode(node); | ||
while (parent) { | ||
this.checkRootNodeSelection(parent); | ||
parent = this.getParentNode(parent); | ||
} | ||
} | ||
|
||
/** Check root node checked state and change it accordingly */ | ||
checkRootNodeSelection(node: FileFlatNode): void { | ||
const nodeSelected = this.checklistSelection.isSelected(node); | ||
const descendants = this.treeControl.getDescendants(node); | ||
const descAllSelected = descendants.every((child) => | ||
this.checklistSelection.isSelected(child) | ||
); | ||
if (nodeSelected && !descAllSelected) { | ||
this.checklistSelection.deselect(node); | ||
} else if (!nodeSelected && descAllSelected) { | ||
this.checklistSelection.select(node); | ||
} | ||
} | ||
|
||
/* Get the parent node of a node */ | ||
getParentNode(node: FileFlatNode): FileFlatNode | null { | ||
const currentLevel = this.getLevel(node); | ||
|
||
if (currentLevel < 1) { | ||
return null; | ||
} | ||
|
||
const startIndex = this.treeControl.dataNodes.indexOf(node) - 1; | ||
|
||
for (let i = startIndex; i >= 0; i--) { | ||
const currentNode = this.treeControl.dataNodes[i]; | ||
|
||
if (this.getLevel(currentNode) < currentLevel) { | ||
return currentNode; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private transformer = (node: FileNode, level: number, parent: any) => { | ||
const flatNode = new FileFlatNode(); | ||
|
||
flatNode.name = node.name; | ||
flatNode.parent = parent; | ||
flatNode.type = node.type; | ||
flatNode.level = level; | ||
flatNode.expandable = !!node.children; | ||
|
||
return flatNode; | ||
} | ||
|
||
private getLevel = (node: FileFlatNode) => { | ||
return node.level; | ||
} | ||
|
||
private isExpandable = (node: FileFlatNode) => { | ||
return node.expandable; | ||
} | ||
|
||
private getChildren = (node: FileNode): FileNode[] => { | ||
return node.children; | ||
} | ||
|
||
private getValue = (node: FileNode): string => { | ||
return node.name; | ||
} | ||
|
||
private getViewValue = (node: FileNode): string => { | ||
const nodeType = node.type ? `.${node.type}` : ''; | ||
|
||
return `${node.name}${nodeType}`; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters