Skip to content

Commit 55e4ace

Browse files
committed
🎉 Added feature for renaming items.
1 parent 3e2e814 commit 55e4ace

File tree

8 files changed

+182
-73
lines changed

8 files changed

+182
-73
lines changed

README.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@ A light-weight library for management of hierachical content. Most solutions I f
55
## What it does.
66

77
1. :heavy_check_mark: Hierachical rendering of content.
8-
2. Event publishing/subscription from items
9-
- ✔️ Subscribing to items checked event (based on type)
8+
2. ✔️ Subscribing to items checked event (based on type)
109
3. :heavy_check_mark: Moving Items between folders (drag-and-drop)
11-
4. Custom formating of items on the tree based on the `type` property.
12-
- :heavy_check_mark: Customising Icons
13-
- ✔️ Rendering (checkboxes or plain content)
14-
15-
5. Programmatically toggle item visibility based on the `type` property.
16-
6. Sorting items alphametically or grouping based on types
17-
7. Disabling and Enabling Item
18-
8. Double clicking to rename item
19-
9. Programmatically determining what item can be dragged into another item.
20-
10. Custom Context Menu depending on item type.
10+
4. :heavy_check_mark: Customising Item Rendering based on item type
11+
5. ✔️ Rendering selectable items like checkboxes or plain content
12+
6. Programmatically toggle item visibility based on the `type` property.
13+
7. Sorting items alphametically or grouping based on types
14+
8. Disabling and Enabling Item
15+
9. Double clicking to rename item
16+
10. Programmatically determining what item can be dragged into another item.
17+
11. Custom Context Menu depending on item type.
2118

2219
## What it looks like.
2320

@@ -197,7 +194,7 @@ export default class App extends Vue {
197194
Out-of-the-box, `v-tree-vue` ships with default behaviors like double clicking an item to rename, pushing the `DEL` key to delete and moving (drag-and-drop) items into new locations. However, this is totally customisable. The default command API exposes the following configurations:
198195

199196
```ts
200-
export interface DefaultBehaviors {
197+
export interface ItemBehavior {
201198
// Allow customisation of items that can be renamed on the tree.
202199
enableRenaming(type: string): void;
203200
// Allow customisation of items that can be deleted on the tree.

package.json

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "v-tree-vue",
3-
"version": "0.1.5",
3+
"version": "0.1.6",
44
"license": "ISC",
55
"repository": {
66
"type": "git",
@@ -17,7 +17,9 @@
1717
"TreeView",
1818
"Hierachical",
1919
"Recursive",
20-
"Tree"
20+
"Tree",
21+
"Typescript",
22+
"Flexible TreeView"
2123
],
2224
"author": "Enyi Francis Hocaha",
2325
"dependencies": {
@@ -50,10 +52,5 @@
5052
"sass-loader": "^8.0.2",
5153
"typescript": "~4.1.5",
5254
"vue-template-compiler": "^2.6.11"
53-
},
54-
"license": "ISC",
55-
"repository": {
56-
"type": "git",
57-
"url": "git+https://github.com/geekhybrid/tree-vue.git"
5855
}
5956
}

src/App.vue

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div style="display: flex">
33
<!-- Example of how to customise appearance of tree items -->
4-
<tree-view :treeViewItems="treeViewNodes" @created="customiseTreeView" :hideGuideLines="true">
4+
<tree-view :treeViewItems="treeViewNodes" @created="customiseTreeView" >
55
<template v-slot:icon="treeViewItem">
66
<img src="@/assets/folder.svg" alt="folder" v-if="treeViewItem.type === 'folder'" >
77
<img src="@/assets/word.svg" alt="vue-logo" v-else-if="treeViewItem.type === '.doc'" height="18" width="18">
@@ -25,14 +25,22 @@ export default class App extends Vue {
2525
2626
customiseTreeView(treeCreatedEvent: TreeViewCreatedEventPayload): void {
2727
const customisations = treeCreatedEvent.itemCustomisations;
28+
29+
const folderRenameHandler = (folderItem: TreeViewItem) => new Promise<TreeViewItem>((accept) => {
30+
console.log(folderItem);
31+
});
32+
33+
customisations.registerDragAndDropValidator(() => true);
34+
customisations.registerItemRenamedHandler('folder', folderRenameHandler);
35+
2836
customisations.makeItemsCheckable([".doc", ".excel", "media" ]);
2937
}
3038
3139
// customiseSchools(treeCreatedEvent: TreeViewCreatedEventPayload): void {
3240
// const customisations = treeCreatedEvent.itemCustomisations;
3341
// const eventManager = treeCreatedEvent.eventManager;
3442
35-
// eventManager.subscribeToItemChecked("department", (items) => console.log(items));
43+
// eventManager.subscribeToItemChecked("department", (items) => g(items));
3644
// customisations.makeItemsCheckable(["department"]);
3745
// }
3846

src/businessLogic/contracts/types.ts

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,34 @@ export interface TreeViewItem {
88
}
99

1010
export interface ItemTypeCustomisations {
11+
isDropValid(droppedNode: TreeViewItem, dropHost: TreeViewItem): boolean;
1112
makeItemsCheckable(types: string[]): void;
12-
typeCustomisations(): {[type: string]: Customisations };
13-
}
14-
15-
export interface DefaultBehaviors {
16-
// Allow customisation of items that can be renamed on the tree.
17-
enableRenaming(type: string): void;
18-
// Allow customisation of items that can be deleted on the tree.
19-
enableDeleting(type: string): void;
20-
// Allow registration of handler to be called when an item of a particular type has been deleted.
21-
registerItemDeletedHandler(type: string, callback: (item: TreeViewItem) => Promise<TreeViewItem>): void;
22-
// Allow registration of a handler to be called when an item of a particular type has been renamed.
13+
registerItemDeletedHandler(type: string, callback: (item: TreeViewItem) => Promise<boolean>): void;
2314
registerItemRenamedHandler(type: string, callback: (renamedItem: TreeViewItem) => Promise<TreeViewItem>): void;
24-
// Allow registration of a handler to be called to verify if a drag-and-drop move operation is valid.
25-
registerItemCanMoveHandler(canItemMoveCallBack: (movingItem: TreeViewItem, destinationItem: TreeViewItem) => Promise<boolean>): void;
26-
// Allow registration of a handler to be called when a move operation is succesful. The moved item property will contain
27-
// the information of the parentID of it's new parent or undefined if it was moved to the root directory.
15+
registerDragAndDropValidator(canItemMoveCallBack: (movingItem: TreeViewItem, destinationItem: TreeViewItem) => boolean): void;
2816
registerItemMovedHandler(callBack: (movedItem: TreeViewItem) => Promise<TreeViewItem>): void;
17+
18+
registerAnyItemDeleted(callback: (item: TreeViewItem) => Promise<boolean>): void;
19+
registerAnyItemRenamed(callback: (item: TreeViewItem) => Promise<TreeViewItem>): void;
20+
registerAnyItemDragAndDrop(): void;
21+
22+
disableDragAndDrop(): void;
23+
getCustomisation(type: string): Customisations;
24+
getRenameHandler(type: string): (item: TreeViewItem) => Promise<TreeViewItem>;
25+
}
26+
27+
export interface Customisations {
28+
canRename?: boolean;
29+
isCheckable?: boolean;
30+
}
31+
32+
export interface EditableItem {
33+
begin(): void;
34+
end(): void;
35+
}
36+
37+
export interface RenameItemStartedEventArgs {
38+
item: EditableItem;
2939
}
3040

3141
export interface TreeViewCreatedEventPayload {
@@ -59,10 +69,6 @@ export interface TreeViewViewModel {
5969
readonly selectedItems: TreeViewItem[];
6070
}
6171

62-
export interface Customisations {
63-
isCheckable?: boolean;
64-
}
65-
6672
export interface ItemCheckedChangedEvent {
6773
item: TreeViewItem,
6874
status: CheckedState

src/businessLogic/itemCustomisations/itemCustomisations.spec.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ describe("ItemCustomisation", () => {
77
const expectedTypes = [".docs", ".excel"];
88
customisations.makeItemsCheckable(expectedTypes);
99

10-
const customisedTypes = customisations.typeCustomisations();
11-
expectedTypes.forEach(type => {
12-
expect(customisedTypes[type].isCheckable).toBe(true);
13-
})
10+
[".docs", ".excel"].forEach(type => {
11+
expect(customisations.getCustomisation(type).isCheckable).toBe(true);
12+
});
1413
});
1514
});

src/businessLogic/itemCustomisations/itemCustomisations.ts

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
import { Customisations, ItemTypeCustomisations } from "../contracts/types";
1+
import { ANY_TYPE } from "@/constants";
2+
import { Customisations, ItemTypeCustomisations, TreeViewItem } from "../contracts/types";
23

34
const typeCustomisations: {[type: string]: Customisations } = {};
5+
let canItemDrop: (movingItem: TreeViewItem, destinationItem: TreeViewItem) => boolean;
6+
let isAllowAnyDrop = true;
7+
8+
let renameHandlers: {[type: string] : (item: TreeViewItem) => Promise<TreeViewItem> } = {}
9+
let deleteHandlers: {[type: string] : (item: TreeViewItem) => Promise<boolean> } = {}
410

511
export const ItemCustomisations: ItemTypeCustomisations = {
612
makeItemsCheckable(types: string[]): void {
@@ -12,7 +18,62 @@ export const ItemCustomisations: ItemTypeCustomisations = {
1218
});
1319
},
1420

15-
typeCustomisations(): {[type: string]: Customisations } {
16-
return typeCustomisations;
21+
registerDragAndDropValidator(canItemMoveCallBack: (movingItem: TreeViewItem, destinationItem: TreeViewItem) => boolean): void {
22+
isAllowAnyDrop = false;
23+
canItemDrop = canItemMoveCallBack;
24+
},
25+
26+
registerItemDeletedHandler(type: string, callback: (item: TreeViewItem) => Promise<boolean>): void {
27+
deleteHandlers[type] = callback;
28+
},
29+
30+
registerItemRenamedHandler(type: string, callback: (renamedItem: TreeViewItem) => Promise<TreeViewItem>): void {
31+
renameHandlers[type] = callback;
32+
if (typeCustomisations[type])
33+
{
34+
typeCustomisations[type]
35+
}
36+
else
37+
{
38+
typeCustomisations[type] = {
39+
canRename: true
40+
}
41+
}
42+
},
43+
44+
registerItemMovedHandler(callBack: (movedItem: TreeViewItem) => Promise<TreeViewItem>): void {
45+
console.log(callBack);
46+
},
47+
48+
registerAnyItemDeleted(callback: (item: TreeViewItem) => Promise<boolean>): void {
49+
deleteHandlers = {};
50+
deleteHandlers[ANY_TYPE] = callback;
51+
},
52+
53+
registerAnyItemRenamed(callback: (item: TreeViewItem) => Promise<TreeViewItem>): void {
54+
renameHandlers = {};
55+
renameHandlers[ANY_TYPE] = callback;
56+
},
57+
58+
registerAnyItemDragAndDrop(): void {
59+
isAllowAnyDrop = true;
60+
canItemDrop = () => true;
61+
},
62+
63+
isDropValid(droppedNode: TreeViewItem, dropHost: TreeViewItem): boolean {
64+
return canItemDrop(droppedNode, dropHost);
65+
},
66+
67+
disableDragAndDrop(): void {
68+
isAllowAnyDrop = false;
69+
canItemDrop = () => false;
70+
},
71+
72+
getCustomisation(type: string): Customisations {
73+
return typeCustomisations[type];
74+
},
75+
76+
getRenameHandler(type: string): (item: TreeViewItem) => Promise<TreeViewItem> {
77+
return renameHandlers[type];
1778
}
1879
}

src/components/treeView.vue/treeView.vue

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</slot>
1919
</div>
2020
<treeview-item :item="treeViewItem" :treeViewModel="viewModel" @changed="updateItemCheckedStatus"
21-
:customisations="getItemCustomisation(treeViewItem.type)" />
21+
:customisations="itemCustomisations" />
2222
</div>
2323

2424
<div class="node-child hide" :class="{'hide-guidelines': hideGuideLines}">
@@ -36,7 +36,13 @@
3636
<script lang='ts'>
3737
import {Vue, Component, Prop, Watch} from 'vue-property-decorator';
3838
import { TreeViewModel } from '@/businessLogic/treviewViewModel/treeViewViewModel'
39-
import { CheckedState, Customisations, ItemCheckedChangedEvent, SelectionMode, TreeViewCreatedEventPayload, TreeViewItem } from '@/businessLogic/contracts/types';
39+
import {
40+
CheckedState,
41+
ItemCheckedChangedEvent,
42+
SelectionMode,
43+
TreeViewCreatedEventPayload,
44+
TreeViewItem
45+
} from '@/businessLogic/contracts/types';
4046
import { ItemCustomisations } from "@/businessLogic/itemCustomisations/itemCustomisations";
4147
import { eventManager } from '@/businessLogic/eventHub/explorerEventPublisher';
4248
@@ -58,10 +64,6 @@ export default class TreeView extends Vue {
5864
this.$emit("created", payload);
5965
}
6066
61-
getItemCustomisation(type: string): Customisations {
62-
return this.itemCustomisations.typeCustomisations()[type];
63-
}
64-
6567
updateItemCheckedStatus(checkedEvent: ItemCheckedChangedEvent): void {
6668
const { item, status } = checkedEvent;
6769
item.checkedStatus = status;
@@ -94,20 +96,20 @@ export default class TreeView extends Vue {
9496
}
9597
}
9698
97-
onDropNode(node: TreeViewItem, event: DragEvent): void {
99+
onDropNode(dropHost: TreeViewItem, event: DragEvent): void {
98100
if (event.dataTransfer) {
99101
const droppedNode = JSON.parse(event.dataTransfer.getData('text/plain')) as TreeViewItem;
100102
101103
this.removeHoverClass(event)
102104
103-
if (droppedNode.id === node.id) {
105+
if (droppedNode.id === dropHost.id) {
104106
return
105107
}
106-
108+
109+
if (!ItemCustomisations.isDropValid(droppedNode, dropHost)) return;
110+
107111
this.viewModel.removeTreeViewItem(droppedNode.id);
108-
109-
droppedNode.parentId = node.id;
110-
112+
droppedNode.parentId = dropHost.id;
111113
this.viewModel.addTreeViewItem(droppedNode);
112114
}
113115
}

0 commit comments

Comments
 (0)