Skip to content

Commit 4374cd9

Browse files
committed
Improve drag'n'drop a lot, bump to 3.0.0
Add support for dropping external stuff into the tree view and setting metadata when dragging starts via dragStartCallback. Also use const and private keywords where appropriate.
1 parent 36e2b0c commit 4374cd9

File tree

6 files changed

+236
-169
lines changed

6 files changed

+236
-169
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,17 @@ Check out the [live demo](http://sparklinlabs.github.io/dnd-tree-view/) and its
1818

1919
The `TreeView` constructor takes an optional second `options` parameter. It supports the following keys:
2020

21-
* `dropCallback` should be `null` or a function of the form `(dropInfo: { target: HTMLLIElement, where: string }, orderedNodes: HTMLElement[]) => boolean`. It'll be called when a drag'n'drop operation ends and must return whether to proceed with the reparenting/reordering or not.
21+
* `dragStartCallback` and `dropCallback` for handling drag'n'drop operations.
2222
* `multipleSelection` is a boolean indicating whether to enable multiple item selection or not.
2323

24-
See [index.d.ts](https://github.com/sparklinlabs/dnd-tree-view/blob/master/index.d.ts) for the full API.
24+
If `dragStartCallback` is not `null`, then dragging elements will be enabled.
25+
It must return a boolean indicating whether to start the drag operation or cancel it.
26+
You can use [`event.dataTransfer.setData(...)`](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations) to setup drag'n'drop metadata.
27+
28+
If `dropCallback` is not `null`, then dropping will be enabled.
29+
It must return a boolean indicating whether to proceed with the reparenting/reordering or not.
30+
31+
See [index.d.ts](https://github.com/sparklinlabs/dnd-tree-view/blob/master/index.d.ts) for the full API and arguments.
2532

2633
## Building from source
2734

index.d.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ declare class TreeView {
22
treeRoot: HTMLOListElement;
33
selectedNodes: HTMLLIElement[];
44

5-
constructor(container: HTMLElement, options?: { dropCallback?: TreeView.DropCallback, multipleSelection?: boolean });
5+
constructor(container: HTMLElement, options?: {
6+
dragStartCallback?: TreeView.DragStartCallback,
7+
dropCallback?: TreeView.DropCallback,
8+
multipleSelection?: boolean
9+
});
610
clearSelection(): void;
711
addToSelection(element: HTMLLIElement): void;
812
append(element: HTMLLIElement, type: string /* "item" or "group" */, parentGroupElement?: HTMLElement): void;
@@ -26,11 +30,13 @@ declare class TreeView {
2630
}
2731

2832
declare namespace TreeView {
33+
interface DragStartCallback {
34+
(event: DragEvent, nodeElt: HTMLLIElement): boolean;
35+
}
36+
2937
interface DropCallback {
30-
(dropInfo: {
31-
target: HTMLLIElement;
32-
where: string /* "above", "inside" or "below" */;
33-
},
38+
(event: DragEvent,
39+
dropLocation: { target: HTMLLIElement|HTMLOListElement; where: string /* "above", "inside" or "below" */; },
3440
orderedNodes: HTMLLIElement[]): boolean;
3541
}
3642
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "dnd-tree-view",
33
"description": "HTML5 tree view widget",
4-
"version": "2.4.2",
4+
"version": "3.0.0",
55
"author": "Elisée Maurer <elisee@sparklinlabs.com>",
66
"repository": {
77
"type": "git",

src/index.jade

Lines changed: 73 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,81 +16,93 @@ html
1616
button(data-type="group").create-group Create group
1717
button.remove-selected Remove selected
1818
.selected-nodes No items selected
19+
.dnd-result
1920
script.
20-
var treeView = new TreeView(document.querySelector("main"), { dropCallback: function(dropInfo, orderedNodes) { return true; } });
21+
var treeView = new TreeView(document.querySelector("main"), {
22+
dragStartCallback: function(event, node) {
23+
event.dataTransfer.setData("text/plain", node.textContent);
24+
return true;
25+
},
26+
dropCallback: function(event, dropLocation, orderedNodes) {
27+
document.querySelector("nav .dnd-result").textContent =
28+
event.dataTransfer.getData("text/plain") + " was dropped " +
29+
dropLocation.where + " " + dropLocation.target.textContent;
30+
return true;
31+
}
32+
});
2133

22-
function createItem(label) {
23-
itemElt = document.createElement("li");
34+
function createItem(label) {
35+
itemElt = document.createElement("li");
2436

25-
iconElt = document.createElement("div");
26-
iconElt.classList.add("icon");
27-
itemElt.appendChild(iconElt);
37+
iconElt = document.createElement("div");
38+
iconElt.classList.add("icon");
39+
itemElt.appendChild(iconElt);
2840

29-
spanElt = document.createElement("span");
30-
spanElt.textContent = label;
31-
itemElt.appendChild(spanElt);
41+
spanElt = document.createElement("span");
42+
spanElt.textContent = label;
43+
itemElt.appendChild(spanElt);
3244

33-
return itemElt;
34-
}
45+
return itemElt;
46+
}
3547

36-
function createGroup(label) {
37-
groupElt = document.createElement("li");
48+
function createGroup(label) {
49+
groupElt = document.createElement("li");
3850

39-
spanElt = document.createElement("span");
40-
spanElt.textContent = label;
41-
groupElt.appendChild(spanElt);
51+
spanElt = document.createElement("span");
52+
spanElt.textContent = label;
53+
groupElt.appendChild(spanElt);
4254

43-
return groupElt;
44-
}
55+
return groupElt;
56+
}
4557

46-
for (var i = 0; i < 3; i++) {
47-
var group = createGroup("Group " + (i+1));
48-
treeView.append(group, "group");
58+
for (var i = 0; i < 3; i++) {
59+
var group = createGroup("Group " + (i+1));
60+
treeView.append(group, "group");
4961

50-
for (var j = 0; j < 3; j++) {
51-
var item = createItem("Item " + (i*3+j+1));
52-
treeView.append(item, "item", group);
53-
}
62+
for (var j = 0; j < 3; j++) {
63+
var item = createItem("Item " + (i*3+j+1));
64+
treeView.append(item, "item", group);
5465
}
55-
56-
group = createGroup("Empty Group 1");
57-
treeView.append(group, "group", document.querySelector(".group"));
58-
59-
group = createGroup("Empty Group 2");
60-
treeView.append(group, "group", document.querySelector(".group:last-child"));
61-
62-
function onClickCreate(event) {
63-
var type = event.target.dataset.type;
64-
var label = prompt("Enter a name", "");
65-
if (label.length === 0) return;
66-
var node = (type === "item") ? createItem(label) : createGroup(label);
67-
68-
var parentNode = treeView.selectedNodes[0];
69-
if (parentNode != null && !parentNode.classList.contains("group")) {
70-
parentNode = parentNode.parentElement.classList.contains("children") ? parentNode.parentElement.previousSibling : null;
71-
}
72-
73-
treeView.append(node, type, parentNode);
66+
}
67+
68+
group = createGroup("Empty Group 1");
69+
treeView.append(group, "group", document.querySelector(".group"));
70+
71+
group = createGroup("Empty Group 2");
72+
treeView.append(group, "group", document.querySelector(".group:last-child"));
73+
74+
function onClickCreate(event) {
75+
var type = event.target.dataset.type;
76+
var label = prompt("Enter a name", "");
77+
if (label.length === 0) return;
78+
var node = (type === "item") ? createItem(label) : createGroup(label);
79+
80+
var parentNode = treeView.selectedNodes[0];
81+
if (parentNode != null && !parentNode.classList.contains("group")) {
82+
parentNode = parentNode.parentElement.classList.contains("children") ? parentNode.parentElement.previousSibling : null;
7483
}
7584

76-
document.querySelector("nav .create-item").addEventListener("click", onClickCreate);
77-
document.querySelector("nav .create-group").addEventListener("click", onClickCreate);
85+
treeView.append(node, type, parentNode);
86+
}
7887

79-
document.querySelector("nav .remove-selected").addEventListener("click", function() {
80-
while (treeView.selectedNodes.length > 0) {
81-
treeView.remove(treeView.selectedNodes[treeView.selectedNodes.length - 1]);
82-
}
83-
});
88+
document.querySelector("nav .create-item").addEventListener("click", onClickCreate);
89+
document.querySelector("nav .create-group").addEventListener("click", onClickCreate);
90+
91+
document.querySelector("nav .remove-selected").addEventListener("click", function() {
92+
while (treeView.selectedNodes.length > 0) {
93+
treeView.remove(treeView.selectedNodes[treeView.selectedNodes.length - 1]);
94+
}
95+
});
8496

85-
treeView.on("selectionChange", function() {
86-
var text;
87-
if (treeView.selectedNodes.length > 1) text = "" + treeView.selectedNodes.length + " items selected";
88-
else if (treeView.selectedNodes.length === 1) text = "1 item selected";
89-
else text = "No items selected";
97+
treeView.on("selectionChange", function() {
98+
var text;
99+
if (treeView.selectedNodes.length > 1) text = "" + treeView.selectedNodes.length + " items selected";
100+
else if (treeView.selectedNodes.length === 1) text = "1 item selected";
101+
else text = "No items selected";
90102

91-
document.querySelector("nav .selected-nodes").textContent = text;
92-
});
103+
document.querySelector("nav .selected-nodes").textContent = text;
104+
});
93105

94-
treeView.on("activate", function() {
95-
alert("Activated " + treeView.selectedNodes[0].querySelector("span").textContent);
96-
});
106+
treeView.on("activate", function() {
107+
alert("Activated " + treeView.selectedNodes[0].querySelector("span").textContent);
108+
});

src/index.styl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ nav {
4242
margin-right: 0.5em;
4343
padding: 0.5em;
4444
}
45+
46+
.dnd-result {
47+
margin-left: 0.5em;
48+
flex: 1;
49+
text-align: right;
50+
color: #666;
51+
}
4552
}
4653

4754
ol.tree {
@@ -55,6 +62,15 @@ ol.tree {
5562

5663
* { -webkit-user-select: none; }
5764

65+
&.drop-inside:before {
66+
position: absolute;
67+
content: "";
68+
border-top: 1px solid #888;
69+
left: 0.25em;
70+
right: 0.25em;
71+
top: 0.25em;
72+
}
73+
5874
ol {
5975
list-style: none;
6076
margin: 0;

0 commit comments

Comments
 (0)