Skip to content

Commit 4dfbdee

Browse files
committed
* Added index to node content template
* Added nodeClass option
1 parent 913e762 commit 4dfbdee

13 files changed

+186
-118
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
<a name="2.6.0"></a>
2+
# 2.6.0 (2016-01-01)
3+
* Added index to node content template
4+
* Added nodeClass option
5+
16
<a name="2.5.1"></a>
27
# 2.5.1 (2016-12-21)
38
* Updated PeerDeps to allow for Angular 2.3

lib/angular2-tree-component.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,26 @@ import { TreeNodeComponent } from './components/tree-node.component';
1414
import { TreeNodeContent } from './components/tree-node-content.component';
1515
import { TreeNodeContent as DeprecatedTreeNodeContent } from './components/deprecated-tree-node-content.component';
1616
import { TreeNodeDropSlot } from './components/tree-node-drop-slot.component';
17+
import { TreeNodeExpanderComponent } from './components/tree-node-expander.component';
18+
import { TreeNodeChildrenComponent } from './components/tree-node-children.component';
1719
import { TreeDropDirective } from './directives/tree-drop.directive';
1820
import { TreeDragDirective } from './directives/tree-drag.directive';
1921
import { AdHocComponentFactoryCreator } from './components/adhoc-component-factory.service';
2022

2123
import './polyfills';
2224
import { deprecated } from './deprecated';
2325

26+
const exportedDirectives = [
27+
TreeComponent,
28+
TreeNodeComponent,
29+
TreeNodeContent,
30+
TreeDropDirective,
31+
TreeDragDirective,
32+
TreeNodeExpanderComponent,
33+
TreeNodeChildrenComponent,
34+
TreeNodeDropSlot
35+
];
36+
2437
export {
2538
TreeModel,
2639
TreeNode,
@@ -36,23 +49,18 @@ export {
3649
TreeNodeContent,
3750
TreeDropDirective,
3851
TreeDragDirective,
52+
TreeNodeExpanderComponent,
53+
TreeNodeChildrenComponent,
3954
TreeNodeDropSlot
4055
};
4156

4257
@NgModule({
4358
declarations: [
4459
LoadingComponent,
45-
TreeComponent,
46-
TreeNodeComponent,
47-
TreeNodeDropSlot,
48-
TreeNodeContent,
49-
TreeDropDirective,
50-
TreeDragDirective
60+
...exportedDirectives
5161
],
5262
exports: [
53-
TreeComponent,
54-
TreeDropDirective,
55-
TreeDragDirective
63+
...exportedDirectives
5664
],
5765
imports: [
5866
CommonModule,

lib/components/loading.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { TreeModel } from '../models/tree.model';
33

44
@Component({
55
selector: 'LoadingComponent',
6-
template: `<span *ngIf="!loadingTemplate">loading...</span>
7-
<template [ngTemplateOutlet]="loadingTemplate"></template>`,
6+
template: `<span *ngIf="!template">loading...</span>
7+
<template [ngTemplateOutlet]="template"></template>`,
88
})
99
export class LoadingComponent {
10-
@Input() loadingTemplate: TemplateRef<any>;
10+
@Input() template: TemplateRef<any>;
1111
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Component, Input, ViewEncapsulation } from '@angular/core';
2+
import { TreeNode } from '../models/tree-node.model';
3+
4+
@Component({
5+
selector: 'TreeNodeChildren',
6+
encapsulation: ViewEncapsulation.None,
7+
styles: [
8+
'.tree-children.tree-children-no-padding { padding-left: 0 }',
9+
'.tree-children { padding-left: 20px }'
10+
],
11+
template: `
12+
<div [class.tree-children]="true"
13+
[class.tree-children-no-padding]="node.options.levelPadding"
14+
*ngIf="node.isExpanded">
15+
<div *ngIf="node.children">
16+
<TreeNode
17+
*ngFor="let node of node.children; let i = index"
18+
[node]="node"
19+
[index]="i"
20+
[templates]="templates">
21+
</TreeNode>
22+
</div>
23+
<LoadingComponent
24+
[style.padding-left]="node.getNodePadding()"
25+
class="tree-node-loading"
26+
*ngIf="!node.children"
27+
[template]="templates.loadingTemplate"
28+
></LoadingComponent>
29+
</div>
30+
`
31+
})
32+
export class TreeNodeChildrenComponent {
33+
@Input() node:TreeNode;
34+
@Input() templates: any;
35+
}
Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { Component, Input, TemplateRef } from '@angular/core';
22
import { TreeNode } from '../models/tree-node.model';
33

4-
export interface ITreeNodeTemplate {
5-
node: TreeNode;
6-
context: any;
7-
}
8-
94
@Component({
105
selector: 'TreeNodeContent',
11-
template: `<span *ngIf="!treeNodeContentTemplate">{{ node.displayField }}</span>
12-
<template [ngTemplateOutlet]="treeNodeContentTemplate" [ngOutletContext]="{ $implicit: node }"></template>`,
6+
template: `<span *ngIf="!template">{{ node.displayField }}</span>
7+
<template
8+
[ngTemplateOutlet]="template"
9+
[ngOutletContext]="{ $implicit: node, node: node, index: index }">
10+
</template>`,
1311
})
1412
export class TreeNodeContent {
1513
@Input() node: TreeNode;
16-
@Input() treeNodeContentTemplate: TemplateRef<ITreeNodeTemplate>;
14+
@Input() index: number;
15+
@Input() template: TemplateRef<any>;
1716
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Component, Input, ViewEncapsulation } from '@angular/core';
2+
import { TreeNode } from '../models/tree-node.model';
3+
4+
@Component({
5+
selector: 'TreeNodeExpander',
6+
encapsulation: ViewEncapsulation.None,
7+
styles: [
8+
'.toggle-children-wrapper-expanded .toggle-children { transform: rotate(90deg) }',
9+
'.toggle-children-wrapper-collapsed .toggle-children { transform: rotate(0); }',
10+
`.toggle-children-wrapper {
11+
padding: 2px 3px 5px 1px;
12+
}`,
13+
`.toggle-children {
14+
background-image: url(\'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAASCAYAAABSO15qAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABAhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ1dWlkOjY1RTYzOTA2ODZDRjExREJBNkUyRDg4N0NFQUNCNDA3IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkYzRkRFQjcxODUzNTExRTU4RTQwRkQwODFEOUZEMEE3IiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkYzRkRFQjcwODUzNTExRTU4RTQwRkQwODFEOUZEMEE3IiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MTk5NzA1OGEtZDI3OC00NDZkLWE4ODgtNGM4MGQ4YWI1NzNmIiBzdFJlZjpkb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6YzRkZmQxMGMtY2NlNS0xMTc4LWE5OGQtY2NkZmM5ODk5YWYwIi8+IDxkYzp0aXRsZT4gPHJkZjpBbHQ+IDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+Z2x5cGhpY29uczwvcmRmOmxpPiA8L3JkZjpBbHQ+IDwvZGM6dGl0bGU+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+5iogFwAAAGhJREFUeNpiYGBgKABigf///zOQg0EARH4A4gZyDIIZ8B/JoAJKDIDhB0CcQIkBRBtEyABkgxwoMQCGD6AbRKoBGAYxQgXIBRuZGKgAKPIC3QLxArnRSHZCIjspk52ZKMrOFBUoAAEGAKnq593MQAZtAAAAAElFTkSuQmCC\');
15+
height: 8px;
16+
width: 9px;
17+
background-size: contain;
18+
display: inline-block;
19+
position: relative;
20+
background-repeat: no-repeat;
21+
background-position: center;
22+
}`,
23+
`.toggle-children-placeholder {
24+
display: inline-block;
25+
height: 10px;
26+
width: 10px;
27+
position: relative;
28+
top: 1px;
29+
padding-right: 3px;
30+
}`
31+
],
32+
template: `
33+
<span
34+
*ngIf="node.hasChildren"
35+
[class.toggle-children-wrapper-expanded]="node.isExpanded"
36+
[class.toggle-children-wrapper-collapsed]="node.isCollapsed"
37+
class="toggle-children-wrapper"
38+
(click)="node.mouseAction('expanderClick', $event)">
39+
40+
<span class="toggle-children"></span>
41+
</span>
42+
<span
43+
*ngIf="!node.hasChildren"
44+
class="toggle-children-placeholder">
45+
</span>
46+
`
47+
})
48+
export class TreeNodeExpanderComponent {
49+
@Input() node:TreeNode;
50+
51+
constructor() {
52+
}
53+
}

lib/components/tree-node.component.ts

Lines changed: 18 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
import { Component, Input, ElementRef, AfterViewInit, ViewEncapsulation, TemplateRef } from '@angular/core';
22
import { TreeNode } from '../models/tree-node.model';
3-
import { ITreeNodeTemplate } from './tree-node-content.component';
43

54
@Component({
65
selector: 'TreeNode',
76
encapsulation: ViewEncapsulation.None,
87
styles: [
9-
'.tree-children.tree-children-no-padding { padding-left: 0 }',
10-
'.tree-children { padding-left: 20px }',
118
`.node-content-wrapper {
129
display: inline-block;
1310
padding: 2px 5px;
@@ -21,124 +18,54 @@ import { ITreeNodeTemplate } from './tree-node-content.component';
2118
'.node-content-wrapper:hover { background: #f7fbff }',
2219
'.tree-node-active > .node-wrapper > .node-content-wrapper, .tree-node-focused > .node-content-wrapper, .node-content-wrapper:hover { box-shadow: inset 0 0 1px #999; }',
2320
'.node-content-wrapper.is-dragging-over { background: #ddffee; box-shadow: inset 0 0 1px #999; }',
24-
'.node-content-wrapper.is-dragging-over-disabled { opacity: 0.5 }',
25-
'.tree-node-expanded > .node-wrapper > .toggle-children-wrapper > .toggle-children { transform: rotate(90deg) }',
26-
'.tree-node-collapsed > .node-wrapper > .toggle-children-wrapper > .toggle-children { transform: rotate(0); }',
27-
`.toggle-children-wrapper {
28-
padding: 2px 3px 5px 1px;
29-
}`,
30-
`.toggle-children {
31-
background-image: url(\'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAASCAYAAABSO15qAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABAhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ1dWlkOjY1RTYzOTA2ODZDRjExREJBNkUyRDg4N0NFQUNCNDA3IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkYzRkRFQjcxODUzNTExRTU4RTQwRkQwODFEOUZEMEE3IiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkYzRkRFQjcwODUzNTExRTU4RTQwRkQwODFEOUZEMEE3IiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MTk5NzA1OGEtZDI3OC00NDZkLWE4ODgtNGM4MGQ4YWI1NzNmIiBzdFJlZjpkb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6YzRkZmQxMGMtY2NlNS0xMTc4LWE5OGQtY2NkZmM5ODk5YWYwIi8+IDxkYzp0aXRsZT4gPHJkZjpBbHQ+IDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+Z2x5cGhpY29uczwvcmRmOmxpPiA8L3JkZjpBbHQ+IDwvZGM6dGl0bGU+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+5iogFwAAAGhJREFUeNpiYGBgKABigf///zOQg0EARH4A4gZyDIIZ8B/JoAJKDIDhB0CcQIkBRBtEyABkgxwoMQCGD6AbRKoBGAYxQgXIBRuZGKgAKPIC3QLxArnRSHZCIjspk52ZKMrOFBUoAAEGAKnq593MQAZtAAAAAElFTkSuQmCC\');
32-
height: 8px;
33-
width: 9px;
34-
background-size: contain;
35-
display: inline-block;
36-
position: relative;
37-
background-repeat: no-repeat;
38-
background-position: center;
39-
}`,
40-
`.toggle-children-placeholder {
41-
display: inline-block;
42-
height: 10px;
43-
width: 10px;
44-
position: relative;
45-
top: 1px;
46-
padding-right: 3px;
47-
}`
21+
'.node-content-wrapper.is-dragging-over-disabled { opacity: 0.5 }'
4822
],
4923
template: `
5024
<div
51-
*ngIf="!node.isHidden"
25+
*ngIf="!node.isHidden && !templates.treeNodeFullTemplate"
5226
class="tree-node tree-node-level-{{ node.level }}"
27+
[class]="node.getClass()"
5328
[class.tree-node-expanded]="node.isExpanded && node.hasChildren"
5429
[class.tree-node-collapsed]="node.isCollapsed && node.hasChildren"
5530
[class.tree-node-leaf]="node.isLeaf"
5631
[class.tree-node-active]="node.isActive"
5732
[class.tree-node-focused]="node.isFocused">
5833
59-
<TreeNodeDropSlot
60-
*ngIf="nodeIndex === 0"
61-
[dropIndex]="nodeIndex"
62-
[node]="node.parent"
63-
></TreeNodeDropSlot>
64-
65-
<div class="node-wrapper" [style.padding-left]="getNodePadding()">
66-
<span
67-
*ngIf="node.hasChildren"
68-
class="toggle-children-wrapper"
69-
(click)="node.mouseAction('expanderClick', $event)">
34+
<TreeNodeDropSlot *ngIf="index === 0" [dropIndex]="index" [node]="node.parent"></TreeNodeDropSlot>
7035
71-
<span class="toggle-children"></span>
72-
</span>
73-
<span
74-
*ngIf="!node.hasChildren"
75-
class="toggle-children-placeholder">
76-
</span>
36+
<div class="node-wrapper" [style.padding-left]="node.getNodePadding()">
37+
<TreeNodeExpander [node]="node"></TreeNodeExpander>
7738
<div class="node-content-wrapper"
78-
#nodeContentWrapper
7939
(click)="node.mouseAction('click', $event)"
8040
(dblclick)="node.mouseAction('dblClick', $event)"
8141
(contextmenu)="node.mouseAction('contextMenu', $event)"
82-
(treeDrop)="onDrop($event)"
83-
[treeAllowDrop]="allowDrop.bind(this)"
42+
(treeDrop)="node.onDrop($event)"
43+
[treeAllowDrop]="node.allowDrop"
8444
[treeDrag]="node"
8545
[treeDragEnabled]="node.allowDrag()">
8646
87-
<TreeNodeContent [node]="node" [treeNodeContentTemplate]="treeNodeContentTemplate"></TreeNodeContent>
47+
<TreeNodeContent [node]="node" [index]="index" [template]="templates.treeNodeTemplate">
48+
</TreeNodeContent>
8849
</div>
8950
</div>
9051
91-
<div [class.tree-children]="true"
92-
[class.tree-children-no-padding]="node.options.levelPadding"
93-
*ngIf="node.isExpanded">
94-
<div *ngIf="node.children">
95-
<TreeNode
96-
*ngFor="let node of node.children; let i = index"
97-
[node]="node"
98-
[nodeIndex]="i"
99-
[treeNodeContentTemplate]="treeNodeContentTemplate"
100-
[loadingTemplate]="loadingTemplate">
101-
</TreeNode>
102-
</div>
103-
<LoadingComponent
104-
[style.padding-left]="getNodePadding()"
105-
class="tree-node-loading"
106-
*ngIf="!node.children"
107-
[loadingTemplate]="loadingTemplate"
108-
></LoadingComponent>
109-
</div>
110-
<TreeNodeDropSlot
111-
[dropIndex]="nodeIndex + 1"
112-
[node]="node.parent"
113-
></TreeNodeDropSlot>
52+
<TreeNodeChildren [node]="node" [templates]="templates"></TreeNodeChildren>
53+
<TreeNodeDropSlot [dropIndex]="index + 1" [node]="node.parent"></TreeNodeDropSlot>
11454
</div>
115-
`
55+
<template
56+
[ngTemplateOutlet]="templates.treeNodeFullTemplate"
57+
[ngOutletContext]="{ $implicit: node, node: node, index: index, templates: templates }">
58+
</template>`
11659
})
11760

11861
export class TreeNodeComponent implements AfterViewInit {
11962
@Input() node:TreeNode;
120-
@Input() nodeIndex:number;
121-
@Input() treeNodeContentTemplate: TemplateRef<ITreeNodeTemplate>;
122-
@Input() loadingTemplate: TemplateRef<any>;
63+
@Input() index:number;
64+
@Input() templates: any;
12365

12466
constructor(private elementRef: ElementRef) {
12567
}
12668

127-
onDrop($event) {
128-
this.node.mouseAction('drop', $event.event, {
129-
from: $event.element,
130-
to: { parent: this.node, index: 0 }
131-
});
132-
}
133-
134-
allowDrop(element) {
135-
return this.node.options.allowDrop(element, { parent: this.node, index: 0 });
136-
}
137-
138-
getNodePadding() {
139-
return this.node.options.levelPadding * (this.node.level - 1) + 'px';
140-
}
141-
14269
ngAfterViewInit() {
14370
this.node.elementRef = this.elementRef;
14471
}

lib/components/tree.component.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Component, Input, Output, OnChanges, SimpleChange, EventEmitter, ViewEncapsulation, ContentChild, TemplateRef } from '@angular/core';
2-
import { ITreeNodeTemplate } from './tree-node-content.component';
32
import { TreeModel } from '../models/tree.model';
43
import { TreeDraggedElement } from '../models/tree-dragged-element.model';
54
import { TreeOptions } from '../models/tree-options.model';
@@ -33,9 +32,12 @@ import * as _ from 'lodash'
3332
<TreeNode
3433
*ngFor="let node of treeModel.roots; let i = index"
3534
[node]="node"
36-
[nodeIndex]="i"
37-
[loadingTemplate]="loadingTemplate"
38-
[treeNodeContentTemplate]="treeNodeTemplate">
35+
[index]="i"
36+
[templates]="{
37+
loadingTemplate: loadingTemplate,
38+
treeNodeTemplate: treeNodeTemplate,
39+
treeNodeFullTemplate: treeNodeFullTemplate
40+
}">
3941
</TreeNode>
4042
</div>
4143
`
@@ -49,7 +51,8 @@ export class TreeComponent implements OnChanges {
4951
_options:TreeOptions;
5052

5153
@ContentChild('loadingTemplate') loadingTemplate: TemplateRef<any>;
52-
@ContentChild('treeNodeTemplate') treeNodeTemplate: TemplateRef<ITreeNodeTemplate>;
54+
@ContentChild('treeNodeTemplate') treeNodeTemplate: TemplateRef<any>;
55+
@ContentChild('treeNodeFullTemplate') treeNodeFullTemplate: TemplateRef<any>;
5356

5457
// Will be handled in ngOnChanges
5558
@Input() set nodes(nodes:any[]) { };

0 commit comments

Comments
 (0)