0
# Drag & Drop Operations
1
2
Advanced drag and drop support with customizable constraints, foreign element support, and visual feedback during operations. The DnD plugin enables intuitive tree manipulation through mouse and touch interactions.
3
4
## Capabilities
5
6
### DnD Configuration
7
8
Configuration options for drag and drop behavior.
9
10
```javascript { .api }
11
/**
12
* Drag and Drop plugin configuration
13
*/
14
interface DnDConfig {
15
/** Enable copy mode (hold Ctrl to copy instead of move) */
16
copy?: boolean;
17
/** Time before opening closed nodes during drag (ms, default: 500) */
18
open_timeout?: number;
19
/** Time before moving node to new position (ms, default: 500) */
20
move_timeout?: number;
21
/** Function or boolean to determine if node is draggable */
22
is_draggable?: boolean|function;
23
/** Check constraints while dragging (default: true) */
24
check_while_dragging?: boolean;
25
/** Allow dragging multiple selected nodes (default: true) */
26
drag_selection?: boolean;
27
/** Enable touch support (boolean or "selected" for selected nodes only) */
28
touch?: boolean|string;
29
/** Larger drop targets for easier dropping (default: false) */
30
large_drop_target?: boolean;
31
/** Larger drag handles for easier dragging (default: false) */
32
large_drag_target?: boolean;
33
/** Use HTML5 drag and drop API (default: true) */
34
use_html5?: boolean;
35
}
36
37
// Usage in tree initialization
38
const config = {
39
"plugins": ["dnd"],
40
"dnd": {
41
"copy": false,
42
"check_while_dragging": true,
43
"drag_selection": true,
44
"touch": true,
45
"large_drop_target": false
46
}
47
};
48
```
49
50
**Usage Examples:**
51
52
```javascript
53
// Initialize tree with drag and drop
54
$("#tree").jstree({
55
"core": {
56
"data": [
57
"Item 1", "Item 2",
58
{"text": "Folder", "children": ["Sub Item 1", "Sub Item 2"]}
59
],
60
"check_callback": true // Enable modifications
61
},
62
"plugins": ["dnd"],
63
"dnd": {
64
"copy": false, // Move by default
65
"check_while_dragging": true,
66
"drag_selection": true
67
}
68
});
69
70
// Get instance for DnD operations
71
const tree = $("#tree").jstree(true);
72
```
73
74
### Draggable Node Control
75
76
Methods and configuration for controlling which nodes can be dragged.
77
78
```javascript { .api }
79
/**
80
* Function to determine if a node is draggable
81
* @param nodes - Array of nodes being dragged
82
* @param event - Original drag event
83
* @returns True if nodes can be dragged
84
*/
85
type IsDraggableFunction = (nodes: Array<object>, event: Event) => boolean;
86
87
/**
88
* Configuration for draggable behavior
89
*/
90
interface DraggableConfig {
91
/** Global draggable setting */
92
is_draggable: boolean|IsDraggableFunction;
93
/** Per-node draggable setting in node data */
94
node_draggable?: boolean;
95
}
96
```
97
98
**Usage Examples:**
99
100
```javascript
101
// Global draggable function
102
$("#tree").jstree({
103
"plugins": ["dnd"],
104
"dnd": {
105
"is_draggable": function(nodes, e) {
106
// Only allow dragging leaf nodes
107
return nodes.every(node => tree.is_leaf(node));
108
}
109
}
110
});
111
112
// Per-node draggable setting
113
$("#tree").jstree({
114
"core": {
115
"data": [
116
{"text": "Draggable Item", "draggable": true},
117
{"text": "Fixed Item", "draggable": false},
118
{"text": "Default Item"} // Uses global setting
119
]
120
},
121
"plugins": ["dnd"]
122
});
123
124
// Dynamic draggable control
125
$("#tree").jstree({
126
"plugins": ["dnd"],
127
"dnd": {
128
"is_draggable": function(nodes, e) {
129
// Allow dragging only if user has permission
130
return nodes.every(node =>
131
node.li_attr && node.li_attr['data-user-can-move'] === 'true'
132
);
133
}
134
}
135
});
136
```
137
138
### Drop Target Control
139
140
Configuration for controlling where nodes can be dropped.
141
142
```javascript { .api }
143
/**
144
* Check callback function for validating drop operations
145
* @param operation - Type of operation ("move_node", "copy_node")
146
* @param node - Node being moved/copied
147
* @param parent - Target parent node
148
* @param position - Position within parent
149
* @param more - Additional operation data including DnD info
150
* @returns True if operation is allowed
151
*/
152
type CheckCallback = (
153
operation: string,
154
node: object,
155
parent: object,
156
position: number|string,
157
more: object
158
) => boolean;
159
```
160
161
**Usage Examples:**
162
163
```javascript
164
// Restrict drop targets with check_callback
165
$("#tree").jstree({
166
"core": {
167
"check_callback": function(operation, node, parent, position, more) {
168
// Allow drops only into folders
169
if (operation === "move_node") {
170
return parent.type === "folder";
171
}
172
return true;
173
}
174
},
175
"plugins": ["dnd", "types"],
176
"types": {
177
"folder": {"icon": "fa fa-folder"},
178
"file": {"icon": "fa fa-file"}
179
}
180
});
181
182
// Complex drop validation
183
$("#tree").jstree({
184
"core": {
185
"check_callback": function(op, node, parent, pos, more) {
186
if (op === "move_node") {
187
// Prevent dropping parents into their children
188
if (more.core && more.dnd) {
189
return !tree.is_ancestor(node, parent);
190
}
191
192
// Prevent certain node types from being parents
193
if (parent.type === "file") {
194
return false;
195
}
196
197
// Limit number of children
198
if (tree.get_children_dom(parent).length >= 10) {
199
return false;
200
}
201
}
202
return true;
203
}
204
},
205
"plugins": ["dnd", "types"]
206
});
207
```
208
209
### Copy vs Move Operations
210
211
Configuration and behavior for copy and move operations.
212
213
```javascript { .api }
214
/**
215
* Copy/Move operation configuration
216
*/
217
interface CopyMoveConfig {
218
/** Default operation mode */
219
copy: boolean;
220
/** Modifier keys for copy mode */
221
copy_modifier?: string; // "ctrl", "alt", "shift", "meta"
222
/** Always copy specific node types */
223
always_copy?: Array<string>;
224
/** Never copy specific node types */
225
never_copy?: Array<string>;
226
}
227
```
228
229
**Usage Examples:**
230
231
```javascript
232
// Copy by default, move with Shift key
233
$("#tree").jstree({
234
"plugins": ["dnd"],
235
"dnd": {
236
"copy": true, // Copy by default
237
"copy_modifier": "shift" // Hold Shift to move instead
238
}
239
});
240
241
// Copy specific node types automatically
242
$("#tree").jstree({
243
"plugins": ["dnd", "types"],
244
"dnd": {
245
"copy": false, // Move by default
246
"always_copy": ["template", "reference"] // Always copy these types
247
},
248
"types": {
249
"template": {"icon": "fa fa-copy"},
250
"reference": {"icon": "fa fa-link"},
251
"regular": {"icon": "fa fa-file"}
252
}
253
});
254
255
// Listen for copy/move operations
256
$("#tree").on("move_node.jstree", function(e, data) {
257
if (data.original) {
258
console.log("Node moved from", data.original.parent, "to", data.parent);
259
}
260
});
261
262
$("#tree").on("copy_node.jstree", function(e, data) {
263
console.log("Node copied:", data.node.text);
264
});
265
```
266
267
### Touch and Mobile Support
268
269
Configuration for touch devices and mobile interactions.
270
271
```javascript { .api }
272
/**
273
* Touch support configuration
274
*/
275
interface TouchConfig {
276
/** Enable touch support */
277
touch: boolean|"selected";
278
/** Touch drag threshold (pixels) */
279
touch_threshold?: number;
280
/** Long press duration for drag start (ms) */
281
long_press_timeout?: number;
282
/** Enable touch feedback */
283
touch_feedback?: boolean;
284
}
285
```
286
287
**Usage Examples:**
288
289
```javascript
290
// Full touch support
291
$("#tree").jstree({
292
"plugins": ["dnd"],
293
"dnd": {
294
"touch": true,
295
"large_drop_target": true, // Easier targeting on mobile
296
"large_drag_target": true
297
}
298
});
299
300
// Touch support for selected nodes only
301
$("#tree").jstree({
302
"plugins": ["dnd"],
303
"dnd": {
304
"touch": "selected", // Only selected nodes are draggable on touch
305
"drag_selection": true
306
}
307
});
308
```
309
310
### Foreign Element Support
311
312
Support for dragging elements from outside the tree.
313
314
```javascript { .api }
315
/**
316
* Foreign element configuration
317
*/
318
interface ForeignElementConfig {
319
/** Allow dropping foreign elements */
320
accept_foreign?: boolean;
321
/** Selector for acceptable foreign elements */
322
foreign_selector?: string;
323
/** Function to process foreign element data */
324
foreign_processor?: function;
325
}
326
```
327
328
**Usage Examples:**
329
330
```javascript
331
// Accept foreign elements
332
$("#tree").jstree({
333
"plugins": ["dnd"],
334
"dnd": {
335
"accept_foreign": true,
336
"foreign_selector": ".draggable-item",
337
"foreign_processor": function(element, target, position) {
338
// Convert foreign element to tree node
339
return {
340
"text": element.text(),
341
"data": element.data(),
342
"type": element.attr("data-type") || "default"
343
};
344
}
345
}
346
});
347
348
// Make external elements draggable to tree
349
$(".draggable-item").draggable({
350
"helper": "clone",
351
"revert": "invalid"
352
});
353
354
// Handle foreign drops
355
$("#tree").on("create_node.jstree", function(e, data) {
356
if (data.node.original && data.node.original.foreign) {
357
console.log("Foreign element dropped:", data.node.text);
358
}
359
});
360
```
361
362
### Visual Feedback
363
364
Configuration for drag and drop visual indicators.
365
366
```javascript { .api }
367
/**
368
* Visual feedback configuration
369
*/
370
interface VisualFeedbackConfig {
371
/** Show drop zones during drag */
372
show_drop_zones?: boolean;
373
/** Highlight valid drop targets */
374
highlight_targets?: boolean;
375
/** Custom drag helper element */
376
drag_helper?: function;
377
/** Drop marker styling */
378
drop_marker?: object;
379
}
380
```
381
382
**Usage Examples:**
383
384
```javascript
385
// Enhanced visual feedback
386
$("#tree").jstree({
387
"plugins": ["dnd"],
388
"dnd": {
389
"large_drop_target": true,
390
"show_drop_zones": true,
391
"highlight_targets": true
392
}
393
});
394
395
// Custom drag helper
396
$("#tree").jstree({
397
"plugins": ["dnd"],
398
"dnd": {
399
"drag_helper": function(nodes) {
400
const helper = $('<div class="custom-drag-helper">');
401
helper.text(nodes.length + " item(s) selected");
402
return helper;
403
}
404
}
405
});
406
```
407
408
### DnD Events
409
410
Events triggered during drag and drop operations.
411
412
```javascript { .api }
413
// DnD-specific events
414
"dnd_start.vakata": DnDStartEvent;
415
"dnd_move.vakata": DnDMoveEvent;
416
"dnd_stop.vakata": DnDStopEvent;
417
418
interface DnDStartEvent {
419
element: jQuery;
420
target: jQuery;
421
helper: jQuery;
422
}
423
424
interface DnDMoveEvent {
425
element: jQuery;
426
target: jQuery;
427
helper: jQuery;
428
event: Event;
429
}
430
431
interface DnDStopEvent {
432
element: jQuery;
433
target: jQuery;
434
helper: jQuery;
435
event: Event;
436
}
437
```
438
439
**Usage Examples:**
440
441
```javascript
442
// Listen for DnD events
443
$(document).on("dnd_start.vakata", function(e, data) {
444
console.log("Drag started");
445
$("body").addClass("dragging");
446
});
447
448
$(document).on("dnd_move.vakata", function(e, data) {
449
// Update custom drop indicators
450
updateDropZones(data.target);
451
});
452
453
$(document).on("dnd_stop.vakata", function(e, data) {
454
console.log("Drag stopped");
455
$("body").removeClass("dragging");
456
});
457
458
// Tree-specific DnD events
459
$("#tree").on("move_node.jstree", function(e, data) {
460
console.log("Node moved:", {
461
node: data.node.text,
462
old_parent: data.old_parent,
463
new_parent: data.parent,
464
old_position: data.old_position,
465
new_position: data.position
466
});
467
});
468
```
469
470
### Advanced DnD Customization
471
472
Advanced configuration options for complex drag and drop scenarios.
473
474
```javascript { .api }
475
/**
476
* Advanced DnD configuration
477
*/
478
interface AdvancedDnDConfig {
479
/** Custom drag start validation */
480
drag_start?: function;
481
/** Custom drop validation */
482
drop_finish?: function;
483
/** Multi-tree support */
484
multi_tree?: boolean;
485
/** Cross-frame dragging */
486
cross_frame?: boolean;
487
/** Drag constraints */
488
constraints?: object;
489
}
490
```
491
492
**Usage Examples:**
493
494
```javascript
495
// Multi-tree drag and drop
496
$("#tree1, #tree2").jstree({
497
"plugins": ["dnd"],
498
"dnd": {
499
"multi_tree": true,
500
"check_while_dragging": true
501
}
502
});
503
504
// Custom drag constraints
505
$("#tree").jstree({
506
"plugins": ["dnd"],
507
"dnd": {
508
"constraints": {
509
"max_depth": 5,
510
"allowed_parents": ["folder", "category"],
511
"forbidden_children": ["readonly"]
512
},
513
"drag_start": function(nodes, event) {
514
// Custom validation before drag starts
515
return nodes.every(node => !node.li_attr.readonly);
516
}
517
}
518
});
519
520
// Cross-frame dragging setup
521
$("#tree").jstree({
522
"plugins": ["dnd"],
523
"dnd": {
524
"cross_frame": true,
525
"use_html5": true
526
}
527
});
528
```
529
530
## Types
531
532
```javascript { .api }
533
// DnD-specific node extensions
534
interface DraggableNode extends TreeNode {
535
draggable?: boolean;
536
droppable?: boolean;
537
dnd_data?: {
538
origin?: string;
539
foreign?: boolean;
540
[key: string]: any;
541
};
542
}
543
544
// DnD plugin settings
545
interface DnDSettings {
546
copy: boolean;
547
open_timeout: number;
548
move_timeout: number;
549
is_draggable: boolean|function;
550
check_while_dragging: boolean;
551
drag_selection: boolean;
552
touch: boolean|string;
553
large_drop_target: boolean;
554
large_drag_target: boolean;
555
use_html5: boolean;
556
}
557
558
// Drag operation data
559
interface DragData {
560
nodes: Array<object>;
561
event: Event;
562
helper: jQuery;
563
origin: string;
564
is_copy: boolean;
565
is_foreign: boolean;
566
}
567
```