Subversion-Projekte lars-tiefland.webanos.zeldi.de

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
4 lars 1
# jstree
2
 
3
[jsTree](http://www.jstree.com/) is jquery plugin, that provides interactive trees. It is absolutely free, [open source](https://github.com/vakata/jstree) and distributed under the MIT license.
4
 
5
jsTree is easily extendable, themable and configurable, it supports HTML & JSON data sources, AJAX & async callback loading.
6
 
7
jsTree functions properly in either box-model (content-box or border-box), can be loaded as an AMD module, and has a built in mobile theme for responsive design, that can easily be customized. It uses jQuery's event system, so binding callbacks on various events in the tree is familiar and easy.
8
 
9
You also get:
10
 * drag & drop support
11
 * keyboard navigation
12
 * inline edit, create and delete
13
 * tri-state checkboxes
14
 * fuzzy searching
15
 * customizable node types
16
 
17
_Aside from this readme you can find a lot more info on [jstree.com](http://www.jstree.com) & [the discussion group](https://groups.google.com/forum/#!forum/jstree)_.
18
 
19
---
20
 
21
<!-- MarkdownTOC depth=0 autolink=true bracket=round -->
22
 
23
- [Getting Started](#getting-started)
24
  - [Include all neccessary files](#include-all-neccessary-files)
25
  - [Populating a tree using HTML](#populating-a-tree-using-html)
26
  - [Populating a tree using an array (or JSON)](#populating-a-tree-using-an-array-or-json)
27
    - [The required JSON format](#the-required-json-format)
28
  - [Populating the tree using AJAX](#populating-the-tree-using-ajax)
29
  - [Populating the tree using AJAX and lazy loading nodes](#populating-the-tree-using-ajax-and-lazy-loading-nodes)
30
  - [Populating the tree using a callback function](#populating-the-tree-using-a-callback-function)
31
- [Working with events](#working-with-events)
32
- [Interacting with the tree using the API](#interacting-with-the-tree-using-the-api)
33
- [More on configuration](#more-on-configuration)
34
- [Plugins](#plugins)
35
  - [checkbox](#checkbox)
36
  - [contextmenu](#contextmenu)
37
  - [dnd](#dnd)
38
  - [massload](#massload)
39
  - [search](#search)
40
  - [sort](#sort)
41
  - [state](#state)
42
  - [types](#types)
43
  - [unique](#unique)
44
  - [wholerow](#wholerow)
45
  - [More plugins](#more-plugins)
46
- [License & Contributing](#license--contributing)
47
 
48
<!-- /MarkdownTOC -->
49
 
50
 
51
---
52
 
53
## Getting Started
54
 
55
### Include all neccessary files
56
To get started you need 3 things in your page:
57
 1. jQuery (anything above 1.9.1 will work)
58
 2. A jstree theme (there is only one theme supplied by default)
59
 3. The jstree source file
60
 
61
```html
62
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
63
 
64
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.0.9/themes/default/style.min.css" />
65
<script src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.0.9/jstree.min.js"></script>
66
```
67
 
68
_If you decide to host jstree yourself - the files are located in the `dist` folder. You can safely ignore the `dist/libs` folder._
69
 
70
---
71
 
72
### Populating a tree using HTML
73
 
74
Now we are all set to create a tree, inline HTML is the easiest option (suitable for menus). All you need to do is select a node (using a jQuery selector) and invoke the `.jstree()` function to let jstree know you want to render a tree inside the selected node. `$.jstree.create(element)` can be used too.
75
 
76
```html
77
<div id="container">
78
  <ul>
79
    <li>Root node
80
      <ul>
81
        <li>Child node 1</li>
82
        <li>Child node 2</li>
83
      </ul>
84
    </li>
85
  </ul>
86
</div>
87
<script>
88
$(function() {
89
  $('#container').jstree();
90
});
91
</script>
92
```
93
 
94
[view result](http://jsfiddle.net/vakata/2kwkh2uL/)
95
 
96
_You can add a few options when rendering a node using a data-attribute (note the quotes):_
97
```html
98
<li data-jstree='{ "selected" : true, "opened" : true }'>Root node ...
99
```
100
 
101
---
102
 
103
### Populating a tree using an array (or JSON)
104
 
105
Building trees from HTML is easy, but it is not very flexible, inline JS data is a better option:
106
 
107
```html
108
<div id="container"></div>
109
<script>
110
$(function() {
111
  $('#container').jstree({
112
    'core' : {
113
      'data' : [
114
        { "text" : "Root node", "children" : [
115
            { "text" : "Child node 1" },
116
            { "text" : "Child node 2" }
117
          ]
118
        }
119
      ]
120
    }
121
  });
122
});
123
</script>
124
```
125
 
126
[view result](http://jsfiddle.net/vakata/2kwkh2uL/1/)
127
 
128
Unlike the previous simple HTML example, this time the `.jstree()` function accepts a config object.
129
 
130
For now it is important to note that jstree will try to parse any data you specify in the  `core.data` key and use it to create a tree. As seen in the previous example, if this key is missing jstree will try to parse the inline HTML of the container.
131
 
132
#### The required JSON format
133
 
134
The data you use must be in a specific format, each branch of the tree is represented by an object, which must at least have a `text` key. The `children` key can be used to add children to the branch, it should be an array of objects.
135
 
136
_Keep in mind, you can use a simple string instead of an object if all you need is node with the given text, the above data can be written as:_
137
 
138
```js
139
[ { "text" : "Root node", "children" : [ "Child node 1", "Child node 2" ] } ]
140
```
141
 
142
There are other available options for each node, only set them if you need them like:
143
 
144
 * `id` - makes if possible to identify a node later (will also be used as a DOM ID of the `LI` node). _Make sure you do not repeat the same ID in a tree instance (that would defeat its purpose of being a unique identifier and may cause problems for jstree)_.
145
 * `icon` - a string which will be used for the node's icon - this can either be a path to a file, or a className (or list of classNames), which you can style in your CSS (font icons also work).
146
 * `data` - this can be anything you want - it is metadata you want attached to the node - you willbe able to access and modify it any time later - it has no effect on the visuals of the node.
147
 * `state` - and object specifyng a few options about the node:
148
   - `selected` - if the node should be initially selected
149
   - `opened` - if the node should be initially opened
150
   - `disabled` - if the node should be disabled
151
   - `checked` - __checkbox plugin specific__ - if the node should be checked (only used when `tie_to_selection` is `false`, which you should only do if you really know what you are doing)
152
   - `undetermined` - __checkbox plugin specific__ - if the node should be rendered in undetermined state (only used with lazy loading and when the node is not yet loaded, otherwise this state is automatically calculated).
153
 * `type` - __types plugin specific__ - the type of the nodes (should be defined in the types config), if not set `"default"` is assumed.
154
 * `li_attr` - object of values which will be used to add HTML attributes on the resulting `LI` DOM node.
155
 * `a_attr` - object of values which will be used to add HTML attributes on the resulting `A` node.
156
 
157
Here is a new demo with some of those properties set:
158
 
159
```html
160
<div id="container"></div>
161
<script>
162
$(function() {
163
  $('#container').jstree({
164
    'core' : {
165
      'data' : [
166
          {
167
              "text" : "Root node",
168
              "state" : {"opened" : true },
169
              "children" : [
170
                  {
171
                    "text" : "Child node 1",
172
                    "state" : { "selected" : true },
173
                    "icon" : "glyphicon glyphicon-flash"
174
                  },
175
                  { "text" : "Child node 2", "state" : { "disabled" : true } }
176
              ]
177
        }
178
      ]
179
    }
180
  });
181
});
182
</script>
183
```
184
 
185
[view result](http://jsfiddle.net/vakata/2kwkh2uL/11/)
186
 
187
---
188
 
189
### Populating the tree using AJAX
190
 
191
Building off of the previous example, let's see how to have jstree make AJAX requests for you.
192
 
193
```html
194
<div id="container"></div>
195
<script>
196
$(function() {
197
  $('#container').jstree({
198
    'core' : {
199
      'data' : {
200
        "url" : "//www.jstree.com/fiddle/",
201
        "dataType" : "json" // needed only if you do not supply JSON headers
202
      }
203
    }
204
  });
205
});
206
</script>
207
```
208
 
209
The server response is:
210
```json
211
[{
212
  "id":1,"text":"Root node","children":[
213
    {"id":2,"text":"Child node 1"},
214
    {"id":3,"text":"Child node 2"}
215
  ]
216
}]
217
```
218
 
219
[view result](http://jsfiddle.net/vakata/2kwkh2uL/4/)
220
 
221
Instead of a JS array, you can set `core.data` to a [jQuery AJAX config](http://api.jquery.com/jQuery.ajax/)
222
jsTree will hit that URL, and provided you return properly formatted JSON it will be displayed.
223
 
224
_If you cannot provide proper JSON headers, set `core.data.dataType` to `"json"`._
225
 
226
The ids in the server response make it possible to identify nodes later (which we will see in the next few demos), but they are not required.
227
 
228
__WHEN USING IDS MAKE SURE THEY ARE UNIQUE INSIDE A PARTICULAR TREE__
229
 
230
---
231
 
232
### Populating the tree using AJAX and lazy loading nodes
233
 
234
Lazy loading means nodes will be loaded then they are needed. Imagine you have a huge amount of nodes you want to show, but loading them with a single request is way too much traffic. Lazy loading makes it possible to load nodes on the fly - jstree will perform AJAX requests as the user browses the tree.
235
 
236
Here we take our previous example, and lazy load the "Child node 1" node.
237
 
238
```html
239
<div id="container"></div>
240
<script>
241
$(function() {
242
  $('#container').jstree({
243
    'core' : {
244
      'data' : {
245
        "url" : "//www.jstree.com/fiddle/?lazy",
246
        "data" : function (node) {
247
          return { "id" : node.id };
248
        }
249
      }
250
    }
251
  });
252
});
253
</script>
254
```
255
 
256
The initial server response is:
257
```json
258
[{
259
  "id":1,"text":"Root node","children":[
260
    {"id":2,"text":"Child node 1","children":true},
261
    {"id":3,"text":"Child node 2"}
262
  ]
263
}]
264
```
265
 
266
[view result](http://jsfiddle.net/vakata/2kwkh2uL/5/)
267
 
268
Now to focus on what is different. First off the `"data"` config option of the data object. If you check with jQuery, it is supposed to be a string or an object. But jstree makes it possible to set a function.
269
 
270
Each time jstree needs to make an AJAX call this function will be called and will receive a single parameter - the node that is being loaded. The return value of this function will be used as the actual `"data"` of the AJAX call. To understand better open up the demo and see the requests go off in the console.
271
 
272
You will notice that the first request goes off to:
273
`http://www.jstree.com/fiddle?lazy&id=#`
274
`#` is the special ID that the function receives when jstree needs to load the root nodes.
275
 
276
Now go ahead and open the root node - two children will be shown, but no request will be made - that is because we loaded those children along with the first request.
277
 
278
Onto the next difference - "Child node 1" appears closed - that is because in the data we supplied `true` as the `"children"` property of this node (you can see it in the server response). This special value indicated to jstree, that it has to lazy load the "Child node 1" node.
279
 
280
Proceed and open this node - you will see a next request fire off to:
281
`http://www.jstree.com/fiddle?lazy&id=2`
282
ID is set to `2` because the node being loaded has an ID of `2`, and we have configured jstree to send the node ID along with the AJAX request (the `data` function).
283
 
284
The server response is:
285
```json
286
["Child node 3","Child node 4"]
287
```
288
 
289
_You can also set `"url"` to a function and it works exactly as with `"data"` - each time a request has to be made, jstree will invoke your function and the request will go off to whatever you return in this function. This is useful when dealing with URLs like: `http://example.com/get_children/1`._
290
 
291
### Populating the tree using a callback function
292
 
293
Sometimes you may not want jsTree to make AJAX calls for you - you might want to make them yourself, or use some other method of puplating the tree. In that case you can use a callback function.
294
 
295
```html
296
<div id="container"></div>
297
<script>
298
$(function() {
299
  $('#container').jstree({
300
    'core' : {
301
      'data' : function (node, cb) {
302
        if(node.id === "#") {
303
          cb([{"text" : "Root", "id" : "1", "children" : true}]);
304
        }
305
        else {
306
          cb(["Child"]);
307
        }
308
      }
309
    }
310
  });
311
});
312
</script>
313
```
314
 
315
[view result](http://jsfiddle.net/vakata/2kwkh2uL/13/)
316
 
317
As you can see your function will receive two arguments - the node whose children need to be loaded and a callback function to call with the data once you have it. The data follows the same familiar JSON format and lazy loading works just as with AJAX (as you can see in the above example).
318
 
319
---
320
 
321
## Working with events
322
 
323
jstree provides a lot of events to let you know something happened with the tree. The events are the same regardless of how you populate the tree.
324
Let's use the most basic event `changed` - it fires when selection on the tree changes:
325
 
326
```html
327
<div id="container"></div>
328
<script>
329
$(function() {
330
  $('#container').jstree({
331
    'core' : {
332
      'data' : [
333
        {"id" : 1, "text" : "Node 1"},
334
        {"id" : 2, "text" : "Node 2"},
335
      ]
336
    }
337
  });
338
  $('#container').on("changed.jstree", function (e, data) {
339
    console.log("The selected nodes are:");
340
    console.log(data.selected);
341
  });
342
});
343
</script>
344
```
345
 
346
[view result](http://jsfiddle.net/vakata/2kwkh2uL/6/)
347
 
348
All jstree events fire in a special `".jstree"` namespace - this is why we listen for `"changed.jstree"`. The handler itself receives one additional parameter - it will be populated with all you need to know about the event that happened. In this case `data.selected` is an array of selected node IDs (please note, that if you have not specified IDs they will be autogenerated).
349
 
350
Let's extend this a bit and log out the text of the node instead of the ID.
351
 
352
```js
353
$('#container').on("changed.jstree", function (e, data) {
354
  console.log(data.instance.get_selected(true)[0].text);
355
  console.log(data.instance.get_node(data.selected[0]).text);
356
});
357
```
358
 
359
The two rows above achieve exactly the same thing - get the text of the first selected node.
360
 
361
In the `data` argument object you will always get an `instance` key - that is a reference to the tree instance, so that you can easily invoke methods.
362
 
363
__All available functions and events are documented in the API docs__
364
 
365
---
366
 
367
## Interacting with the tree using the API
368
 
369
We scratcched the surface on interacting with the tree in the previous example. Let's move on to obtaining an instance and calling a method on this instance:
370
 
371
```html
372
<button>Select node 1</button>
373
<div id="container"></div>
374
<script>
375
$(function() {
376
  $('#container').jstree({
377
    'core' : {
378
      'data' : [
379
        {"id" : 1, "text" : "Node 1"},
380
        {"id" : 2, "text" : "Node 2"},
381
      ]
382
    }
383
  });
384
  $('button').on("click", function () {
385
    var instance = $('#container').jstree(true);
386
    instance.deselect_all();
387
    instance.select_node('1');
388
  });
389
});
390
</script>
391
```
392
 
393
[view result](http://jsfiddle.net/vakata/2kwkh2uL/7/)
394
 
395
The above example shows how to obtain a reference to a jstree instance (again with a selector, but this time instead of a config, we pass a boolean `true`), and call a couple of methods - the latter one is selecting a node by its ID.
396
 
397
Methods can also be invoked like this:
398
 
399
```js
400
$('#container').jstree("select_node", "1");
401
```
402
 
403
__All available functions and events are documented in the API docs__
404
 
405
## More on configuration
406
 
407
We already covered the config object in general (when we specified inline & AJAX data sources).
408
 
409
```js
410
$("#tree").jstree({ /* config object goes here */ });
411
```
412
 
413
Each key in the config object corresponds to a plugin, and the value of that key is the configuration for that plugin. There are also two special keys `"core"` and `"plugins"`:
414
 * `"core"` stores the core configuration options
415
 * `"plugins"` is an array of plugin names (strings) you want active on the instance
416
 
417
When configuring you only need to set values that you want to be different from the defaults.
418
 
419
__All config options and defaults are documented in the API docs__
420
 
421
```js
422
$("#tree").jstree({
423
  "core" : { // core options go here
424
    "multiple" : false, // no multiselection
425
    "themes" : {
426
      "dots" : false // no connecting dots between dots
427
    }
428
  },
429
  "plugins" : ["state"] // activate the state plugin on this instance
430
});
431
```
432
 
433
[view result](http://jsfiddle.net/vakata/2kwkh2uL/8/)
434
 
435
We will cover all plugins further down.
436
 
437
__Keep in mind by default all modifications to the structure are prevented - that means drag'n'drop, create, rename, delete will not work unless you enable them.__
438
 
439
```js
440
$("#tree").jstree({
441
  "core" : {
442
    "check_callback" : true, // enable all modifications
443
  },
444
  "plugins" : ["dnd","contextmenu"]
445
});
446
```
447
 
448
[view result](http://jsfiddle.net/vakata/2kwkh2uL/9/)
449
 
450
`"core.check_callback"` can also be set to a function, that will be invoked every time a modification is about to happen (or when jstree needs to check if a modification is possible). If you return `true` the operation will be allowed, a value of `false` means it will not be allowed. The possible operation you can expect are `create_node`, `rename_node`, `delete_node`, `move_node` and `copy_node`. The `more` parameter will contain various information provided by the plugin that is invoking the check. For example the DND plugin will provide an object containing information about the move ot copy operation that is being checked - is it a multi tree operation, which node is currently hovered, where the insert arrow is pointing - before, after or inside, etc.
451
 
452
```js
453
$("#tree").jstree({
454
  "core" : {
455
    "check_callback" : function (operation, node, parent, position, more) {
456
      if(operation === "copy_node" || operation === "move_node") {
457
        if(parent.id === "#") {
458
          return false; // prevent moving a child above or below the root
459
        }
460
      },
461
      return true; // allow everything else
462
    }
463
  },
464
  "plugins" : ["dnd","contextmenu"]
465
});
466
```
467
 
468
[view result](http://jsfiddle.net/vakata/2kwkh2uL/10/)
469
 
470
The `more` parameter you receive contains other information related to the check being performed.
471
 
472
__For example__: `move_node` & `copy_node` checks will fire repeatedly while the user drags a node, if the check was triggered by the `dnd` plugin `more` will contain a `dnd` key, which will be set to `true`.
473
You can check for `more.dnd` and only perform a certain action if `dnd` triggered the check.
474
If you only want to perform an operation when a node is really about to be dropped check for `more.core`.
475
 
476
## Plugins
477
 
478
jsTree comes with a few plugin bundled, but they will only modify your tree if you activate them using the `"plugins"` config option. Here is a brief description of each plugin. You can read more on the available config options for each plugin in the API docs.
479
 
480
### checkbox
481
Renders a checkbox icon in front of each node, making multiselection easy. It also has a "tri-state" option, meaning a node with some of its children checked will get a "square" icon.
482
 
483
_Keep in mind that if any sort of cascade is enabled, disabled nodes may be checked too (not by themselves, but for example when a parent of a disabled node is checked and selection is configured to cascade down)._
484
 
485
```js
486
$("#tree").jstree({
487
  "plugins" : ["checkbox"]
488
});
489
```
490
 
491
[view result](http://jsfiddle.net/vakata/2kwkh2uL/14/)
492
 
493
### contextmenu
494
Makes it possible to right click nodes and shows a list of configurable actions in a menu.
495
 
496
```js
497
$("#tree").jstree({
498
  "core" : { "check_callback" : true }, // so that modifying operations work
499
  "plugins" : ["contextmenu"]
500
});
501
```
502
 
503
[view result](http://jsfiddle.net/vakata/2kwkh2uL/16/)
504
 
505
### dnd
506
Makes it possible to drag and drop tree nodes and rearrange the tree.
507
 
508
```js
509
$("#tree").jstree({
510
  "core" : { "check_callback" : true }, // so that operations work
511
  "plugins" : ["dnd"]
512
});
513
```
514
 
515
[view result](http://jsfiddle.net/vakata/2kwkh2uL/17/)
516
 
517
### massload
518
Makes it possible to load multiple nodes in a single go (for a lazy loaded tree).
519
 
520
```js
521
$("#tree").jstree({
522
  "core" : {
523
    "data" : { .. AJAX config .. }
524
  },
525
  "massload" : {
526
    "url" : "/some/path",
527
    "data" : function (nodes) {
528
      return { "ids" : nodes.join(",") };
529
    }
530
  },
531
  "plugins" : [ "massload", "state" ]
532
});
533
```
534
 
535
### search
536
Adds the possibility to search for items in the tree and show only matching nodes. It also has AJAX / callback hooks, so that search will work on lazy loaded trees too.
537
 
538
```html
539
<form id="s">
540
  <input type="search" id="q" />
541
  <button type="submit">Search</button>
542
</form>
543
<script>
544
$("#container").jstree({
545
  "plugins" : ["search"]
546
});
547
$("#s").submit(function(e) {
548
  e.preventDefault();
549
  $("#container").jstree(true).search($("#q").val());
550
});
551
</script>
552
```
553
 
554
[view result](http://jsfiddle.net/vakata/2kwkh2uL/18/)
555
 
556
### sort
557
Automatically arranges all sibling nodes according to a comparison config option function, which defaults to alphabetical order.
558
 
559
```js
560
$("#tree").jstree({
561
  "plugins" : ["sort"]
562
});
563
```
564
 
565
[view result](http://jsfiddle.net/vakata/2kwkh2uL/19/)
566
 
567
### state
568
Saves all opened and selected nodes in the user's browser, so when returning to the same tree the previous state will be restored.
569
 
570
```js
571
$("#tree").jstree({
572
  // the key is important if you have multiple trees in the same domain
573
  "state" : { "key" : "state_demo" },
574
  "plugins" : ["state"]
575
});
576
```
577
 
578
[view result](http://jsfiddle.net/vakata/2kwkh2uL/20/)
579
 
580
### types
581
Makes it possible to add a "type" for a node, which means to easily control nesting rules and icon for groups of nodes instead of individually. To set a node type add a type property to the node structure.
582
 
583
```js
584
$("#tree").jstree({
585
  "types" : {
586
    "default" : {
587
      "icon" : "glyphicon glyphicon-flash"
588
    },
589
    "demo" : {
590
      "icon" : "glyphicon glyphicon-ok"
591
    }
592
  },
593
  "plugins" : ["types"]
594
});
595
```
596
 
597
[view result](http://jsfiddle.net/vakata/2kwkh2uL/21/)
598
 
599
### unique
600
Enforces that no nodes with the same name can coexist as siblings - prevents renaming and moving nodes to a parent, which already contains a node with the same name.
601
 
602
```js
603
$("#tree").jstree({
604
  "plugins" : ["unique"]
605
});
606
```
607
 
608
[view result](http://jsfiddle.net/vakata/2kwkh2uL/22/)
609
 
610
### wholerow
611
Makes each node appear block level which makes selection easier. May cause slow down for large trees in old browsers.
612
 
613
```js
614
$("#tree").jstree({
615
  "plugins" : ["wholerow"]
616
});
617
```
618
 
619
[view result](http://jsfiddle.net/vakata/2kwkh2uL/23/)
620
 
621
### More plugins
622
If you create your own plugin (or download a 3rd party one) you must include its source on the page and list its name in the `"plugins"` config array.
623
 
624
```js
625
// conditional select
626
(function ($, undefined) {
627
  "use strict";
628
  $.jstree.defaults.conditionalselect = function () { return true; };
629
  $.jstree.plugins.conditionalselect = function (options, parent) {
630
    this.activate_node = function (obj, e) {
631
      if(this.settings.conditionalselect.call(this, this.get_node(obj))) {
632
        parent.activate_node.call(this, obj, e);
633
      }
634
    };
635
  };
636
})(jQuery);
637
$("#tree").jstree({
638
  "conditionalselect" : function (node) {
639
    return node.text === "Root node" ? false : true;
640
  },
641
  "plugins" : ["conditionalselect"]
642
});
643
```
644
 
645
[view result](http://jsfiddle.net/vakata/2kwkh2uL/24/)
646
 
647
As seen here when creating a plugin you can define a default config, add your own functions to jstree, or override existing ones while maintaining the ability to call the overridden function.
648
 
649
## License & Contributing
650
 
651
_Please do NOT edit files in the "dist" subdirectory as they are generated via grunt. You'll find source code in the "src" subdirectory!_
652
 
653
If you want to you can always [donate a small amount][paypal] to help the development of jstree.
654
[paypal]: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=paypal@vakata.com&currency_code=USD&amount=&return=http://jstree.com/donation&item_name=Buy+me+a+coffee+for+jsTree
655
 
656
Copyright (c) 2014 Ivan Bozhanov (http://vakata.com)
657
 
658
Licensed under the [MIT license](http://www.opensource.org/licenses/mit-license.php).