0
# Additional Plugins
1
2
State management, node types, sorting, context menus, and other specialized functionality. These plugins extend jsTree's core capabilities with additional features for enhanced tree management and user interaction.
3
4
## Capabilities
5
6
### State Plugin
7
8
Persistent state management for preserving tree state across sessions.
9
10
```javascript { .api }
11
/**
12
* State plugin configuration
13
*/
14
interface StateConfig {
15
/** Storage key for state data (default: "jstree") */
16
key?: string;
17
/** Events that trigger state save (default: ["changed.jstree", "open_node.jstree", "close_node.jstree"]) */
18
events?: Array<string>;
19
/** Time to live for state data in seconds (default: 3600) */
20
ttl?: number;
21
/** Custom filter function to determine what to save */
22
filter?: function;
23
/** Preserve loaded state on refresh (default: false) */
24
preserve_loaded?: boolean;
25
}
26
27
/**
28
* Save current tree state to storage
29
*/
30
save_state(): void;
31
32
/**
33
* Restore tree state from storage
34
*/
35
restore_state(): void;
36
37
/**
38
* Get current tree state object
39
* @returns State object containing selected nodes, opened nodes, etc.
40
*/
41
get_state(): object;
42
43
/**
44
* Set tree state from object
45
* @param state - State object to restore
46
* @param callback - Function to call when state is restored
47
*/
48
set_state(state: object, callback?: function): void;
49
50
/**
51
* Clear saved state from storage
52
*/
53
clear_state(): void;
54
```
55
56
**Usage Examples:**
57
58
```javascript
59
// Initialize with state plugin
60
$("#tree").jstree({
61
"plugins": ["state"],
62
"state": {
63
"key": "my-tree-state",
64
"events": ["changed.jstree", "open_node.jstree", "close_node.jstree"],
65
"ttl": 7200, // 2 hours
66
"filter": function(state) {
67
// Only save certain parts of state
68
return {
69
core: {
70
selected: state.core.selected,
71
open: state.core.open
72
}
73
};
74
}
75
}
76
});
77
78
// Manual state operations
79
const tree = $("#tree").jstree(true);
80
81
// Save current state
82
tree.save_state();
83
84
// Get state object
85
const currentState = tree.get_state();
86
console.log("Current state:", currentState);
87
88
// Restore specific state
89
tree.set_state({
90
core: {
91
selected: ["node_1", "node_2"],
92
open: ["parent_1", "parent_2"]
93
}
94
});
95
96
// Clear saved state
97
tree.clear_state();
98
```
99
100
### Types Plugin
101
102
Node type system with type-specific icons, behavior, and validation.
103
104
```javascript { .api }
105
/**
106
* Types plugin configuration
107
*/
108
interface TypesConfig {
109
/** Default node type (default: "default") */
110
default?: string;
111
/** Type definitions */
112
types?: {[type: string]: TypeDefinition};
113
}
114
115
interface TypeDefinition {
116
/** Maximum number of children (default: -1 for unlimited) */
117
max_children?: number;
118
/** Maximum depth for this type (default: -1 for unlimited) */
119
max_depth?: number;
120
/** Valid children types (default: -1 for all types) */
121
valid_children?: Array<string>|number;
122
/** Icon class or URL for this type */
123
icon?: string|boolean;
124
/** Additional node attributes */
125
li_attr?: object;
126
/** Additional anchor attributes */
127
a_attr?: object;
128
}
129
130
/**
131
* Get node type
132
* @param obj - Node to get type for
133
* @returns Node type string
134
*/
135
get_type(obj: string|object): string;
136
137
/**
138
* Set node type
139
* @param obj - Node to set type for
140
* @param type - New type name
141
* @returns True on success
142
*/
143
set_type(obj: string|object, type: string): boolean;
144
```
145
146
**Usage Examples:**
147
148
```javascript
149
// Initialize with types
150
$("#tree").jstree({
151
"plugins": ["types"],
152
"types": {
153
"default": {
154
"icon": "fa fa-file"
155
},
156
"folder": {
157
"icon": "fa fa-folder",
158
"valid_children": ["folder", "file"],
159
"max_children": 50
160
},
161
"file": {
162
"icon": "fa fa-file-o",
163
"valid_children": [],
164
"max_children": 0
165
},
166
"image": {
167
"icon": "fa fa-image",
168
"valid_children": [],
169
"li_attr": {"class": "image-node"}
170
}
171
},
172
"core": {
173
"data": [
174
{"text": "Documents", "type": "folder", "children": [
175
{"text": "report.pdf", "type": "file"},
176
{"text": "photo.jpg", "type": "image"}
177
]}
178
]
179
}
180
});
181
182
// Type operations
183
const tree = $("#tree").jstree(true);
184
185
// Get node type
186
const nodeType = tree.get_type("node_1");
187
console.log("Node type:", nodeType);
188
189
// Set node type
190
tree.set_type("node_1", "folder");
191
192
// Create typed nodes
193
tree.create_node("#", {
194
"text": "New Folder",
195
"type": "folder"
196
});
197
```
198
199
### Sort Plugin
200
201
Automatic and manual sorting of tree nodes.
202
203
```javascript { .api }
204
/**
205
* Sort plugin configuration
206
*/
207
interface SortConfig {
208
/** Custom sort function */
209
sort?: function;
210
/** Case sensitive sorting (default: false) */
211
case_sensitive?: boolean;
212
/** Natural sorting (handles numbers correctly) */
213
natural?: boolean;
214
}
215
216
/**
217
* Sort nodes alphabetically
218
* @param obj - Node to sort children of (default: root)
219
* @param deep - Also sort all descendants (default: false)
220
*/
221
sort(obj?: string|object, deep?: boolean): void;
222
```
223
224
**Usage Examples:**
225
226
```javascript
227
// Initialize with sorting
228
$("#tree").jstree({
229
"plugins": ["sort"],
230
"sort": {
231
"case_sensitive": false,
232
"natural": true,
233
"sort": function(a, b) {
234
// Custom sort logic
235
const nodeA = this.get_node(a);
236
const nodeB = this.get_node(b);
237
238
// Sort folders before files
239
if (nodeA.type === "folder" && nodeB.type !== "folder") return -1;
240
if (nodeA.type !== "folder" && nodeB.type === "folder") return 1;
241
242
// Then sort alphabetically
243
return nodeA.text.toLowerCase().localeCompare(nodeB.text.toLowerCase());
244
}
245
}
246
});
247
248
// Manual sorting
249
const tree = $("#tree").jstree(true);
250
tree.sort(); // Sort root level
251
tree.sort("folder_1", true); // Sort folder and all descendants
252
```
253
254
### Context Menu Plugin
255
256
Customizable right-click context menus with conditional items.
257
258
```javascript { .api }
259
/**
260
* Context menu plugin configuration
261
*/
262
interface ContextMenuConfig {
263
/** Select node when showing context menu (default: true) */
264
select_node?: boolean;
265
/** Show menu at node position vs cursor position (default: true) */
266
show_at_node?: boolean;
267
/** Menu items configuration */
268
items?: object|function;
269
}
270
271
interface ContextMenuItem {
272
/** Display label */
273
label?: string;
274
/** Icon class */
275
icon?: string;
276
/** Action function */
277
action?: function;
278
/** Submenu items */
279
submenu?: {[key: string]: ContextMenuItem};
280
/** Separator */
281
separator_before?: boolean;
282
separator_after?: boolean;
283
/** Conditional visibility */
284
visible?: boolean|function;
285
/** Conditional enablement */
286
disabled?: boolean|function;
287
/** Custom class name */
288
_class?: string;
289
}
290
291
/**
292
* Show context menu programmatically
293
* @param obj - Node to show menu for
294
* @param x - X coordinate (optional)
295
* @param y - Y coordinate (optional)
296
* @param e - Original event (optional)
297
*/
298
show_contextmenu(obj: string|object, x?: number, y?: number, e?: Event): void;
299
```
300
301
**Usage Examples:**
302
303
```javascript
304
// Initialize with context menu
305
$("#tree").jstree({
306
"plugins": ["contextmenu"],
307
"contextmenu": {
308
"items": function(node) {
309
return {
310
"create": {
311
"label": "Create",
312
"icon": "fa fa-plus",
313
"action": function(data) {
314
const inst = $.jstree.reference(data.reference);
315
const obj = inst.get_node(data.reference);
316
inst.create_node(obj, {}, "last", function(new_node) {
317
setTimeout(function() { inst.edit(new_node); }, 0);
318
});
319
}
320
},
321
"rename": {
322
"label": "Rename",
323
"icon": "fa fa-edit",
324
"action": function(data) {
325
const inst = $.jstree.reference(data.reference);
326
const obj = inst.get_node(data.reference);
327
inst.edit(obj);
328
}
329
},
330
"delete": {
331
"label": "Delete",
332
"icon": "fa fa-trash",
333
"separator_before": true,
334
"action": function(data) {
335
const inst = $.jstree.reference(data.reference);
336
const obj = inst.get_node(data.reference);
337
if (inst.is_selected(obj)) {
338
inst.delete_node(inst.get_selected());
339
} else {
340
inst.delete_node(obj);
341
}
342
}
343
},
344
"properties": {
345
"label": "Properties",
346
"icon": "fa fa-info",
347
"separator_before": true,
348
"visible": function(key, opt) {
349
// Only show for certain node types
350
return node.type === "file";
351
},
352
"action": function(data) {
353
showNodeProperties(data.reference);
354
}
355
}
356
};
357
}
358
}
359
});
360
361
// Dynamic context menu
362
$("#tree").jstree({
363
"plugins": ["contextmenu", "types"],
364
"contextmenu": {
365
"items": function(node) {
366
const items = {};
367
368
// Add type-specific items
369
if (node.type === "folder") {
370
items.create_folder = {
371
"label": "New Folder",
372
"action": function(data) {
373
// Create folder logic
374
}
375
};
376
items.create_file = {
377
"label": "New File",
378
"action": function(data) {
379
// Create file logic
380
}
381
};
382
}
383
384
// Add common items
385
items.rename = {
386
"label": "Rename",
387
"action": function(data) {
388
const inst = $.jstree.reference(data.reference);
389
inst.edit(data.reference);
390
}
391
};
392
393
return items;
394
}
395
}
396
});
397
```
398
399
### Unique Plugin
400
401
Ensures unique node names within parent nodes.
402
403
```javascript { .api }
404
/**
405
* Unique plugin configuration
406
*/
407
interface UniqueConfig {
408
/** Case sensitive uniqueness check (default: false) */
409
case_sensitive?: boolean;
410
/** Trim whitespace when checking (default: true) */
411
trim_whitespace?: boolean;
412
/** Custom duplicate callback */
413
duplicate?: function;
414
}
415
```
416
417
**Usage Examples:**
418
419
```javascript
420
// Initialize with unique names
421
$("#tree").jstree({
422
"plugins": ["unique"],
423
"unique": {
424
"case_sensitive": false,
425
"duplicate": function(name, counter) {
426
// Custom naming for duplicates
427
return name + " (" + counter + ")";
428
}
429
}
430
});
431
432
// Automatic duplicate handling
433
const tree = $("#tree").jstree(true);
434
tree.create_node("#", {"text": "New Item"}); // Creates "New Item"
435
tree.create_node("#", {"text": "New Item"}); // Creates "New Item (2)"
436
tree.create_node("#", {"text": "new item"}); // Creates "new item (3)" if case_sensitive: false
437
```
438
439
### Wholerow Plugin
440
441
Extends clickable area to full row width for easier interaction.
442
443
```javascript { .api }
444
/**
445
* Wholerow plugin configuration
446
*/
447
interface WholerowConfig {
448
/** Enable wholerow selection */
449
wholerow?: boolean;
450
}
451
```
452
453
**Usage Examples:**
454
455
```javascript
456
// Initialize with wholerow
457
$("#tree").jstree({
458
"plugins": ["wholerow"],
459
"wholerow": {
460
"wholerow": true
461
}
462
});
463
464
// The entire row becomes clickable, not just the text/icon
465
```
466
467
### Changed Plugin
468
469
Tracks and reports changes to the tree structure.
470
471
```javascript { .api }
472
/**
473
* Get array of changed node IDs since last call
474
* @param callback - Function to call with changed nodes
475
* @returns Array of changed node IDs
476
*/
477
get_changed(callback?: function): Array<string>;
478
```
479
480
**Usage Examples:**
481
482
```javascript
483
// Initialize with changed tracking
484
$("#tree").jstree({
485
"plugins": ["changed"]
486
});
487
488
// Get changed nodes
489
const tree = $("#tree").jstree(true);
490
const changedNodes = tree.get_changed();
491
console.log("Changed nodes:", changedNodes);
492
493
// Listen for changes
494
$("#tree").on("changed.jstree", function(e, data) {
495
console.log("Tree changed:", data.changed);
496
});
497
```
498
499
### Conditionalselect Plugin
500
501
Allows conditional node selection via callback functions.
502
503
```javascript { .api }
504
/**
505
* Conditionalselect plugin configuration
506
*/
507
interface ConditionalselectConfig {
508
/** Function to determine if node can be selected */
509
conditionalselect?: function;
510
}
511
512
type ConditionalSelectFunction = (node: object, event: Event) => boolean;
513
```
514
515
**Usage Examples:**
516
517
```javascript
518
// Initialize with conditional selection
519
$("#tree").jstree({
520
"plugins": ["conditionalselect"],
521
"conditionalselect": {
522
"conditionalselect": function(node, event) {
523
// Only allow selection of leaf nodes
524
return this.is_leaf(node);
525
}
526
}
527
});
528
529
// More complex conditions
530
$("#tree").jstree({
531
"plugins": ["conditionalselect", "types"],
532
"conditionalselect": {
533
"conditionalselect": function(node, event) {
534
// Prevent selection based on node type and user permissions
535
if (node.type === "readonly") return false;
536
if (node.li_attr && node.li_attr["data-locked"] === "true") return false;
537
538
// Check user permissions
539
const userRole = getCurrentUserRole();
540
if (userRole === "viewer" && node.type === "admin") return false;
541
542
return true;
543
}
544
}
545
});
546
```
547
548
### Massload Plugin
549
550
Enables loading multiple nodes in a single request for performance optimization.
551
552
```javascript { .api }
553
/**
554
* Massload plugin configuration
555
*/
556
interface MassloadConfig {
557
/** URL for mass loading endpoint */
558
url?: string;
559
/** Request data configuration */
560
data?: function;
561
}
562
```
563
564
**Usage Examples:**
565
566
```javascript
567
// Initialize with mass loading
568
$("#tree").jstree({
569
"plugins": ["massload"],
570
"massload": {
571
"url": "/api/nodes/massload",
572
"data": function(nodes) {
573
return {
574
"ids": nodes.join(","),
575
"timestamp": Date.now()
576
};
577
}
578
}
579
});
580
581
// Server endpoint should return data for multiple nodes at once
582
// instead of making individual requests for each node
583
```
584
585
## Plugin Integration Patterns
586
587
### Multi-Plugin Usage
588
589
Common patterns for combining multiple plugins effectively.
590
591
```javascript { .api }
592
/**
593
* Comprehensive tree setup with multiple plugins
594
*/
595
interface ComprehensiveTreeConfig {
596
plugins: Array<string>;
597
core: CoreConfig;
598
checkbox?: CheckboxConfig;
599
contextmenu?: ContextMenuConfig;
600
dnd?: DnDConfig;
601
search?: SearchConfig;
602
state?: StateConfig;
603
types?: TypesConfig;
604
sort?: SortConfig;
605
unique?: UniqueConfig;
606
wholerow?: WholerowConfig;
607
conditionalselect?: ConditionalselectConfig;
608
}
609
```
610
611
**Usage Examples:**
612
613
```javascript
614
// Full-featured tree setup
615
$("#tree").jstree({
616
"plugins": [
617
"checkbox", "contextmenu", "dnd", "search",
618
"state", "types", "sort", "unique", "wholerow"
619
],
620
"core": {
621
"check_callback": true,
622
"themes": {"stripes": true}
623
},
624
"checkbox": {
625
"three_state": true,
626
"cascade": "up+down+undetermined"
627
},
628
"contextmenu": {
629
"items": contextMenuBuilder
630
},
631
"dnd": {
632
"check_while_dragging": true,
633
"drag_selection": true
634
},
635
"search": {
636
"fuzzy": true,
637
"show_only_matches": true
638
},
639
"state": {
640
"key": "full-tree-state"
641
},
642
"types": {
643
"folder": {"icon": "fa fa-folder"},
644
"file": {"icon": "fa fa-file"}
645
},
646
"sort": {
647
"case_sensitive": false
648
}
649
});
650
651
// Event coordination across plugins
652
$("#tree").on("ready.jstree", function() {
653
// Tree is fully initialized with all plugins
654
const tree = $(this).jstree(true);
655
656
// Restore state
657
tree.restore_state();
658
659
// Enable search UI
660
$("#search-input").on("keyup", function() {
661
tree.search($(this).val());
662
});
663
});
664
```
665
666
## Types
667
668
```javascript { .api }
669
// Plugin-enhanced node object
670
interface EnhancedTreeNode extends TreeNode {
671
// State plugin
672
state?: {
673
loaded?: boolean;
674
opened?: boolean;
675
selected?: boolean;
676
disabled?: boolean;
677
};
678
679
// Types plugin
680
type?: string;
681
682
// Checkbox plugin (when enabled)
683
state?: {
684
checked?: boolean;
685
undetermined?: boolean;
686
checkbox_disabled?: boolean;
687
};
688
689
// Plugin-specific data
690
data?: {
691
[key: string]: any;
692
};
693
}
694
695
// Combined plugin settings
696
interface PluginSettings {
697
[plugin: string]: any;
698
}
699
```