|
25 | 25 | clearButton: false, |
26 | 26 | scrollContainer: null, |
27 | 27 | defaultDropdownHeight: 300, |
| 28 | + dragAndDrop: false, |
28 | 29 | }; |
29 | 30 |
|
30 | 31 | var constants = { |
|
66 | 67 | events: { |
67 | 68 | SelectionChanged: "selectionChanged", |
68 | 69 | SelectionChanging: "selectionChanging", |
| 70 | + NodeOrderChanged: "nodeOrderChanged", |
69 | 71 | _NodeSelected: "_nodeSelected", |
70 | 72 | EscapePressed: "_escapePressed", |
71 | 73 | HoverChanged: "_hoverChanged", |
|
173 | 175 | return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); |
174 | 176 | } |
175 | 177 |
|
| 178 | + class DragAndDropHandler { |
| 179 | + constructor(setNodeIndex) { |
| 180 | + this.setNodeIndex = setNodeIndex; |
| 181 | + this.boundOnDragStart = this.onDragStart.bind(this); |
| 182 | + this.boundOnDragOver = this.onDragOver.bind(this); |
| 183 | + this.boundOnDrop = this.onDrop.bind(this); |
| 184 | + } |
| 185 | + initialize(liElement) { |
| 186 | + liElement.setAttribute("draggable", "true"); |
| 187 | + liElement.addEventListener("dragstart", this.boundOnDragStart); |
| 188 | + liElement.addEventListener("dragover", this.boundOnDragOver); |
| 189 | + liElement.addEventListener("drop", this.boundOnDrop); |
| 190 | + } |
| 191 | + destroy(liElement) { |
| 192 | + liElement.removeAttribute("draggable"); |
| 193 | + liElement.removeEventListener("dragstart", this.boundOnDragStart); |
| 194 | + liElement.removeEventListener("dragover", this.boundOnDragOver); |
| 195 | + liElement.removeEventListener("drop", this.boundOnDrop); |
| 196 | + } |
| 197 | + onDragStart(e) { |
| 198 | + var _a; |
| 199 | + const target = e.target; |
| 200 | + if (!target.hasAttribute("draggable")) { |
| 201 | + return; |
| 202 | + } |
| 203 | + if (e.dataTransfer) { |
| 204 | + e.dataTransfer.effectAllowed = "move"; |
| 205 | + target.setAttribute("data-dragging", "true"); |
| 206 | + (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.setData("text/plain", target.id); |
| 207 | + } |
| 208 | + } |
| 209 | + onDragOver(e) { |
| 210 | + var _a, _b, _c, _d; |
| 211 | + e.preventDefault(); |
| 212 | + const target = this.getTargetListItem(e.target); |
| 213 | + if (!target) { |
| 214 | + return; |
| 215 | + } |
| 216 | + const { elements: sameLevelNodes, ids: sameLevelNodeIds } = this.getSameLevelNodes(target); |
| 217 | + const draggedId = (_a = sameLevelNodes.find((x) => x.getAttribute("data-dragging") === "true")) === null || _a === void 0 ? void 0 : _a.id; |
| 218 | + if (!draggedId) { |
| 219 | + return; |
| 220 | + } |
| 221 | + if (!sameLevelNodeIds.includes(draggedId)) { |
| 222 | + return; |
| 223 | + } |
| 224 | + const toDrop = document.getElementById(draggedId); |
| 225 | + if (!toDrop) { |
| 226 | + return; |
| 227 | + } |
| 228 | + const bounding = target.getBoundingClientRect(); |
| 229 | + const offset = bounding.y + bounding.height / 2; |
| 230 | + if (e.clientY - offset > 0) { |
| 231 | + (_b = target.parentElement) === null || _b === void 0 ? void 0 : _b.insertBefore(toDrop, target.nextSibling); |
| 232 | + } |
| 233 | + else { |
| 234 | + (_c = target.parentElement) === null || _c === void 0 ? void 0 : _c.insertBefore(toDrop, target); |
| 235 | + } |
| 236 | + (_d = e.dataTransfer) === null || _d === void 0 ? void 0 : _d.setData("text/plain", JSON.stringify({ id: toDrop.id, newIndex: sameLevelNodeIds.indexOf(toDrop.id) })); |
| 237 | + } |
| 238 | + onDrop(e) { |
| 239 | + var _a, _b; |
| 240 | + e.preventDefault(); |
| 241 | + e.stopPropagation(); |
| 242 | + const droppedId = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData("text/plain"); |
| 243 | + if (droppedId) { |
| 244 | + (_b = document.getElementById(droppedId)) === null || _b === void 0 ? void 0 : _b.removeAttribute("data-dragging"); |
| 245 | + const { ids } = this.getSameLevelNodes(document.getElementById(droppedId)); |
| 246 | + this.setNodeIndex(droppedId, ids.indexOf(droppedId)); |
| 247 | + } |
| 248 | + } |
| 249 | + getTargetListItem(t) { |
| 250 | + while (t.parentElement && t.tagName !== "LI") { |
| 251 | + t = t.parentElement; |
| 252 | + } |
| 253 | + return t; |
| 254 | + } |
| 255 | + getSameLevelNodes(target) { |
| 256 | + var _a; |
| 257 | + const sameLevelNodes = Array.from(((_a = target.parentElement) === null || _a === void 0 ? void 0 : _a.children) || []); |
| 258 | + const sameLevelNodeIds = sameLevelNodes.map((x) => x.id); |
| 259 | + return { elements: sameLevelNodes, ids: sameLevelNodeIds }; |
| 260 | + } |
| 261 | + } |
| 262 | + |
176 | 263 | class BaseTree { |
177 | 264 | constructor(element, config, dataService, eventManager, readOnly) { |
178 | 265 | this.element = element; |
|
185 | 272 | this.searchTextInput = null; |
186 | 273 | this.searchTextInputEvent = null; |
187 | 274 | this.keyEventHandler = new KeyEventHandler(this.eventManager, this.dataService, this.readOnly); |
| 275 | + this.dragAndDropHandler = new DragAndDropHandler((uid, newIndex) => { |
| 276 | + this.dataService.setNodeIndex(uid, newIndex); |
| 277 | + this.eventManager.publish(constants.events.NodeOrderChanged, this.dataService.getNodes()); |
| 278 | + }); |
188 | 279 | this.subscription = this.eventManager.subscribe(constants.events.HoverChanged, (n) => this.hoverNode(n)); |
189 | 280 | } |
190 | 281 | destroy() { |
191 | 282 | this.deactivateKeyListener(); |
| 283 | + if (this.config.dragAndDrop) { |
| 284 | + this.removeDragAndDropListeners(); |
| 285 | + } |
192 | 286 | if (this.subscription) { |
193 | 287 | this.subscription.dispose(); |
194 | 288 | this.subscription = null; |
|
208 | 302 | deactivateKeyListener() { |
209 | 303 | this.keyEventHandler.destroy(); |
210 | 304 | } |
| 305 | + removeDragAndDropListeners() { |
| 306 | + const nodeContainer = this.getNodeContainer(); |
| 307 | + if (nodeContainer) { |
| 308 | + Array.from(nodeContainer.querySelectorAll("li")).forEach((x) => this.dragAndDropHandler.destroy(x)); |
| 309 | + } |
| 310 | + } |
211 | 311 | setNodeUiState(node, current, cssClass) { |
212 | 312 | var _a, _b, _c; |
213 | 313 | if (!node || current !== node.value) { |
|
266 | 366 | renderTree() { |
267 | 367 | const nodeContainer = this.getNodeContainer(); |
268 | 368 | if (nodeContainer) { |
| 369 | + if (this.config.dragAndDrop) { |
| 370 | + this.removeDragAndDropListeners(); |
| 371 | + } |
269 | 372 | nodeContainer.innerHTML = ""; |
270 | 373 | nodeContainer.appendChild(this.renderUnorderedList(this.dataService.allNodes)); |
271 | 374 | } |
|
279 | 382 | highlightRegex = new RegExp(`(${escapeRegex((_b = this.searchTextInput) === null || _b === void 0 ? void 0 : _b.value)})`, "ig"); |
280 | 383 | } |
281 | 384 | nodes.forEach((node) => { |
282 | | - var _a; |
| 385 | + var _a, _b; |
283 | 386 | if (node.hidden) { |
284 | 387 | return; |
285 | 388 | } |
286 | 389 | const hasChildren = ((_a = node.children) === null || _a === void 0 ? void 0 : _a.length) > 0; |
287 | 390 | const liElement = document.createElement("li"); |
288 | 391 | liElement.id = node.uid; |
| 392 | + if (this.config.dragAndDrop && !((_b = this.searchTextInput) === null || _b === void 0 ? void 0 : _b.value)) { |
| 393 | + this.dragAndDropHandler.initialize(liElement); |
| 394 | + } |
289 | 395 | const lineWrapperDiv = document.createElement("div"); |
290 | 396 | lineWrapperDiv.classList.add(constants.classNames.SimpleTreeNodeWrapper); |
291 | 397 | lineWrapperDiv.addEventListener("mouseover", () => this.hoverNode(node)); |
|
381 | 487 | } |
382 | 488 | } |
383 | 489 | collapseAllNodes(flag) { |
384 | | - this.dataService.getAllNodes().forEach((t) => this.collapseNode(t, flag, false)); |
| 490 | + this.dataService.getNodesInternal().forEach((t) => this.collapseNode(t, flag, false)); |
385 | 491 | this.renderTree(); |
386 | 492 | } |
387 | 493 | setReadOnly(readOnly) { |
|
511 | 617 | clear() { |
512 | 618 | this.allNodes = []; |
513 | 619 | } |
514 | | - getAllNodes() { |
| 620 | + getNodesInternal() { |
515 | 621 | return this.allNodes; |
516 | 622 | } |
| 623 | + getNodes() { |
| 624 | + return this.allNodes.map(this.copyNode); |
| 625 | + } |
517 | 626 | getNode(value) { |
518 | 627 | const nodeToReturn = this.getNodeInternal(this.allNodes, value); |
519 | 628 | if (nodeToReturn) { |
|
593 | 702 | node.label = newLabel; |
594 | 703 | } |
595 | 704 | } |
596 | | - getParentForNode(nodes, value) { |
| 705 | + getParentForNode(nodes, comparisonValue, predicate = null) { |
| 706 | + if (!predicate) { |
| 707 | + predicate = (n) => n.value === comparisonValue; |
| 708 | + } |
597 | 709 | for (const node of nodes) { |
598 | | - if (node.children && node.children.some((n) => n.value === value)) { |
| 710 | + if (node.children && node.children.some(predicate)) { |
599 | 711 | return node; |
600 | 712 | } |
601 | 713 | let parent = null; |
602 | 714 | if (node.children) { |
603 | | - parent = this.getParentForNode(node.children, value); |
| 715 | + parent = this.getParentForNode(node.children, comparisonValue, predicate); |
604 | 716 | } |
605 | 717 | if (parent) { |
606 | 718 | return parent; |
|
808 | 920 | } |
809 | 921 | return `${this.treeInstanceId}-${Math.abs(hash)}`; |
810 | 922 | } |
| 923 | + setNodeIndex(uid, newIndex) { |
| 924 | + const node = this.allNodes.find((node) => node.uid === uid); |
| 925 | + if (node) { |
| 926 | + this.allNodes.splice(this.allNodes.indexOf(node), 1); |
| 927 | + this.allNodes.splice(newIndex, 0, node); |
| 928 | + } |
| 929 | + else { |
| 930 | + const parent = this.getParentForNode(this.allNodes, uid, (n) => n.uid === uid); |
| 931 | + if (parent) { |
| 932 | + const childNode = parent.children.find((node) => node.uid === uid); |
| 933 | + parent.children.splice(parent.children.indexOf(childNode), 1); |
| 934 | + parent.children.splice(newIndex, 0, childNode); |
| 935 | + } |
| 936 | + } |
| 937 | + console.log(this.allNodes); |
| 938 | + } |
811 | 939 | } |
812 | 940 |
|
813 | 941 | class CommonTreeLogic { |
|
0 commit comments