Skip to content

Commit 11b6d30

Browse files
author
Georgii Rychko
committed
Merge branch 'develop' of bitbucket.org:rychkog/ng2-tree into develop
# Conflicts: # .gitignore
2 parents 8fb883a + 15597c1 commit 11b6d30

14 files changed

Lines changed: 391 additions & 175 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ node_modules/
33
build/
44
.vscode/
55
npm-debug.log
6+
typings/
7+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {Directive, ElementRef, Input, OnInit, Output, EventEmitter, HostListener} from 'angular2/core';
2+
import {Ng2TreeService} from './ng2-tree.service';
3+
4+
@Directive({
5+
selector: '[editable]'
6+
})
7+
export class EditableNodeDirective implements OnInit {
8+
@Input()
9+
nodeValue: string;
10+
11+
@Output()
12+
valueChanged: EventEmitter<any> = new EventEmitter(false);
13+
14+
private element: any;
15+
private treeService: Ng2TreeService;
16+
17+
constructor(elementRef: ElementRef, treeService: Ng2TreeService) {
18+
this.element = elementRef;
19+
this.treeService = treeService;
20+
}
21+
22+
ngOnInit(): void {
23+
this.element.nativeElement.focus();
24+
this.element.nativeElement.value = this.nodeValue;
25+
}
26+
27+
@HostListener('keyup', ['$event', '$event.target.value'])
28+
private editCompleted($event: any, newValue: any) {
29+
//13 - enter
30+
//27 - esc
31+
if ($event.keyCode === 13) {
32+
// http://stackoverflow.com/questions/35515254/what-is-a-dehydrated-detector-and-how-am-i-using-one-here
33+
setTimeout(() => this.valueChanged.emit({value: newValue}), 1);
34+
}
35+
}
36+
37+
@HostListener('blur', ['$event', '$event.target.value'])
38+
private editCompletedByMouse($event: any, newValue: any) {
39+
//13 - enter
40+
//27 - esc
41+
this.valueChanged.emit({value: newValue});
42+
}
43+
}

components/ng2-tree.component.ts

Lines changed: 116 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,123 @@
1-
import {Component} from 'angular2/core';
1+
import {Input, Component, OnInit} from 'angular2/core';
2+
import {CORE_DIRECTIVES} from 'angular2/common';
3+
import {Ng2TreeService} from './ng2-tree.service';
4+
import {EditableNodeDirective} from './editable-node.directive.ts';
25

36
@Component({
47
selector: 'ng2-tree',
58
template: `
6-
<pre>
7-
[-] A
8-
|
9-
+-----B
10-
|
11-
+-----C
12-
|
13-
+-----[-] D
14-
| |
15-
| +-----X
16-
| |
17-
| +-----Y
18-
|
19-
[+]
20-
</pre>
21-
`
9+
<ul class="tree" (keyup)="cancelActions($event)">
10+
<li>
11+
<div (mouseup)="showMenu($event)">
12+
<span class="folding" (click)="switchFolding($event, tree)" [ngClass]="foldingType(tree)"></span>
13+
<span class="node-value" *ngIf="!edit">{{tree.value}}</span>
14+
<input type="text" class="node-value" editable [nodeValue]="tree.value" (valueChanged)="applyNewValue($event, tree)" *ngIf="edit"/>
15+
</div>
16+
<div class="node-menu" *ngIf="isMenuVisible">
17+
<ul class="node-menu-content">
18+
<li (click)="rename($event, tree)">Rename node</li>
19+
<li>Add node</li>
20+
<li>Remove node</li>
21+
</ul>
22+
</div>
23+
<ng2-tree *ngFor="#child of tree.children" [tree]="child"></ng2-tree>
24+
</li>
25+
</ul>
26+
`,
27+
directives: [EditableNodeDirective, Ng2Tree, CORE_DIRECTIVES]
2228
})
23-
export class Ng2Tree {
29+
export class Ng2Tree implements OnInit {
30+
private static COMPONENT_TAG_NAME: string = 'NG2-TREE';
31+
private static FOLDING_NODE_EXPANDED: string = 'node-expanded';
32+
private static FOLDING_NODE_COLLAPSED: string = 'node-collapsed';
33+
private static FOLDING_NODE_LEAF: string = 'node-leaf';
2434

35+
@Input()
36+
private tree: any;
37+
38+
private treeService: Ng2TreeService;
39+
private isMenuVisible: boolean = false;
40+
private edit: boolean = false;
41+
42+
constructor(treeService: Ng2TreeService) {
43+
this.treeService = treeService;
44+
}
45+
46+
private switchFolding($event: any, tree: any): void {
47+
console.log('fold');
48+
this.handleFoldingType($event.target.parentNode.parentNode, tree);
49+
}
50+
51+
private foldingType(node: any): any {
52+
if (node.foldingType) {
53+
return node.foldingType;
54+
}
55+
56+
if (node.children) {
57+
node.foldingType = Ng2Tree.FOLDING_NODE_EXPANDED;
58+
} else {
59+
node.foldingType = Ng2Tree.FOLDING_NODE_LEAF;
60+
}
61+
62+
return node.foldingType;
63+
}
64+
65+
private nextFoldingType(node: any): string {
66+
if (node.foldingType === Ng2Tree.FOLDING_NODE_EXPANDED) {
67+
return Ng2Tree.FOLDING_NODE_COLLAPSED;
68+
}
69+
70+
return Ng2Tree.FOLDING_NODE_EXPANDED;
71+
}
72+
73+
private handleFoldingType(parent: any, node: any) {
74+
if (node.foldingType === Ng2Tree.FOLDING_NODE_LEAF) {
75+
return;
76+
}
77+
78+
let display = 'block';
79+
if (node.foldingType === Ng2Tree.FOLDING_NODE_EXPANDED) {
80+
display = 'none';
81+
}
82+
83+
node.foldingType = this.nextFoldingType(node);
84+
for (let element of parent.childNodes) {
85+
if (element.nodeName === Ng2Tree.COMPONENT_TAG_NAME) {
86+
element.style.display = display;
87+
}
88+
}
89+
}
90+
91+
private rename($event: any, node: any) {
92+
if ($event.which === 1) {
93+
this.edit = true;
94+
this.isMenuVisible = false;
95+
}
96+
}
97+
98+
private showMenu($event: any): void {
99+
if ($event.which === 3) {
100+
this.isMenuVisible = !this.isMenuVisible;
101+
this.treeService.emitMenuEvent({sender: this, action: 'close'})
102+
}
103+
$event.preventDefault();
104+
}
105+
106+
private cancelActions($event: any): void {
107+
108+
}
109+
110+
private applyNewValue($event: any, node: any): void {
111+
node.value = $event.value;
112+
this.edit = false;
113+
}
114+
115+
ngOnInit(): void {
116+
this.treeService.menuEventStream()
117+
.subscribe(menuEvent => {
118+
if (menuEvent.sender !== this && menuEvent.action === 'close') {
119+
this.isMenuVisible = false;
120+
}
121+
})
122+
}
25123
}

components/ng2-tree.service.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {Injectable, EventEmitter} from 'angular2/core';
2+
import {Observable} from 'rxjs/Observable';
3+
4+
@Injectable()
5+
export class Ng2TreeService {
6+
private menuEvents$:EventEmitter<any> = new EventEmitter();
7+
private cancelEvents$:EventEmitter<any> = new EventEmitter();
8+
9+
menuEventStream(): Observable<any> {
10+
return this.menuEvents$;
11+
}
12+
13+
emitMenuEvent(event: any): void {
14+
this.menuEvents$.emit(event);
15+
}
16+
17+
cancelEventStream(): Observable<any> {
18+
return this.cancelEvents$;
19+
}
20+
21+
emitCancelEvent(event: any): void {
22+
this.cancelEvents$.emit(event);
23+
}
24+
}

demo/app.ts

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,65 @@
33
import {bootstrap} from 'angular2/platform/browser';
44
import {Component} from 'angular2/core';
55
import {Ng2Tree} from '../ng2-tree';
6+
import {Ng2TreeService} from '../components/ng2-tree.service';
7+
8+
require('./styles.styl');
69

710
@Component({
8-
selector: 'app',
9-
template: `
10-
<h1>{{msg}}</h1>
11-
<ng2-tree></ng2-tree>
12-
`,
13-
directives: [Ng2Tree]
11+
selector: 'app',
12+
template: `<ng2-tree [tree]="tree"></ng2-tree>`,
13+
directives: [Ng2Tree]
1414
})
1515
class App {
16-
public msg:string = 'Hello, World!';
16+
private tree: any = {
17+
value: 'A',
18+
children: [
19+
{
20+
value: 'B',
21+
},
22+
{
23+
value: 'C',
24+
},
25+
{
26+
value: 'D',
27+
children: [
28+
{
29+
value: 'X',
30+
children: [
31+
{
32+
value: 'X',
33+
},
34+
{
35+
value: 'Y',
36+
}
37+
]
38+
},
39+
{
40+
value: 'Y',
41+
children: [
42+
{
43+
value: 'X',
44+
},
45+
{
46+
value: 'Y',
47+
children: [
48+
{
49+
value: 'X',
50+
},
51+
{
52+
value: 'Y',
53+
}
54+
]
55+
}
56+
]
57+
}
58+
]
59+
},
60+
{
61+
value: 'W'
62+
}
63+
]
64+
};
1765
}
1866

19-
bootstrap(App);
67+
bootstrap(App, [Ng2TreeService]);

demo/colors.styl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
folding-color = orange
2+
node-value-color = green
3+
node-menu-active-item = orange
4+
node-menu-background = #e1e1e1

demo/index.ejs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title><%= htmlWebpackPlugin.options.title %></title>
6+
</head>
7+
<body>
8+
<app>Loading...</app>
9+
10+
</body>
11+
</html>

0 commit comments

Comments
 (0)