Skip to content
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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,12 @@ Here is an example of its usage:
'node': '<i class="fa fa-folder-o fa-lg"></i>',
'leaf': '<i class="fa fa-file-o fa-lg"></i>',
'leftMenu': '<i class="fa fa-navicon fa-lg"></i>'
},
'menuItems': [
{ action: NodeMenuItemAction.Custom, name: 'Foo', cssClass: 'fa fa-arrow-right' },
{ action: NodeMenuItemAction.Custom, name: 'Bar', cssClass: 'fa fa-arrow-right' },
{ action: NodeMenuItemAction.Custom, name: 'Baz', cssClass: 'fa fa-arrow-right'}
]
}
},
children: [
Expand All @@ -358,6 +364,7 @@ Here is an example of its usage:
* `node` - String - It specifies a html template which will be included to the left of the node's value.
* `leaf` - String - It specifies a html template which will be included to the left of the leaf's value.
* `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.
* `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.

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.

Expand Down
10 changes: 9 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import {

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

import { NodeMenuItemAction } from './src/menu/menu.events';
import { NodeMenuItem } from './src/menu/node-menu.component';

import {
NodeEvent,
NodeCreatedEvent,
Expand All @@ -18,6 +21,7 @@ import {
NodeSelectedEvent,
NodeExpandedEvent,
NodeCollapsedEvent,
MenuItemSelectedEvent,
NodeDestructiveEvent
} from './src/tree.events';

Expand All @@ -41,5 +45,9 @@ export {
NodeCollapsedEvent,
NodeDestructiveEvent,
TreeComponent,
TreeModule
TreeModule,
NodeMenuItemAction,
NodeMenuItem,
ChildrenLoadingFunction,
MenuItemSelectedEvent
};
10 changes: 4 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"@types/jasmine": "2.8.2",
"@types/node": "8.0.53",
"alertifyjs": "1.10.0",
"codelyzer": "3.0.1",
"codelyzer": "4.0.1",
"conventional-changelog": "1.1.7",
"conventional-changelog-cli": "1.3.5",
"conventional-github-releaser": "2.0.0",
Expand All @@ -88,13 +88,11 @@
"shelljs": "0.7.8",
"systemjs-builder": "0.16.12",
"ts-node": "3.3.0",
"tslint": "5.4.3",
"tslint-config-valorsoft": "2.0.1",
"tslint": "5.8.0",
"tslint-config-valorsoft": "2.1.1",
"typescript": "2.4.2",
"uuid": "3.1.0",
"webpack": "3.8.1",
"zone.js": "0.8.18"
},
"dependencies": {
"uuid": "3.1.0"
}
}
18 changes: 16 additions & 2 deletions src/demo/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { NodeEvent, TreeModel, RenamableNode, Ng2TreeSettings } from '../../../index';
import { Ng2TreeSettings, NodeEvent, RenamableNode, TreeModel } from '../../../index';
import { NodeMenuItemAction } from '../../menu/menu.events';
import { MenuItemSelectedEvent } from '../../tree.events';

declare const alertify: any;

Expand All @@ -12,6 +14,7 @@ declare const alertify: any;
<div class="tree-content">
<tree #treeFonts
[tree]="fonts"
(menuItemSelected)="onMenuItemSelected($event)"
(nodeRemoved)="onNodeRemoved($event)"
(nodeRenamed)="onNodeRenamed($event)"
(nodeSelected)="onNodeSelected($event)"
Expand Down Expand Up @@ -202,8 +205,15 @@ export class AppComponent implements OnInit {
]
},
{
value: 'Sans-serif',
value: 'Sans-serif (Right click me - I have a custom menu)',
id: 11,
settings: {
menuItems: [
{ action: NodeMenuItemAction.Custom, name: 'Foo', cssClass: 'fa fa-arrow-right' },
{ action: NodeMenuItemAction.Custom, name: 'Bar', cssClass: 'fa fa-arrow-right' },
{ action: NodeMenuItemAction.Custom, name: 'Baz', cssClass: 'fa fa-arrow-right'}
]
},
children: [
{value: 'Arial', id: 12},
{value: 'Century Gothic', id: 13},
Expand Down Expand Up @@ -567,6 +577,10 @@ export class AppComponent implements OnInit {
AppComponent.logEvent(e, 'Selected');
}

public onMenuItemSelected(e: MenuItemSelectedEvent) {
AppComponent.logEvent(e, `You selected ${e.selectedItem} menu item`);
}

public onNodeExpanded(e: NodeEvent): void {
AppComponent.logEvent(e, 'Expanded');
}
Expand Down
4 changes: 3 additions & 1 deletion src/menu/menu.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export enum NodeMenuItemAction {
NewFolder,
NewTag,
Rename,
Remove
Remove,
Custom
}

export enum NodeMenuAction {
Expand All @@ -16,4 +17,5 @@ export interface NodeMenuEvent {

export interface NodeMenuItemSelectedEvent {
nodeMenuItemAction: NodeMenuItemAction;
nodeMenuItemSelected?: string;
}
14 changes: 11 additions & 3 deletions src/menu/node-menu.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
Component, EventEmitter, Output, Inject, OnDestroy, OnInit, ViewChild, Renderer2
Component, EventEmitter, Output, Input, Inject, OnDestroy, OnInit, ViewChild, Renderer2
} from '@angular/core';
import { NodeMenuService } from './node-menu.service';
import { NodeMenuItemSelectedEvent, NodeMenuItemAction, NodeMenuAction } from './menu.events';
Expand All @@ -23,6 +23,9 @@ export class NodeMenuComponent implements OnInit, OnDestroy {
@Output()
public menuItemSelected: EventEmitter<NodeMenuItemSelectedEvent> = new EventEmitter<NodeMenuItemSelectedEvent>();

@Input()
public menuItems: NodeMenuItem[];

@ViewChild('menuContainer') public menuContainer: any;

public availableMenuItems: NodeMenuItem[] = [
Expand Down Expand Up @@ -55,6 +58,7 @@ export class NodeMenuComponent implements OnInit, OnDestroy {
}

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

public onMenuItemSelected(e: MouseEvent, selectedMenuItem: NodeMenuItem): void {
if (isLeftButtonClicked(e)) {
this.menuItemSelected.emit({nodeMenuItemAction: selectedMenuItem.action});
this.menuItemSelected.emit({
nodeMenuItemAction: selectedMenuItem.action,
nodeMenuItemSelected: selectedMenuItem.name
});

this.nodeMenuService.fireMenuEvent(e.target as HTMLElement, NodeMenuAction.Close);
}
}
Expand All @@ -84,5 +92,5 @@ export class NodeMenuComponent implements OnInit, OnDestroy {
export interface NodeMenuItem {
name: string;
action: NodeMenuItemAction;
cssClass: string;
cssClass?: string;
}
35 changes: 28 additions & 7 deletions src/tree-internal.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { Component, ElementRef, TemplateRef, Inject, Input, OnDestroy, OnInit, OnChanges, SimpleChanges } from '@angular/core';
import {
Component,
ElementRef,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
TemplateRef
} from '@angular/core';
import * as TreeTypes from './tree.types';
import { Tree } from './tree';
import { TreeController } from './tree-controller';
Expand Down Expand Up @@ -41,13 +50,19 @@ import { get } from './utils/fn.utils';

<div class="node-left-menu" *ngIf="tree.hasLeftMenu()" (click)="showLeftMenu($event)" [innerHTML]="tree.leftMenuTemplate">
</div>
<node-menu *ngIf="tree.hasLeftMenu() && isLeftMenuVisible"
<node-menu *ngIf="tree.hasLeftMenu() && isLeftMenuVisible && !hasCustomMenu()"
(menuItemSelected)="onMenuItemSelected($event)">
</node-menu>
</div>

<node-menu *ngIf="isRightMenuVisible" (menuItemSelected)="onMenuItemSelected($event)"></node-menu>
<node-menu *ngIf="isRightMenuVisible && !hasCustomMenu()"
(menuItemSelected)="onMenuItemSelected($event)">
</node-menu>

<node-menu *ngIf="hasCustomMenu() && (isRightMenuVisible || isLeftMenuVisible)"
[menuItems]="tree.menuItems"
(menuItemSelected)="onMenuItemSelected($event)">
</node-menu>
<ng-template [ngIf]="tree.isNodeExpanded()">
<tree-internal *ngFor="let child of tree.childrenAsync | async" [tree]="child" [template]="template"></tree-internal>
</ng-template>
Expand All @@ -72,9 +87,9 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy {

private subscriptions: Subscription[] = [];

public constructor(@Inject(NodeMenuService) private nodeMenuService: NodeMenuService,
@Inject(TreeService) public treeService: TreeService,
@Inject(ElementRef) public element: ElementRef) {
public constructor(private nodeMenuService: NodeMenuService,
public treeService: TreeService,
public element: ElementRef) {
}

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

this.settings = this.settings || { rootIsVisible: true };

this.subscriptions.push(this.nodeMenuService.hideMenuStream(this.element)
.subscribe(() => {
this.isRightMenuVisible = false;
Expand Down Expand Up @@ -182,6 +196,9 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy {
case NodeMenuItemAction.Remove:
this.onRemoveSelected();
break;
case NodeMenuItemAction.Custom:
this.treeService.fireMenuItemSelected(this.tree, e.nodeMenuItemSelected);
break;
default:
throw new Error(`Chosen menu item doesn't exist`);
}
Expand Down Expand Up @@ -235,4 +252,8 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy {
public isRootHidden(): boolean {
return this.tree.isRoot() && !this.settings.rootIsVisible;
}

public hasCustomMenu(): boolean {
return this.tree.hasCustomMenu();
}
}
13 changes: 10 additions & 3 deletions src/tree.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
} from '@angular/core';
import { TreeService } from './tree.service';
import * as TreeTypes from './tree.types';
import { NodeEvent } from './tree.events';
import { NodeEvent, MenuItemSelectedEvent } from './tree.events';
import { Tree } from './tree';
import { TreeController } from './tree-controller';
import { Subscription } from 'rxjs/Subscription';
Expand Down Expand Up @@ -46,8 +46,11 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy {
@Output()
public nodeCollapsed: EventEmitter<any> = new EventEmitter();

@Output()
public loadNextLevel: EventEmitter<any> = new EventEmitter();
@Output()
public menuItemSelected: EventEmitter<any> = new EventEmitter();

@Output()
public loadNextLevel: EventEmitter<any> = new EventEmitter();

public tree: Tree;
@ViewChild('rootComponent') public rootComponent;
Expand Down Expand Up @@ -96,6 +99,10 @@ public loadNextLevel: EventEmitter<any> = new EventEmitter();
this.nodeCollapsed.emit(e);
}));

this.subscriptions.push(this.treeService.menuItemSelected$.subscribe((e: MenuItemSelectedEvent) => {
this.menuItemSelected.emit(e);
}));

this.subscriptions.push(this.treeService.loadNextLevel$.subscribe((e: NodeEvent) => {
this.loadNextLevel.emit(e);
}));
Expand Down
6 changes: 6 additions & 0 deletions src/tree.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ export class NodeCollapsedEvent extends NodeEvent {
}
}

export class MenuItemSelectedEvent extends NodeEvent {
public constructor(node: Tree, public selectedItem: string) {
super(node);
}
}

export class LoadNextLevelEvent extends NodeEvent {
public constructor(node: Tree) {
super(node);
Expand Down
8 changes: 7 additions & 1 deletion src/tree.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
NodeRemovedEvent,
NodeRenamedEvent,
NodeSelectedEvent,
MenuItemSelectedEvent,
LoadNextLevelEvent
} from './tree.events';
import { RenamableNode } from './tree.types';
Expand All @@ -15,7 +16,7 @@ import { Observable, Subject } from 'rxjs/Rx';
import { ElementRef, Inject, Injectable } from '@angular/core';
import { NodeDraggableService } from './draggable/node-draggable.service';
import { NodeDraggableEvent } from './draggable/draggable.events';
import {isEmpty} from './utils/fn.utils';
import { isEmpty } from './utils/fn.utils';

@Injectable()
export class TreeService {
Expand All @@ -26,6 +27,7 @@ export class TreeService {
public nodeSelected$: Subject<NodeSelectedEvent> = new Subject<NodeSelectedEvent>();
public nodeExpanded$: Subject<NodeExpandedEvent> = new Subject<NodeExpandedEvent>();
public nodeCollapsed$: Subject<NodeCollapsedEvent> = new Subject<NodeCollapsedEvent>();
public menuItemSelected$: Subject<MenuItemSelectedEvent> = new Subject<MenuItemSelectedEvent>();
public loadNextLevel$: Subject<LoadNextLevelEvent> = new Subject<LoadNextLevelEvent>();

private controllers: Map<string | number, TreeController> = new Map();
Expand Down Expand Up @@ -58,6 +60,10 @@ export class TreeService {
this.nodeMoved$.next(new NodeMovedEvent(tree, parent));
}

public fireMenuItemSelected(tree: Tree, selectedItem: string): void {
this.menuItemSelected$.next(new MenuItemSelectedEvent(tree, selectedItem));
}

public fireNodeSwitchFoldingType(tree: Tree): void {
if (tree.isNodeExpanded()) {
this.fireNodeExpanded(tree);
Expand Down
16 changes: 16 additions & 0 deletions src/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {

import { Observable, Observer } from 'rxjs/Rx';
import { TreeModel, RenamableNode, FoldingType, TreeStatus, TreeModelSettings, ChildrenLoadingFunction } from './tree.types';
import { NodeMenuItem } from './menu/node-menu.component';

import * as uuidv4 from 'uuid/v4';

Expand Down Expand Up @@ -343,6 +344,21 @@ export class Tree {
return !this.isBranch();
}

/**
* Get menu items of the current tree.
* @returns {NodeMenuItem[]} The menu items of the current tree.
*/
public get menuItems(): NodeMenuItem[] {
return get(this.node.settings, 'menuItems');
}

/**
* Check whether or not this tree has a custom menu.
* @returns {boolean} A flag indicating whether or not this tree has a custom menu.
*/
public hasCustomMenu(): boolean {
return !this.isStatic() && !!get(this.node.settings, 'menuItems', false);
}
/**
* Check whether this tree is "Branch" or not. "Branch" is a node that has children.
* @returns {boolean} A flag indicating whether or not this tree is a "Branch".
Expand Down
8 changes: 8 additions & 0 deletions src/tree.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { get, defaultsDeep } from './utils/fn.utils';
import { NodeMenuItem } from './menu/node-menu.component';

export class FoldingType {
public static Expanded: FoldingType = new FoldingType('node-expanded');
Expand Down Expand Up @@ -76,6 +77,13 @@ export class TreeModelSettings {
*/
public rightMenu?: boolean;

/**
* "menu" property when set will be available as custom context menu.
* @name TreeModelSettings#MenuItems
* @type NodeMenuItem
*/
public menuItems?: NodeMenuItem[];

/**
* "static" property when set to true makes it impossible to drag'n'drop tree or call a menu on it.
* @name TreeModelSettings#static
Expand Down
Loading