Skip to content

Commit 47d98b9

Browse files
author
Georgii Rychko
authored
Merge pull request #171 from valor-software/develop
sync master with develop
2 parents be42398 + d776886 commit 47d98b9

19 files changed

+300
-38
lines changed

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
- [isCollapsed - check whether a node is collapsed](#iscollapsed---check-whether-a-node-is-collapsed)
3333
- [expand - expands a node](#expand---expands-a-node)
3434
- [isExpanded - checks whether a node is expanded](#isexpanded---checks-whether-a-node-is-expanded)
35+
- [toTreeModel - converts a tree to a TreeModel instance](#totreemodel---converts-a-tree-to-a-treemodel-instance)
3536
- [rename - renames a node (changes its value underneath)](#rename---renames-a-node-changes-its-value-underneath)
3637
- [startRenaming - changes the node template so that text input appears and lets a user type a new name](#startrenaming---changes-the-node-template-so-that-text-input-appears-and-lets-a-user-type-a-new-name)
3738
- [remove - removes a node from the tree](#remove---removes-a-node-from-the-tree)
@@ -334,6 +335,12 @@ Here is an example of its usage:
334335
'node': '<i class="fa fa-folder-o fa-lg"></i>',
335336
'leaf': '<i class="fa fa-file-o fa-lg"></i>',
336337
'leftMenu': '<i class="fa fa-navicon fa-lg"></i>'
338+
},
339+
'menuItems': [
340+
{ action: NodeMenuItemAction.Custom, name: 'Foo', cssClass: 'fa fa-arrow-right' },
341+
{ action: NodeMenuItemAction.Custom, name: 'Bar', cssClass: 'fa fa-arrow-right' },
342+
{ action: NodeMenuItemAction.Custom, name: 'Baz', cssClass: 'fa fa-arrow-right'}
343+
]
337344
}
338345
},
339346
children: [
@@ -357,6 +364,7 @@ Here is an example of its usage:
357364
* `node` - String - It specifies a html template which will be included to the left of the node's value.
358365
* `leaf` - String - It specifies a html template which will be included to the left of the leaf's value.
359366
* `leftMenu` - String - It specifies a html template to the right of the node's value. This template becomes clickable and shows a menu on node's click.
367+
* `menuItems` - here you can specify your custom menu items. You should feed an array of NodeMenuItem instances to this setting. Once done - setup a subscription to `MenuItemSelectedEvent`s by listening to `(menuItemSelected)="onMenuItemSelected($event)"` on the tree.
360368

361369
All options that are defined on a `parent` are automatically applied to children. If you want you can override them by `settings` of the child node.
362370

@@ -450,7 +458,7 @@ You can subscribe to `NodeCreatedEvent` by attaching listener to `(nodeCreated)`
450458
`NodeCreatedEvent` has a `node` property of type `Tree`, which contains a created node and a `controller` property, which will give you access to node's controller.
451459

452460
```typescript
453-
{node: <Tree>{...}, controller: <TreeController>{...}}
461+
{node: <Tree>{...}}
454462
```
455463

456464
#### NodeRenamedEvent
@@ -531,7 +539,11 @@ Relevant for loading children via ngrx (or any redux-inspired library).
531539
```
532540

533541
## :gun: Controller
534-
First of all you should know how to get a controller of a particular node. You can get a controller of a node only if you set an id property of a node. For example, your tree structure should look like:
542+
First of all you should know how to get a controller of a particular node. You can get a controller of a node only if you set an id property of a node.
543+
544+
> TIP: Ids for nodes created via the context menu or using a TreeController instance get populated automatically unless nodes had ids before there were added to the tree
545+
546+
For example, your tree structure should look like:
535547

536548
```typescript
537549
public tree: TreeModel = {
@@ -655,6 +667,14 @@ This method expands the node in case it can be expanded. On successful expanding
655667
oopNodeController.isExpanded();
656668
```
657669

670+
#### toTreeModel - converts a tree to a TreeModel instance
671+
672+
Actually controller makes and returns a clone of tree's underlying model
673+
674+
```typescript
675+
oopNodeController.toTreeModel();
676+
```
677+
658678
This method returns true if the node is expanded and false otherwise.
659679

660680
#### rename - renames a node (changes its value underneath)

index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import {
99

1010
import { Tree } from './src/tree';
1111

12+
import { NodeMenuItemAction } from './src/menu/menu.events';
13+
import { NodeMenuItem } from './src/menu/node-menu.component';
14+
1215
import {
1316
NodeEvent,
1417
NodeCreatedEvent,
@@ -18,6 +21,7 @@ import {
1821
NodeSelectedEvent,
1922
NodeExpandedEvent,
2023
NodeCollapsedEvent,
24+
MenuItemSelectedEvent,
2125
NodeDestructiveEvent
2226
} from './src/tree.events';
2327

@@ -41,5 +45,9 @@ export {
4145
NodeCollapsedEvent,
4246
NodeDestructiveEvent,
4347
TreeComponent,
44-
TreeModule
48+
TreeModule,
49+
NodeMenuItemAction,
50+
NodeMenuItem,
51+
ChildrenLoadingFunction,
52+
MenuItemSelectedEvent
4553
};

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"@types/jasmine": "2.8.2",
6464
"@types/node": "8.0.53",
6565
"alertifyjs": "1.10.0",
66-
"codelyzer": "3.0.1",
66+
"codelyzer": "4.0.1",
6767
"conventional-changelog": "1.1.7",
6868
"conventional-changelog-cli": "1.3.5",
6969
"conventional-github-releaser": "2.0.0",
@@ -88,9 +88,10 @@
8888
"shelljs": "0.7.8",
8989
"systemjs-builder": "0.16.12",
9090
"ts-node": "3.3.0",
91-
"tslint": "5.4.3",
92-
"tslint-config-valorsoft": "2.0.1",
91+
"tslint": "5.8.0",
92+
"tslint-config-valorsoft": "2.1.1",
9393
"typescript": "2.4.2",
94+
"uuid": "3.1.0",
9495
"webpack": "3.8.1",
9596
"zone.js": "0.8.18"
9697
}

src/demo/app/app.component.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { Component, OnInit, ViewChild } from '@angular/core';
2-
import { NodeEvent, TreeModel, RenamableNode, Ng2TreeSettings } from '../../../index';
2+
import { Ng2TreeSettings, NodeEvent, RenamableNode, TreeModel } from '../../../index';
3+
import { NodeMenuItemAction } from '../../menu/menu.events';
4+
import { MenuItemSelectedEvent } from '../../tree.events';
35

46
declare const alertify: any;
57

@@ -12,6 +14,7 @@ declare const alertify: any;
1214
<div class="tree-content">
1315
<tree #treeFonts
1416
[tree]="fonts"
17+
(menuItemSelected)="onMenuItemSelected($event)"
1518
(nodeRemoved)="onNodeRemoved($event)"
1619
(nodeRenamed)="onNodeRenamed($event)"
1720
(nodeSelected)="onNodeSelected($event)"
@@ -202,8 +205,15 @@ export class AppComponent implements OnInit {
202205
]
203206
},
204207
{
205-
value: 'Sans-serif',
208+
value: 'Sans-serif (Right click me - I have a custom menu)',
206209
id: 11,
210+
settings: {
211+
menuItems: [
212+
{ action: NodeMenuItemAction.Custom, name: 'Foo', cssClass: 'fa fa-arrow-right' },
213+
{ action: NodeMenuItemAction.Custom, name: 'Bar', cssClass: 'fa fa-arrow-right' },
214+
{ action: NodeMenuItemAction.Custom, name: 'Baz', cssClass: 'fa fa-arrow-right'}
215+
]
216+
},
207217
children: [
208218
{value: 'Arial', id: 12},
209219
{value: 'Century Gothic', id: 13},
@@ -567,6 +577,10 @@ export class AppComponent implements OnInit {
567577
AppComponent.logEvent(e, 'Selected');
568578
}
569579

580+
public onMenuItemSelected(e: MenuItemSelectedEvent) {
581+
AppComponent.logEvent(e, `You selected ${e.selectedItem} menu item`);
582+
}
583+
570584
public onNodeExpanded(e: NodeEvent): void {
571585
AppComponent.logEvent(e, 'Expanded');
572586
}

src/menu/menu.events.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ export enum NodeMenuItemAction {
22
NewFolder,
33
NewTag,
44
Rename,
5-
Remove
5+
Remove,
6+
Custom
67
}
78

89
export enum NodeMenuAction {
@@ -16,4 +17,5 @@ export interface NodeMenuEvent {
1617

1718
export interface NodeMenuItemSelectedEvent {
1819
nodeMenuItemAction: NodeMenuItemAction;
20+
nodeMenuItemSelected?: string;
1921
}

src/menu/node-menu.component.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
Component, EventEmitter, Output, Inject, OnDestroy, OnInit, ViewChild, Renderer2
2+
Component, EventEmitter, Output, Input, Inject, OnDestroy, OnInit, ViewChild, Renderer2
33
} from '@angular/core';
44
import { NodeMenuService } from './node-menu.service';
55
import { NodeMenuItemSelectedEvent, NodeMenuItemAction, NodeMenuAction } from './menu.events';
@@ -23,6 +23,9 @@ export class NodeMenuComponent implements OnInit, OnDestroy {
2323
@Output()
2424
public menuItemSelected: EventEmitter<NodeMenuItemSelectedEvent> = new EventEmitter<NodeMenuItemSelectedEvent>();
2525

26+
@Input()
27+
public menuItems: NodeMenuItem[];
28+
2629
@ViewChild('menuContainer') public menuContainer: any;
2730

2831
public availableMenuItems: NodeMenuItem[] = [
@@ -55,6 +58,7 @@ export class NodeMenuComponent implements OnInit, OnDestroy {
5558
}
5659

5760
public ngOnInit(): void {
61+
this.availableMenuItems = this.menuItems || this.availableMenuItems;
5862
this.disposersForGlobalListeners.push(this.renderer.listen('document', 'keyup', this.closeMenu.bind(this)));
5963
this.disposersForGlobalListeners.push(this.renderer.listen('document', 'mousedown', this.closeMenu.bind(this)));
6064
}
@@ -65,7 +69,11 @@ export class NodeMenuComponent implements OnInit, OnDestroy {
6569

6670
public onMenuItemSelected(e: MouseEvent, selectedMenuItem: NodeMenuItem): void {
6771
if (isLeftButtonClicked(e)) {
68-
this.menuItemSelected.emit({nodeMenuItemAction: selectedMenuItem.action});
72+
this.menuItemSelected.emit({
73+
nodeMenuItemAction: selectedMenuItem.action,
74+
nodeMenuItemSelected: selectedMenuItem.name
75+
});
76+
6977
this.nodeMenuService.fireMenuEvent(e.target as HTMLElement, NodeMenuAction.Close);
7078
}
7179
}
@@ -84,5 +92,5 @@ export class NodeMenuComponent implements OnInit, OnDestroy {
8492
export interface NodeMenuItem {
8593
name: string;
8694
action: NodeMenuItemAction;
87-
cssClass: string;
95+
cssClass?: string;
8896
}

src/tree-controller.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ export class TreeController {
4444
return this.tree.isNodeCollapsed();
4545
}
4646

47+
public toTreeModel(): TreeModel {
48+
return this.tree.toTreeModel();
49+
}
50+
4751
public rename(newValue: string): void {
4852
this.tree.markAsBeingRenamed();
4953
this.component.applyNewValue({ type: 'keyup', value: newValue });

src/tree-internal.component.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import { Component, ElementRef, TemplateRef, Inject, Input, OnDestroy, OnInit, OnChanges, SimpleChanges } from '@angular/core';
1+
import {
2+
Component,
3+
ElementRef,
4+
Input,
5+
OnChanges,
6+
OnDestroy,
7+
OnInit,
8+
SimpleChanges,
9+
TemplateRef
10+
} from '@angular/core';
211
import * as TreeTypes from './tree.types';
312
import { Tree } from './tree';
413
import { TreeController } from './tree-controller';
@@ -41,13 +50,19 @@ import { get } from './utils/fn.utils';
4150
4251
<div class="node-left-menu" *ngIf="tree.hasLeftMenu()" (click)="showLeftMenu($event)" [innerHTML]="tree.leftMenuTemplate">
4352
</div>
44-
<node-menu *ngIf="tree.hasLeftMenu() && isLeftMenuVisible"
53+
<node-menu *ngIf="tree.hasLeftMenu() && isLeftMenuVisible && !hasCustomMenu()"
4554
(menuItemSelected)="onMenuItemSelected($event)">
4655
</node-menu>
4756
</div>
4857
49-
<node-menu *ngIf="isRightMenuVisible" (menuItemSelected)="onMenuItemSelected($event)"></node-menu>
58+
<node-menu *ngIf="isRightMenuVisible && !hasCustomMenu()"
59+
(menuItemSelected)="onMenuItemSelected($event)">
60+
</node-menu>
5061
62+
<node-menu *ngIf="hasCustomMenu() && (isRightMenuVisible || isLeftMenuVisible)"
63+
[menuItems]="tree.menuItems"
64+
(menuItemSelected)="onMenuItemSelected($event)">
65+
</node-menu>
5166
<ng-template [ngIf]="tree.isNodeExpanded()">
5267
<tree-internal *ngFor="let child of tree.childrenAsync | async" [tree]="child" [template]="template"></tree-internal>
5368
</ng-template>
@@ -72,9 +87,9 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy {
7287

7388
private subscriptions: Subscription[] = [];
7489

75-
public constructor(@Inject(NodeMenuService) private nodeMenuService: NodeMenuService,
76-
@Inject(TreeService) public treeService: TreeService,
77-
@Inject(ElementRef) public element: ElementRef) {
90+
public constructor(private nodeMenuService: NodeMenuService,
91+
public treeService: TreeService,
92+
public element: ElementRef) {
7893
}
7994

8095
public ngOnInit(): void {
@@ -84,7 +99,6 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy {
8499
}
85100

86101
this.settings = this.settings || { rootIsVisible: true };
87-
88102
this.subscriptions.push(this.nodeMenuService.hideMenuStream(this.element)
89103
.subscribe(() => {
90104
this.isRightMenuVisible = false;
@@ -182,6 +196,9 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy {
182196
case NodeMenuItemAction.Remove:
183197
this.onRemoveSelected();
184198
break;
199+
case NodeMenuItemAction.Custom:
200+
this.treeService.fireMenuItemSelected(this.tree, e.nodeMenuItemSelected);
201+
break;
185202
default:
186203
throw new Error(`Chosen menu item doesn't exist`);
187204
}
@@ -235,4 +252,8 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy {
235252
public isRootHidden(): boolean {
236253
return this.tree.isRoot() && !this.settings.rootIsVisible;
237254
}
255+
256+
public hasCustomMenu(): boolean {
257+
return this.tree.hasCustomMenu();
258+
}
238259
}

src/tree.component.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
} from '@angular/core';
55
import { TreeService } from './tree.service';
66
import * as TreeTypes from './tree.types';
7-
import { NodeEvent } from './tree.events';
7+
import { NodeEvent, MenuItemSelectedEvent } from './tree.events';
88
import { Tree } from './tree';
99
import { TreeController } from './tree-controller';
1010
import { Subscription } from 'rxjs/Subscription';
@@ -46,8 +46,11 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy {
4646
@Output()
4747
public nodeCollapsed: EventEmitter<any> = new EventEmitter();
4848

49-
@Output()
50-
public loadNextLevel: EventEmitter<any> = new EventEmitter();
49+
@Output()
50+
public menuItemSelected: EventEmitter<any> = new EventEmitter();
51+
52+
@Output()
53+
public loadNextLevel: EventEmitter<any> = new EventEmitter();
5154

5255
public tree: Tree;
5356
@ViewChild('rootComponent') public rootComponent;
@@ -96,6 +99,10 @@ public loadNextLevel: EventEmitter<any> = new EventEmitter();
9699
this.nodeCollapsed.emit(e);
97100
}));
98101

102+
this.subscriptions.push(this.treeService.menuItemSelected$.subscribe((e: MenuItemSelectedEvent) => {
103+
this.menuItemSelected.emit(e);
104+
}));
105+
99106
this.subscriptions.push(this.treeService.loadNextLevel$.subscribe((e: NodeEvent) => {
100107
this.loadNextLevel.emit(e);
101108
}));

src/tree.events.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ export class NodeCollapsedEvent extends NodeEvent {
5555
}
5656
}
5757

58+
export class MenuItemSelectedEvent extends NodeEvent {
59+
public constructor(node: Tree, public selectedItem: string) {
60+
super(node);
61+
}
62+
}
63+
5864
export class LoadNextLevelEvent extends NodeEvent {
5965
public constructor(node: Tree) {
6066
super(node);

0 commit comments

Comments
 (0)