jstree-rails 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/INSTALLER.sh +57 -0
  4. data/LICENSE +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +2 -0
  7. data/jstree-rails.gemspec +17 -0
  8. data/lib/jstree-rails/rails.rb +6 -0
  9. data/lib/jstree-rails/version.rb +5 -0
  10. data/lib/jstree-rails.rb +8 -0
  11. data/vendor/assets/images/jstree/themes/default/d.gif +0 -0
  12. data/vendor/assets/images/jstree/themes/default/d.png +0 -0
  13. data/vendor/assets/images/jstree/themes/default/throbber.gif +0 -0
  14. data/vendor/assets/images/jstree/themes/default-rtl/d.gif +0 -0
  15. data/vendor/assets/images/jstree/themes/default-rtl/d.png +0 -0
  16. data/vendor/assets/images/jstree/themes/default-rtl/dots.gif +0 -0
  17. data/vendor/assets/images/jstree/themes/default-rtl/throbber.gif +0 -0
  18. data/vendor/assets/javascripts/jstree/index.js +15 -0
  19. data/vendor/assets/javascripts/jstree/jstree.checkbox.js +187 -0
  20. data/vendor/assets/javascripts/jstree/jstree.contextmenu.js +145 -0
  21. data/vendor/assets/javascripts/jstree/jstree.dnd.js +162 -0
  22. data/vendor/assets/javascripts/jstree/jstree.hotkeys.js +138 -0
  23. data/vendor/assets/javascripts/jstree/jstree.html.js +69 -0
  24. data/vendor/assets/javascripts/jstree/jstree.js +1982 -0
  25. data/vendor/assets/javascripts/jstree/jstree.json.js +99 -0
  26. data/vendor/assets/javascripts/jstree/jstree.rules.js +145 -0
  27. data/vendor/assets/javascripts/jstree/jstree.sort.js +38 -0
  28. data/vendor/assets/javascripts/jstree/jstree.state.js +39 -0
  29. data/vendor/assets/javascripts/jstree/jstree.themes.js +215 -0
  30. data/vendor/assets/javascripts/jstree/jstree.ui.js +201 -0
  31. data/vendor/assets/javascripts/jstree/jstree.unique.js +33 -0
  32. data/vendor/assets/javascripts/jstree/jstree.xml.js +185 -0
  33. data/vendor/assets/javascripts/jstree/vakata.js +2079 -0
  34. data/vendor/assets/stylesheets/jstree/themes/default/style.css +79 -0
  35. data/vendor/assets/stylesheets/jstree/themes/default-rtl/style.css +84 -0
  36. metadata +80 -0
@@ -0,0 +1,1982 @@
1
+ /*
2
+ * jsTree 1.0.0
3
+ * http://jstree.com/
4
+ *
5
+ * Copyright (c) 2011 Ivan Bozhanov (vakata.com)
6
+ *
7
+ * Licensed same as jquery - under the terms of either the MIT License or the GPL Version 2 License
8
+ * http://www.opensource.org/licenses/mit-license.php
9
+ * http://www.gnu.org/licenses/gpl.html
10
+ *
11
+ */
12
+
13
+ /*global jQuery */
14
+
15
+ /* File: jstree.js
16
+ The only required part of jstree it consists of a few functions bound to the $.jstree object, the actual plugin function and a few core functions for manipulating a tree.
17
+ */
18
+ (function () {
19
+ "use strict";
20
+ if(!jQuery) { throw "jsTree: jQuery not included."; }
21
+ if(jQuery.jstree) { return; } // prevent another load? maybe there is a better way?
22
+
23
+ /* Group: $.jstree.
24
+ Some static functions and variables, unless you know exactly what you are doing do not use these, but <$().jstree> instead.
25
+ */
26
+ (function ($) {
27
+ var instances = [],
28
+ focused_instance = -1,
29
+ plugins = {},
30
+ functions = {};
31
+ /*
32
+ Variable: $.jstree
33
+ *object* Contains all static functions and variables used by jstree, some plugins also append variables.
34
+ */
35
+ $.jstree = {
36
+ /*
37
+ Variable: $.jstree.VERSION
38
+ *string* the version of jstree
39
+ */
40
+ VERSION : '1.0.0',
41
+
42
+ /*
43
+ Variable: $.jstree.IS_IE6
44
+ *boolean* indicating if the client is running Internet Explorer 6
45
+ */
46
+ IS_IE6 : (jQuery.browser.msie && parseInt(jQuery.browser.version,10) === 6),
47
+
48
+ /*
49
+ Variable: $.jstree.IS_IE7
50
+ *boolean* indicating if the client is running Internet Explorer 7
51
+ */
52
+ IS_IE7 : (jQuery.browser.msie && parseInt(jQuery.browser.version,10) === 6),
53
+
54
+ /*
55
+ Variable: $.jstree.IS_FF2
56
+ *boolean* indicating if the client is running Firefox 2
57
+ */
58
+ IS_FF2 : (jQuery.browser.mozilla && parseFloat(jQuery.browser.version,10) < 1.9),
59
+
60
+ /*
61
+ Function: $.jstree.__construct
62
+ Creates a new jstree instance, any arguments after the first one are merged and used to configure the tree.
63
+
64
+ `.data("jstree")` is also called on the container and is used for configuration (keep in mind you can specify this data using a "data-jstree" attribute)
65
+
66
+ Parameters:
67
+ container - *mixed* the container of the tree (this should not be the UL node, but a wrapper) - DOM node, jQuery object or selector
68
+ */
69
+ __construct : function (container) {
70
+ var s = {}, // settings
71
+ d = {}, // data
72
+ p = [], // plugins
73
+ t = [], // plugins temp
74
+ i = 0; // index
75
+ container = $(container);
76
+ if($.jstree._reference(container)) { $.jstree.__destruct(container); }
77
+ $.extend.apply(null, [true, s].concat(Array.prototype.slice.call(arguments, 1), (container.data("jstree") || {}) ));
78
+ p = $.isArray(s.plugins) ? s.plugins : $.jstree.defaults.plugins.slice();
79
+ p = $.vakata.array_unique(p);
80
+ s = $.extend(true, {}, $.jstree.defaults, s);
81
+ $.each(plugins, function (i, val) {
82
+ if(i !== "core" && $.inArray(i, p) === -1) { s[i] = null; delete s[i]; }
83
+ else { t.push(i); d[i] = {}; }
84
+ });
85
+ s.plugins = t;
86
+ i = parseInt(instances.push({}),10) - 1;
87
+ container
88
+ .data("jstree_instance_id", i)
89
+ .addClass("jstree jstree-" + i);
90
+
91
+ this.data = d;
92
+ this.get_index = function () { return i; };
93
+ this.get_container = function () { return container; };
94
+ this.get_container_ul = function () { return container.children("ul:eq(0)"); };
95
+ this.get_settings = function (writable) { return writable ? s : $.extend(true, {}, s); };
96
+ this.__trigger = function (ev, data) {
97
+ if(!ev) { return; }
98
+ if(!data) { data = {}; }
99
+ if(typeof ev === "string") { ev = ev.replace(".jstree","") + ".jstree"; }
100
+ data.inst = this;
101
+ this.get_container().triggerHandler(ev, data);
102
+ };
103
+ instances[i] = this;
104
+ $.each(t, function (j, val) { if(plugins[val]) { plugins[val].__construct.apply(instances[i]); } });
105
+ this.__trigger("__construct");
106
+ $.jstree._focus(i);
107
+ return this;
108
+ },
109
+ /*
110
+ Group: $.jstree.
111
+
112
+ Function: $.jstree.__destruct
113
+ Destroys an instance, and also clears `jstree-` prefixed classes and all events in the `jstree` namespace
114
+
115
+ Parameters:
116
+ instance - *mixed* the instance to destroy (this argument is passed to <$.jstree._reference> to get the instance)
117
+
118
+ See also:
119
+ <$.jstree._reference>
120
+ */
121
+ __destruct : function (instance) {
122
+ instance = $.jstree._reference(instance);
123
+ if(!instance) { return false; }
124
+ var s = instance.get_settings(),
125
+ n = instance.get_index(),
126
+ i = 0;
127
+ if(focused_instance === n) {
128
+ for(i in instances) {
129
+ if(instances.hasOwnProperty(i) && i !== n) {
130
+ $.jstree._focus(i);
131
+ break;
132
+ }
133
+ }
134
+ if(focused_instance === n) { $.jstree._focus(false); }
135
+ }
136
+ $.each(s.plugins, function (i, val) {
137
+ try { plugins[val].__destruct.apply(instance); } catch(err) { }
138
+ });
139
+ instance.__trigger("__destruct");
140
+ instance.get_container()
141
+ .unbind(".jstree")
142
+ .undelegate(".jstree")
143
+ .removeData("jstree_instance_id")
144
+ .find("[class^='jstree']")
145
+ .andSelf()
146
+ .attr("class", function () { return this.className.replace(/jstree[^ ]*|$/ig,''); });
147
+ $(document)
148
+ .unbind(".jstree-" + n)
149
+ .undelegate(".jstree-" + n);
150
+ delete instances[n];
151
+ return true;
152
+ },
153
+ /*
154
+ Function: $.jstree.__call
155
+ Call a function on the instance and return the result
156
+
157
+ Parameters:
158
+ instance - *mixed* the instance to destroy (this argument is passed to <$.jstree._reference> to get the instance)
159
+ operation - *string* the operation to execute
160
+ args - *array* the arguments to pass to the function
161
+
162
+ See also:
163
+ <$.jstree._reference>
164
+ */
165
+ __call : function (instance, operation, args) {
166
+ instance = $.jstree._reference(instance);
167
+ if(!instance || !$.isFunction(instance[operation])) { return; }
168
+ return instance[operation].apply(instance, args);
169
+ },
170
+ /*
171
+ Function: $.jstree._reference
172
+ Returns an instance
173
+
174
+ Parameters:
175
+ needle - *mixed* - integer, DOM node contained inside a jstree container, ID string, jQuery object, selector
176
+ */
177
+ _reference : function (needle) {
178
+ if(instances[needle]) { return instances[needle]; }
179
+ var o = $(needle);
180
+ if(!o.length && typeof needle === "string") { o = $("#" + needle); }
181
+ if(!o.length) { return null; }
182
+ return instances[o.closest(".jstree").data("jstree_instance_id")] || null;
183
+ },
184
+ /*
185
+ Function: $.jstree._focused
186
+ Returns the currently focused instance (by default once an instance is created it is focused)
187
+ */
188
+ _focused : function () {
189
+ return instances[focused_instance] || null;
190
+ },
191
+ /*
192
+ Function: $.jstree._focus
193
+ Make an instance focused (which defocuses the previously focused instance)
194
+
195
+ Parameters:
196
+ instance - *mixed* the instance to focus (this argument is passed to <$.jstree._reference> to get the instance)
197
+
198
+ See also:
199
+ <$.jstree._reference>
200
+ */
201
+ _focus : function (instance) {
202
+ if(instance === false) {
203
+ instances[focused_instance].get_container().removeClass("jstree-focused");
204
+ instances[focused_instance].__trigger("_defocus");
205
+ focused_instance = -1;
206
+ return false;
207
+ }
208
+ instance = $.jstree._reference(instance);
209
+ if(!instance || instance.get_index() === focused_instance) { return false; }
210
+ if(focused_instance !== -1) {
211
+ instances[focused_instance].get_container().removeClass("jstree-focused");
212
+ instances[focused_instance].__trigger("_defocus");
213
+ }
214
+ focused_instance = instance.get_index();
215
+ instance.get_container().addClass("jstree-focused");
216
+ instance.__trigger("_focus");
217
+ return true;
218
+ },
219
+ /*
220
+ Function: $.jstree.plugin
221
+ Register a plugin
222
+
223
+ Parameters:
224
+ plugin_name - *string* the name of the new plugin (it will be used as a key in an object - make sure it is valid)
225
+ plugin_data - *object* consists of 4 keys. Default is:
226
+ >{
227
+ > __construct : $.noop, // this function will be executed when a new instance is created
228
+ > __destuct : $.noop, // this function will be executed when an instance is destroyed
229
+ > _fn : { }, // each key of this object should be a function that will extend the jstree prototype
230
+ > defaults : false // the default configuration for the plugin (if any)
231
+ >}
232
+ */
233
+ plugin : function (plugin_name, plugin_data) {
234
+ plugin_data = $.extend({}, {
235
+ __construct : $.noop,
236
+ __destuct : $.noop,
237
+ _fn : { },
238
+ defaults : false
239
+ }, plugin_data);
240
+ plugins[plugin_name] = plugin_data;
241
+ $.jstree.defaults[plugin_name] = plugin_data.defaults;
242
+ $.each(plugin_data._fn, function (i, val) {
243
+ val.plugin = plugin_name;
244
+ val.old = functions[i];
245
+ functions[i] = function () {
246
+ var rslt,
247
+ func = val,
248
+ args = Array.prototype.slice.call(arguments),
249
+ evnt = new $.Event("before.jstree"),
250
+ plgn = this.get_settings(true).plugins;
251
+
252
+ do {
253
+ if(func && func.plugin && $.inArray(func.plugin, plgn) !== -1) { break; }
254
+ func = func.old;
255
+ } while(func);
256
+ if(!func) { return; }
257
+
258
+ if(i.indexOf("_") === 0) {
259
+ rslt = func.apply(this, args);
260
+ }
261
+ else {
262
+ rslt = this.__trigger(evnt, { "func" : i, "args" : args, "plugin" : func.plugin });
263
+ if(rslt === false) { return; }
264
+ rslt = func.apply(
265
+ $.extend({}, this, {
266
+ __callback : function (data) {
267
+ this.__trigger( i, { "args" : args, "rslt" : data, "plugin" : func.plugin });
268
+ return data;
269
+ },
270
+ __call_old : function (replace_arguments) {
271
+ return func.old.apply(this, (replace_arguments ? Array.prototype.slice.call(arguments, 1) : args ) );
272
+ }
273
+ }), args);
274
+ }
275
+ return rslt;
276
+ };
277
+ functions[i].old = val.old;
278
+ functions[i].plugin = plugin_name;
279
+ });
280
+ },
281
+ /*
282
+ Variable: $.jstree.defaults
283
+ *object* storing all the default configuration options for every plugin and the core.
284
+ If this is modified all instances created after the modification, which do not explicitly specify some other value will use the new default.
285
+
286
+ Example:
287
+ >// this instance will use the _default_ theme
288
+ >$("#div0").jstree({ plugins : ["themes"] });
289
+ >$.jstree.defaults.themes.theme = "classic";
290
+ >// this instance will use the _classic_ theme
291
+ >$("#div1").jstree({ plugins : ["themes"] });
292
+ >// this instance will use the _apple_ theme
293
+ >$("#div2").jstree({ themes : { "theme" : "apple" }, plugins : ["themes"] });
294
+ */
295
+ defaults : {
296
+ plugins : []
297
+ }
298
+ };
299
+ /* Group: $().jstree()
300
+ The actual plugin wrapper, use this to create instances or execute functions on created instances.
301
+
302
+ Function: $().jstree
303
+
304
+ Creates an instance using the specified objects for containers, or executes a command on an instance, specified by a container.
305
+
306
+ Parameters:
307
+ settings - *mixed*
308
+
309
+ - if you pass an *object* a new instance will be created (using <$.jstree.__construct>)
310
+ for each of the objects in the jquery collection,
311
+ if an instance already exists on the container it will be destroyed first
312
+
313
+ - if you pass a *string* it will be executed using <$.jstree.__call> on each instance
314
+
315
+ Examples:
316
+ > // this creates an instance
317
+ > $("#some-id").jstree({
318
+ > plugins : [ "html_data", "themes", "ui" ]
319
+ > });
320
+ >
321
+ > // this executes a function on the instance
322
+ > $("#some-id").jstree("select_node", "#the-id-to-select");
323
+
324
+ See also:
325
+ <$.jstree.__construct>,
326
+ <$.jstree.__destruct>,
327
+ <$.jstree.__call>
328
+ */
329
+ $.fn.jstree = function (settings) {
330
+ var _is_method = (typeof settings === 'string'),
331
+ _arguments = Array.prototype.slice.call(arguments, 1),
332
+ _return = this;
333
+ this.each(function () {
334
+ if(_is_method) {
335
+ var val = $.jstree.__call(this, settings, _arguments);
336
+ if(typeof val !== "undefined" && (settings.indexOf("is_" === 0) || (val !== true && val !== false))) {
337
+ _return = val;
338
+ return false;
339
+ }
340
+ }
341
+ else {
342
+ _is_method = new $.jstree.__construct(this, settings);
343
+ }
344
+ });
345
+ return _return;
346
+ };
347
+ functions = $.jstree.__construct.prototype;
348
+
349
+ $.expr[':'].jstree = function(a,i,m) {
350
+ return typeof ($(a).data("jstree_instance_id")) !== 'undefined';
351
+ };
352
+ })(jQuery);
353
+
354
+ (function ($) {
355
+ var ccp_node = false,
356
+ ccp_mode = false;
357
+
358
+ $(function() { $.jstree.SCROLLBAR_WIDTH = $.vakata.get_scrollbar_width(); });
359
+
360
+ $.jstree.plugin("core", {
361
+ __construct : function () {
362
+ this.data.core.rtl = (this.get_container().css("direction") === "rtl");
363
+ if(this.data.core.rtl) { this.get_container().addClass("jstree-rtl"); }
364
+ this.data.core.ready = false;
365
+
366
+ this.get_container()
367
+ .bind("__construct.jstree", $.proxy(function () {
368
+ // defer, so that events bound AFTER creating the instance (like __ready) are still handled
369
+ setTimeout($.proxy(function () { if(this) { this.init(); } }, this), 0);
370
+ }, this))
371
+ .bind("before.jstree", $.proxy(function (e, data) {
372
+ if(!/^is_locked|unlock$/.test(data.func) && this.data.core.locked) {
373
+ e.stopImmediatePropagation();
374
+ return false;
375
+ }
376
+ }, this))
377
+ .bind("create_node.jstree", $.proxy(function (e, data) {
378
+ this.clean_node(data.rslt.obj);
379
+ }, this))
380
+ .bind("load_node.jstree", $.proxy(function (e, data) {
381
+ // data.rslt.status
382
+ this.clean_node(data.rslt.obj === -1 ? this.get_container_ul().children('li') : data.rslt.obj.find('> ul > li'));
383
+ if(!this.data.core.ready && !this.get_container_ul().find('.jstree-loading:eq(0)').length) {
384
+ this.data.core.ready = true;
385
+ this.__trigger("__ready");
386
+ }
387
+ }, this))
388
+ .bind("__loaded.jstree", $.proxy(function (e, data) {
389
+ data.inst.get_container_ul().children('li').each(function () {
390
+ data.inst.correct_node(this);
391
+ });
392
+ }, this))
393
+ .bind("open_node.jstree", $.proxy(function (e, data) {
394
+ data.rslt.obj.find('> ul > li').each(function () {
395
+ data.inst.correct_node(this);
396
+ });
397
+ }, this))
398
+ .bind("mousedown.jstree", $.proxy(function () {
399
+ $.jstree._focus(this.get_index());
400
+ }, this))
401
+ .bind("dblclick.jstree", function () {
402
+ if(document.selection && document.selection.empty) { document.selection.empty(); }
403
+ else { if(window.getSelection) { var sel = window.getSelection(); try { sel.removeAllRanges(); sel.collapse(); } catch (er) { } } }
404
+ })
405
+ .delegate("li > ins", "click.jstree", $.proxy(function (e) {
406
+ // var trgt = $(e.target);
407
+ // if(trgt.is("ins") && e.pageY - trgt.offset().top < this.data.core.li_height) { this.toggle_node(trgt); }
408
+ this.toggle_node(e.target);
409
+ }, this));
410
+ },
411
+ __destruct : function () {
412
+
413
+ },
414
+ /* Class: jstree */
415
+ /*
416
+ Variable: data
417
+ *object* Provides storage for plugins (aside from private variables). Every plugin has an key in this object.
418
+ > this.data.<plugin_name>;
419
+ This is useful for detecting if some plugin is included in the instance (plugins also use this for dependencies and enhancements).
420
+
421
+ Function: get_index
422
+ Returns an *integer*, which is the instance's index. Every instance on the page has an unique index, when destroying an intance the index will not be reused.
423
+
424
+ Function: get_container
425
+ Returns the jQuery extended container of the tree (the element you used when constructing the tree).
426
+
427
+ Function: get_container_ul
428
+ Returns the jQuery extended first UL node inside the container of the tree.
429
+
430
+ Function: get_settings
431
+ Returns the settings for the tree.
432
+
433
+ Parameters:
434
+ writable - *boolean* whether to return a copy of the settings object or a reference to it.
435
+
436
+ Example:
437
+ > $("#div1").jstree("get_settings"); // will return a copy
438
+ > $.jstree._reference("#div1").get_settings(); // same as above
439
+ > $.jstree._focused().get_settings(true); // a reference. BE CAREFUL!
440
+
441
+ Function: __trigger
442
+ Used internally to trigger events on the container node.
443
+
444
+ Parameters:
445
+ event_name - the name of the event to trigger (the *jstree* namespace will be appended to it)
446
+ data - the additional object to pass along with the event. By default _data.inst_ will be the current instance, so when you bind to the event, you can access the instance easily.
447
+ > $("div").bind("some-event.jstree", function (e, data) { data.inst.some_function(); });
448
+ */
449
+ /*
450
+ Group: CORE options
451
+
452
+ Variable: config.core.strings
453
+ *mixed* used to store all localization strings. Default is _false_.
454
+
455
+ Example 1:
456
+ >$("div").jstree({
457
+ > core : {
458
+ > strings : function (s) {
459
+ > if(s === "Loading ...") { s = "Please wait ..."; }
460
+ > return s;
461
+ > }
462
+ > }
463
+ >});
464
+
465
+ Example 2:
466
+ >$("div").jstree({
467
+ > core : {
468
+ > strings : {
469
+ > "Loading ..." : "Please wait ..."
470
+ > }
471
+ > }
472
+ >});
473
+
474
+ See also:
475
+ <_get_string>
476
+ */
477
+ defaults : {
478
+ strings : false
479
+ },
480
+ _fn : {
481
+ /*
482
+ Group: CORE functions
483
+
484
+ Function: _get_string
485
+ Used to get the common string in the tree.
486
+
487
+ If <config.core.strings> is set to a function, that function is called with a single parameter (the needed string), the response is returned.
488
+
489
+ If <config.core.strings> is set to an object, the key named as the needed string is returned.
490
+
491
+ If <config.core.strings> is not set, the the needed string is returned.
492
+
493
+ Parameters:
494
+ needed_string - *string* the needed string
495
+ */
496
+ _get_string : function (s) {
497
+ var a = this.get_settings(true).core.strings;
498
+ if($.isFunction(a)) { return a.call(this, s); }
499
+ if(a && a[s]) { return a[s]; }
500
+ return s;
501
+ },
502
+ /*
503
+ Function: init
504
+ Used internally. This function is called once the core plugin is constructed.
505
+
506
+ Triggers:
507
+ <__loaded>
508
+
509
+ Event: __loaded
510
+ This event is triggered in the *jstree* namespace when data is first rendered in the tree. It won't be triggered after a refresh. Fires only once.
511
+
512
+ Parameters:
513
+ data.inst - the instance
514
+
515
+ Example:
516
+ > $("div").bind("__loaded.jstree", function (e, data) { data.inst.do_something(); });
517
+
518
+ Event: __ready
519
+ This event is triggered in the *jstree* namespace when all initial loading is done. It won't be triggered after a refresh. Fires only once.
520
+
521
+ Parameters:
522
+ data.inst - the instance
523
+ */
524
+ init : function () {
525
+ this.data.core.original_container_html = this.get_container().find(" > ul > li").clone(true);
526
+ this.data.core.original_container_html.find("li").andSelf().contents().filter(function() { return this.nodeType === 3 && (!this.nodeValue || /^\s+$/.test(this.nodeValue)); }).remove();
527
+ this.get_container().html("<ul><li class='jstree-loading'><a href='#'>" + this._get_string("Loading ...") + "</a></li></ul>");
528
+ this.clean_node(-1);
529
+ this.data.core.li_height = this.get_container_ul().children("li:eq(0)").height() || 18;
530
+ this.load_node(-1, function () {
531
+ this.__trigger("__loaded");
532
+ });
533
+ },
534
+ /*
535
+ Function: lock
536
+ Used to lock the tree. When the tree is in a locked state, no functions can be called on the instance (except <is_locked> and <unlock>).
537
+ Additionally a _jstree-locked_ class is applied on the container.
538
+
539
+ Triggers:
540
+ <lock>
541
+
542
+ Event: lock
543
+ This event is triggered in the *jstree* namespace when the tree is locked.
544
+
545
+ Parameters:
546
+ data.inst - the instance
547
+ data.args - *array* the arguments passed to the function
548
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else).
549
+ data.rslt - _null_
550
+
551
+ Example:
552
+ > $("div").bind("lock.jstree", function (e, data) { data.inst.do_something(); });
553
+ */
554
+ lock : function () {
555
+ this.data.core.locked = true;
556
+ this.get_container().addClass("jstree-locked");
557
+ this.__callback();
558
+ },
559
+ /*
560
+ Function: unlock
561
+ Used to unlock the tree. Instance can be used normally again. The _jstree-locked_ class is removed from the container.
562
+
563
+ Triggers:
564
+ <unlock>
565
+
566
+ Event: unlock
567
+ This event is triggered in the *jstree* namespace when the tree is unlocked.
568
+
569
+ Parameters:
570
+ data.inst - the instance
571
+ data.args - *array* the arguments passed to the function
572
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else).
573
+ data.rslt - _null_
574
+
575
+ Example:
576
+ > $("div").bind("unlock.jstree", function (e, data) { data.inst.do_something(); });
577
+ */
578
+ unlock : function () {
579
+ this.data.core.locked = false;
580
+ this.get_container().removeClass("jstree-locked");
581
+ this.__callback();
582
+ },
583
+ /*
584
+ Function: is_locked
585
+ Used to get the locked status of the tree.
586
+
587
+ Returns:
588
+ locked - *boolean* _true_ if tree is locked, _false_ otherwise
589
+ */
590
+ is_locked : function () {
591
+ return this.data.core.locked;
592
+ },
593
+ /*
594
+ Function: get_node
595
+ Get a hold of the LI node (which represents the jstree node).
596
+
597
+ Parameters:
598
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
599
+
600
+ Returns:
601
+ jquery collection - node was found, the collection contains the LI node
602
+ -1 - the tree container was referenced
603
+ false - on failure (obj is not part of a tree, or does not exists in the DOM)
604
+ */
605
+ get_node : function (obj) {
606
+ var $obj = $(obj, this.get_container());
607
+ if($obj.is(".jstree") || obj === -1) { return -1; }
608
+ $obj = $obj.closest("li", this.get_container());
609
+ return $obj.length ? $obj : false;
610
+ },
611
+ /*
612
+ Function: get_next
613
+ Get the next sibling of a node
614
+
615
+ Parameters:
616
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
617
+ strict - *boolean* if set to _true_ jstree will only return immediate siblings, otherwise, if _obj_ is the last child of its parent, the parent's next sibling is returned.
618
+
619
+ Returns:
620
+ jquery collection - node was found, the collection contains the LI node
621
+ -1 - the tree container was referenced
622
+ false - node was not found, or failure (obj is not part of a tree, or does not exists in the DOM)
623
+ */
624
+ get_next : function (obj, strict) {
625
+ obj = this.get_node(obj);
626
+ if(obj === -1) { return this.get_container_ul().children("li:eq(0)"); }
627
+ if(!obj || !obj.length) { return false; }
628
+ if(strict) { return (obj.nextAll("li").size() > 0) ? obj.nextAll("li:eq(0)") : false; }
629
+ if(obj.hasClass("jstree-open")) { return obj.find("li:eq(0)"); }
630
+ else if(obj.nextAll("li").size() > 0) { return obj.nextAll("li:eq(0)"); }
631
+ else { return obj.parentsUntil(".jstree","li").next("li").eq(0); }
632
+ },
633
+ /*
634
+ Function: get_prev
635
+ Get the previous sibling of a node
636
+
637
+ Parameters:
638
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
639
+ strict - *boolean* if set to _true_ jstree will only return immediate siblings, otherwise, if _obj_ is the first child of its parent, the parent's previous sibling is returned.
640
+
641
+ Returns:
642
+ jquery collection - node was found, the collection contains the LI node
643
+ -1 - the tree container was referenced
644
+ false - node was not found, or failure (obj is not part of a tree, or does not exists in the DOM)
645
+ */
646
+ get_prev : function (obj, strict) {
647
+ obj = this.get_node(obj);
648
+ if(obj === -1) { return this.get_container().find("> ul > li:last-child"); }
649
+ if(!obj || !obj.length) { return false; }
650
+ if(strict) { return (obj.prevAll("li").length > 0) ? obj.prevAll("li:eq(0)") : false; }
651
+ if(obj.prev("li").length) {
652
+ obj = obj.prev("li").eq(0);
653
+ while(obj.hasClass("jstree-open")) { obj = obj.children("ul:eq(0)").children("li:last"); }
654
+ return obj;
655
+ }
656
+ else { var o = obj.parentsUntil(".jstree","li:eq(0)"); return o.length ? o : false; }
657
+ },
658
+ /*
659
+ Function: get_parent
660
+ Get the parent of a node
661
+
662
+ Parameters:
663
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
664
+
665
+ Returns:
666
+ jquery collection - node was found, the collection contains the LI node
667
+ -1 - when _obj_ was a root node
668
+ false - on failure (obj is not part of a tree, or does not exists in the DOM)
669
+ */
670
+ get_parent : function (obj) {
671
+ obj = this.get_node(obj);
672
+ if(obj === -1 || !obj || !obj.length) { return false; }
673
+ var o = obj.parentsUntil(".jstree", "li:eq(0)");
674
+ return o.length ? o : -1;
675
+ },
676
+ /*
677
+ Function: get_children
678
+ Get all the children of a node
679
+
680
+ Parameters:
681
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc. If _-1_ is used all root nodes are returned.
682
+
683
+ Returns:
684
+ jquery collection - node was found, the collection contains the LI nodes of all immediate children
685
+ false - on failure (obj is not part of a tree, or does not exists in the DOM)
686
+ */
687
+ get_children : function (obj) {
688
+ obj = this.get_node(obj);
689
+ if(obj === -1) { return this.get_container_ul().children("li"); }
690
+ if(!obj || !obj.length) { return false; }
691
+ return obj.find("> ul > li");
692
+ },
693
+ /*
694
+ Function: is_parent
695
+ Check if a node is a parent.
696
+
697
+ Parameters:
698
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
699
+
700
+ Returns:
701
+ true - _obj_ has children or is closed (will be loaded)
702
+ false - _obj_ is not a valid node or has no children (leaf node)
703
+ */
704
+ is_parent : function (obj) { obj = this.get_node(obj); return obj && obj !== -1 && (obj.find("> ul > li:eq(0)").length || obj.hasClass("jstree-closed")); },
705
+ /*
706
+ Function: is_loaded
707
+ Check if a node is loaded.
708
+
709
+ Parameters:
710
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
711
+
712
+ Returns:
713
+ true - _obj_ has children or is leaf
714
+ false - _obj_ is currently loading or is not a leaf, but has no children
715
+ */
716
+ is_loaded : function (obj) { obj = this.get_node(obj); return obj && ( (obj === -1 && !this.get_container().find("> ul > li.jstree-loading").length) || ( obj !== -1 && !obj.hasClass('jstree-loading') && (obj.find('> ul > li').length || obj.hasClass('jstree-leaf')) ) ); },
717
+ /*
718
+ Function: is_loading
719
+ Check if a node is currently loading.
720
+
721
+ Parameters:
722
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
723
+
724
+ Returns:
725
+ true - _obj_ is currently loading
726
+ false - _obj_ is not currently loading
727
+ */
728
+ is_loading : function (obj) { obj = this.get_node(obj); return obj && ( (obj === -1 && this.get_container().find("> ul > li.jstree-loading").length) || (obj !== -1 && obj.hasClass("jstree-loading")) ); },
729
+ /*
730
+ Function: is_open
731
+ Check if a node is currently open.
732
+
733
+ Parameters:
734
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
735
+
736
+ Returns:
737
+ true - _obj_ is currently open
738
+ false - _obj_ is not currently open
739
+ */
740
+ is_open : function (obj) { obj = this.get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-open"); },
741
+ /*
742
+ Function: is_closed
743
+ Check if a node is currently closed.
744
+
745
+ Parameters:
746
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
747
+
748
+ Returns:
749
+ true - _obj_ is currently closed
750
+ false - _obj_ is not currently closed
751
+ */
752
+ is_closed : function (obj) { obj = this.get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-closed"); },
753
+ /*
754
+ Function: is_leaf
755
+ Check if a node is a leaf node (has no children).
756
+
757
+ Parameters:
758
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
759
+
760
+ Returns:
761
+ true - _obj_ is a leaf node
762
+ false - _obj_ is not a leaf node
763
+ */
764
+ is_leaf : function (obj) { obj = this.get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-leaf"); },
765
+ /*
766
+ Function: load_node
767
+ Load the children of a node.
768
+
769
+ Parameters:
770
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc. Use -1 to load the root nodes.
771
+ callback - a function to be executed in the tree's scope. Receives two arguments: _obj_ (the same node used to call load_node), _status_ (a boolean indicating if the node was loaded successfully.
772
+
773
+ Returns:
774
+ true - _obj_ is a valid node and will try loading it
775
+ false - _obj_ is not a valid node
776
+
777
+ Triggers:
778
+ <load_node>
779
+
780
+ See also:
781
+ <_load_node>
782
+
783
+ Event: load_node
784
+ This event is triggered in the *jstree* namespace when a node is loaded (succesfully or not).
785
+
786
+ Parameters:
787
+ data.inst - the instance
788
+ data.args - *array* the arguments passed to the function
789
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else).
790
+ data.rslt - *object* which contains two keys _obj_ (the loaded node) and _status_ - whether the node was loaded successfully.
791
+
792
+ Example:
793
+ > $("div").bind("load_node.jstree", function (e, data) { if(data.rslt.status) { data.inst.open_node(data.rslt.obj); } });
794
+ */
795
+ load_node : function (obj, callback) {
796
+ obj = this.get_node(obj);
797
+ if(!obj) { callback.call(this, obj, false); return false; }
798
+ // if(this.is_loading(obj)) { return true; }
799
+ if(obj !== -1) { obj.addClass("jstree-loading"); }
800
+ this._load_node(obj, $.proxy(function (status) {
801
+ if(obj !== -1) { obj.removeClass("jstree-loading"); }
802
+ this.__callback({ "obj" : obj, "status" : status });
803
+ if(callback) { callback.call(this, obj, status); }
804
+ }, this));
805
+ return true;
806
+ },
807
+ /*
808
+ Function: _load_node
809
+ Load the children of a node, but as opposed to <load_node> does not change any visual properties or trigger events. This function is used in <load_node> internally. The idea is for data source plugins to overwrite this function.
810
+ This implementation (from the *core*) only uses markup found in the tree container, and does not load async.
811
+
812
+ Parameters:
813
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc. Use -1 to load the root nodes.
814
+ callback - a function to be executed in the tree's scope. Receives one argument: _status_ (a boolean indicating if the node was loaded successfully).
815
+ */
816
+ _load_node : function (obj, callback) {
817
+ // if using async - empty the node first
818
+ if(obj === -1) {
819
+ this.get_container_ul().empty().append(this.data.core.original_container_html.clone(true));
820
+ }
821
+ callback.call(null, true);
822
+ },
823
+ /*
824
+ Function: open_node
825
+ Open a node so that its children are visible. If the node is not loaded try loading it first.
826
+
827
+ Parameters:
828
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
829
+ callback - a function to be executed in the tree's scope. Receives two arguments: _obj_ (the node being opened) and _status_ (a boolean indicating if the node was opened successfully).
830
+ animation - the duration in miliseconds of the slideDown animation. If not supplied the jQuery default is used. Please note that on IE6 a _0_ is enforced here due to performance issues.
831
+
832
+ Triggers:
833
+ <open_node>, <__after_open>
834
+
835
+ Event: open_node
836
+ This event is triggered in the *jstree* namespace when a node is successfully opened (but if animation is used this event is triggered BEFORE the animation completes). See <__after_open>.
837
+
838
+ Parameters:
839
+ data.inst - the instance
840
+ data.args - *array* the arguments passed to the function
841
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else).
842
+ data.rslt - *object* which contains a single key: _obj_ (the opened node).
843
+
844
+ Example:
845
+ > $("div").bind("open_node.jstree", function (e, data) {
846
+ > data.rslt.obj.find('> ul > .jstree-closed').each(function () {
847
+ > data.inst.open_node(this);
848
+ > }
849
+ > });
850
+
851
+ Event: __after_open
852
+ This event is triggered in the *jstree* namespace when a node is successfully opened AFTER the animation completes). See <open_node>.
853
+
854
+ Parameters:
855
+ data.inst - the instance
856
+ data.rslt - *object* which contains a single key: _obj_ (the opened node).
857
+
858
+ Example:
859
+ > $("div").bind("__after_open.jstree", function (e, data) {
860
+ > data.rslt.obj.find('> ul > .jstree-closed').each(function () {
861
+ > data.inst.open_node(this);
862
+ > }
863
+ > });
864
+ */
865
+ open_node : function (obj, callback, animation) {
866
+ obj = this.get_node(obj);
867
+ if(obj === -1 || !obj || !obj.length) { return false; }
868
+ if(!this.is_closed(obj)) { if(callback) { callback.call(this, obj, false); } return false; }
869
+ if(!this.is_loaded(obj)) { // TODO: is_loading?
870
+ this.load_node(obj, function (o, ok) {
871
+ return ok ? this.open_node(o, callback, animation) : callback ? callback.call(this, o, false) : false;
872
+ });
873
+ }
874
+ else {
875
+ var t = this;
876
+ obj
877
+ .children("ul").css("display","none").end()
878
+ .removeClass("jstree-closed").addClass("jstree-open")
879
+ // .children("ins").text("-").end()
880
+ .children("ul").stop(true, true).slideDown( ($.jstree.IS_IE6 ? 0 : animation), function () {
881
+ this.style.display = "";
882
+ t.__trigger("__after_open", { "rslt" : { "obj" : obj } });
883
+ });
884
+ if(callback) { callback.call(this, obj, true); }
885
+ this.__callback({ "obj" : obj });
886
+ }
887
+ },
888
+ /*
889
+ Function: close_node
890
+ Close a node so that its children are not visible.
891
+
892
+ Parameters:
893
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
894
+ animation - the duration in miliseconds of the slideDown animation. If not supplied the jQuery default is used. Please note that on IE6 a _0_ is enforced here due to performance issues.
895
+
896
+ Triggers:
897
+ <close_node>, <__after_close>
898
+
899
+ Event: close_node
900
+ This event is triggered in the *jstree* namespace when a node is closed (but if animation is used this event is triggered BEFORE the animation completes). See <__after_close>.
901
+
902
+ Parameters:
903
+ data.inst - the instance
904
+ data.args - *array* the arguments passed to the function
905
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else).
906
+ data.rslt - *object* which contains a single key: _obj_ (the closed node).
907
+
908
+ Example:
909
+ > $("div").bind("close_node.jstree", function (e, data) {
910
+ > data.rslt.obj.children('ul').remove();
911
+ > });
912
+
913
+ Event: __after_close
914
+ This event is triggered in the *jstree* namespace when a node is closed AFTER the animation completes). See <close_node>.
915
+
916
+ Parameters:
917
+ data.inst - the instance
918
+ data.rslt - *object* which contains a single key: _obj_ (the opened node).
919
+
920
+ Example:
921
+ > $("div").bind("__after_close.jstree", function (e, data) {
922
+ > data.rslt.obj.children('ul').remove();
923
+ > });
924
+ */
925
+ close_node : function (obj, animation) {
926
+ obj = this.get_node(obj);
927
+ if(!obj || !obj.length || !this.is_open(obj)) { return false; }
928
+ var t = this;
929
+ obj
930
+ .children("ul").attr("style","display:block !important").end()
931
+ .removeClass("jstree-open").addClass("jstree-closed")
932
+ // .children("ins").text("+").end()
933
+ .children("ul").stop(true, true).slideUp( ($.jstree.IS_IE6 ? 0 : animation), function () {
934
+ this.style.display = "";
935
+ t.__trigger("__after_close", { "rslt" : { "obj" : obj } });
936
+ });
937
+ this.__callback({ "obj" : obj });
938
+ },
939
+ /*
940
+ Function: toggle_node
941
+ If a node is closed - open it, if it is open - close it.
942
+
943
+ Parameters:
944
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
945
+ */
946
+ toggle_node : function (obj) {
947
+ if(this.is_closed(obj)) { return this.open_node(obj); }
948
+ if(this.is_open(obj)) { return this.close_node(obj); }
949
+ },
950
+ /*
951
+ Function: open_all
952
+ Open all nodes from a certain node down.
953
+
954
+ Parameters:
955
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc. If _-1_ is used or is omitted all nodes in the tree are opened.
956
+ animation - the duration of the slideDown animation when opening the nodes. If not set _0_ is enforced for performance issues.
957
+ original_obj - used internally to keep track of the recursion - do not set manually!
958
+
959
+ Triggers:
960
+ <open_all>
961
+
962
+ Event: open_all
963
+ This event is triggered in the *jstree* namespace when an open_all call completes.
964
+
965
+ Parameters:
966
+ data.inst - the instance
967
+ data.args - *array* the arguments passed to the function
968
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else).
969
+ data.rslt - *object* which contains a single key: _obj_ (the node used in the call).
970
+
971
+ Example:
972
+ > $("div").bind("open_all.jstree", function (e, data) {
973
+ > alert('DONE');
974
+ > });
975
+ */
976
+ open_all : function (obj, animation, original_obj) {
977
+ obj = obj ? this.get_node(obj) : -1;
978
+ obj = !obj || obj === -1 ? this.get_container_ul() : obj;
979
+ original_obj = original_obj || obj;
980
+ var _this = this;
981
+ obj = this.is_closed(obj) ? obj.find('li.jstree-closed').andSelf() : obj.find('li.jstree-closed');
982
+ obj.each(function () {
983
+ _this.open_node(
984
+ this,
985
+ _this.is_loaded(this) ?
986
+ false :
987
+ function(obj) { this.open_all(obj, animation, original_obj); },
988
+ animation || 0
989
+ );
990
+ });
991
+ if(original_obj.find('li.jstree-closed').length === 0) { this.__callback({ "obj" : original_obj }); }
992
+ },
993
+ /*
994
+ Function: close_all
995
+ Close all nodes from a certain node down.
996
+
997
+ Parameters:
998
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc. If _-1_ is used or is omitted all nodes in the tree are closed.
999
+ animation - the duration of the slideDown animation when closing the nodes. If not set _0_ is enforced for performance issues.
1000
+
1001
+ Triggers:
1002
+ <close_all>
1003
+
1004
+ Event: close_all
1005
+ This event is triggered in the *jstree* namespace when a close_all call completes.
1006
+
1007
+ Parameters:
1008
+ data.inst - the instance
1009
+ data.args - *array* the arguments passed to the function
1010
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else).
1011
+ data.rslt - *object* which contains a single key: _obj_ (the node used in the call).
1012
+
1013
+ Example:
1014
+ > $("div").bind("close_all.jstree", function (e, data) {
1015
+ > alert('DONE');
1016
+ > });
1017
+ */
1018
+ close_all : function (obj, animation) {
1019
+ obj = obj ? this._get_node(obj) : -1;
1020
+ var $obj = !obj || obj === -1 ? this.get_container_ul() : obj,
1021
+ _this = this;
1022
+ $obj = this.is_open($obj) ? $obj.find('li.jstree-open').andSelf() : $obj.find('li.jstree-open');
1023
+ $obj.each(function () { _this.close_node(this, animation || 0); });
1024
+ this.__callback({ "obj" : obj });
1025
+ },
1026
+ /*
1027
+ Function: clean_node
1028
+ This function converts inserted nodes to the required by jsTree format. It takes care of converting a simple unodreder list to the internally used markup.
1029
+ The core calls this function automatically when new data arrives (by binding to the <load_node> event).
1030
+ Each plugin may override this function to include its own source, but keep in mind to do it like that:
1031
+ > clean_node : function(obj) {
1032
+ > obj = this.__call_old();
1033
+ > obj.each(function () {
1034
+ > // do your stuff here
1035
+ > });
1036
+ > }
1037
+
1038
+ Parameters:
1039
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc. If _-1_ is used or is omitted all nodes in the tree are cleaned.
1040
+
1041
+ Returns:
1042
+ jQuery collection - the cleaned children of the original node.
1043
+ */
1044
+ clean_node : function (obj) {
1045
+ // DETACH maybe inside the "load_node" function? But what about animations, etc?
1046
+ obj = this.get_node(obj);
1047
+ obj = !obj || obj === -1 ? this.get_container().find("li") : obj.find("li").andSelf();
1048
+ var _this = this;
1049
+ return obj.each(function () {
1050
+ var t = $(this),
1051
+ d = t.data("jstree"),
1052
+ s = (d && d.opened) || t.hasClass("jstree-open") ? "open" : (d && d.closed) || t.children("ul").length ? "closed" : "leaf";
1053
+ if(d && d.opened) { delete d.opened; }
1054
+ if(d && d.closed) { delete d.closed; }
1055
+ t.removeClass("jstree-open jstree-closed jstree-leaf jstree-last");
1056
+ if(!t.children("a").length) {
1057
+ // allow for text and HTML markup inside the nodes
1058
+ t.contents().filter(function() { return this.nodeType === 3 || this.tagName !== 'UL'; }).wrapAll('<a href="#"></a>');
1059
+ // TODO: make this faster
1060
+ t.children('a').html(t.children('a').html().replace(/[\s\t\n]+$/,''));
1061
+ }
1062
+ else {
1063
+ if(!$.trim(t.children('a').attr('href'))) { t.children('a').attr("href","#"); }
1064
+ }
1065
+ if(!t.children("ins.jstree-ocl").length) {
1066
+ t.prepend("<ins class='jstree-icon jstree-ocl'>&#160;</ins>");
1067
+ }
1068
+ if(t.is(":last-child")) {
1069
+ t.addClass("jstree-last");
1070
+ }
1071
+ switch(s) {
1072
+ case 'leaf':
1073
+ t.addClass('jstree-leaf');
1074
+ break;
1075
+ case 'closed':
1076
+ t.addClass('jstree-open');
1077
+ _this.close_node(t, 0);
1078
+ break;
1079
+ case 'open':
1080
+ t.addClass('jstree-closed');
1081
+ _this.open_node(t, false, 0);
1082
+ break;
1083
+ }
1084
+ });
1085
+ },
1086
+ /*
1087
+ Function: correct_node
1088
+ This function corrects the open/closed/leaf state as data changes (as the user interacts with the tree).
1089
+ The core calls this function automatically when a node is opened, deleted or moved.
1090
+
1091
+ Parameters:
1092
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc. If _-1_ is used or is omitted the root nodes are processed.
1093
+
1094
+ Returns:
1095
+ jQuery collection - the processed children of the original node.
1096
+ */
1097
+ /* PROCESS SINGLE NODE (OR USE BOOLEAN single PARAM), CALL FROM CLEAN_NODE, LOSE THE EVENTS ABOVE */
1098
+ correct_node : function (obj, deep) {
1099
+ obj = this.get_node(obj);
1100
+ if(!obj || (obj === -1 && !deep)) { return false; }
1101
+ if(obj === -1) { obj = this.get_container().find('li'); }
1102
+ else { obj = deep ? obj.find('li').andSelf() : obj; }
1103
+ obj.each(function () {
1104
+ var obj = $(this);
1105
+ switch(!0) {
1106
+ case obj.hasClass("jstree-open") && !obj.find("> ul > li").length:
1107
+ obj.removeClass("jstree-open").addClass("jstree-leaf").children("ul").remove(); // children("ins").html("&#160;").end()
1108
+ break;
1109
+ case obj.hasClass("jstree-leaf") && !!obj.find("> ul > li").length:
1110
+ obj.removeClass("jstree-leaf").addClass("jstree-closed"); //.children("ins").html("+");
1111
+ break;
1112
+ }
1113
+ obj[obj.is(":last-child") ? 'addClass' : 'removeClass']("jstree-last");
1114
+ });
1115
+ return obj;
1116
+ },
1117
+ /*
1118
+ Function: scroll_to_node
1119
+ This function scrolls the container to the desired node (if needed).
1120
+
1121
+ Parameters:
1122
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
1123
+ */
1124
+ scroll_to_node : function (obj) {
1125
+ var c = this.get_container()[0], t;
1126
+ if(c.scrollHeight > c.offsetHeight) {
1127
+ obj = this.get_node(obj);
1128
+ if(!obj || obj === -1 || !obj.length || !obj.is(":visible")) { return; }
1129
+ t = obj.offset().top - this.get_container().offset().top;
1130
+ if(t < 0) {
1131
+ c.scrollTop = c.scrollTop + t - 1;
1132
+ }
1133
+ if(t + this.data.core.li_height + (c.scrollWidth > c.offsetWidth ? $.jstree.SCROLLBAR_WIDTH : 0) > c.offsetHeight) {
1134
+ c.scrollTop = c.scrollTop + (t - c.offsetHeight + this.data.core.li_height + 1 + (c.scrollWidth > c.offsetWidth ? $.jstree.SCROLLBAR_WIDTH : 0));
1135
+ }
1136
+ }
1137
+ },
1138
+ /*
1139
+ Function: get_state
1140
+ This function returns the current state of the tree (as collected from all active plugins).
1141
+ Plugin authors: pay special attention to the way this function is extended for new plugins. In your plugin code write:
1142
+ > get_state : function () {
1143
+ > var state = this.__call_old();
1144
+ > state.your-plugin-name = <some-value-you-collect>;
1145
+ > return state;
1146
+ > }
1147
+
1148
+ Returns:
1149
+ object - the current state of the instance
1150
+ */
1151
+ get_state : function () { // TODO: scroll position, theme
1152
+ var state = { 'open' : [], 'scroll' : { 'left' : this.get_container().scrollLeft(), 'top' : this.get_container().scrollTop() } };
1153
+ this.get_container_ul().find('.jstree-open').each(function () { if(this.id) { state.open.push(this.id); } });
1154
+ return state;
1155
+ },
1156
+ /*
1157
+ Function: set_state
1158
+ This function returns sets the state of the tree.
1159
+ Plugin authors: pay special attention to the way this function is extended for new plugins. In your plugin code write:
1160
+ > set_state : function (state, callback) {
1161
+ > if(this.__call_old()) {
1162
+ > if(state.your-plugin-name) {
1163
+ >
1164
+ > // restore using `state.your-plugin-name`
1165
+ > // if you need some async activity so that you return to this bit of code
1166
+ > // do not delete state.your-plugin-name and return false (see core's function for example)
1167
+ >
1168
+ > delete state.your-plugin-name;
1169
+ > this.set_state(state, callback);
1170
+ > return false;
1171
+ > }
1172
+ > return true;
1173
+ > }
1174
+ > return false;
1175
+ > }
1176
+
1177
+ Parameters:
1178
+ state - *object* the state to restore to
1179
+ callback - *function* this will be executed in the instance's scope once restoring is done
1180
+
1181
+ Returns:
1182
+ boolean - the return value is used to determine the phase of restoration
1183
+
1184
+ Triggers:
1185
+ <set_state>
1186
+
1187
+ Event: set_state
1188
+ This event is triggered in the *jstree* namespace when a set_state call completes.
1189
+
1190
+ Parameters:
1191
+ data.inst - the instance
1192
+ data.args - *array* the arguments passed to the function
1193
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else)
1194
+ */
1195
+ set_state : function (state, callback) {
1196
+ if(state) {
1197
+ if($.isArray(state.open)) {
1198
+ var res = true,
1199
+ t = this;
1200
+ //this.close_all();
1201
+ $.each(state.open.concat([]), function (i, v) {
1202
+ v = document.getElementById(v);
1203
+ if(v) {
1204
+ if(t.is_loaded(v)) {
1205
+ if(t.is_closed(v)) {
1206
+ t.open_node(v, false, 0);
1207
+ }
1208
+ $.vakata.array_remove(state.open, i);
1209
+ }
1210
+ else {
1211
+ if(!t.is_loading(v)) {
1212
+ t.open_node(v, $.proxy(function () { this.set_state(state); }, t), 0);
1213
+ }
1214
+ // there will be some async activity - so wait for it
1215
+ res = false;
1216
+ }
1217
+ }
1218
+ });
1219
+ if(res) {
1220
+ delete state.open;
1221
+ this.set_state(state, callback);
1222
+ }
1223
+ return false;
1224
+ }
1225
+ if(state.scroll) {
1226
+ if(state.scroll && typeof state.scroll.left !== 'undefined') {
1227
+ this.get_container().scrollLeft(state.scroll.left);
1228
+ }
1229
+ if(state.scroll && typeof state.scroll.top !== 'undefined') {
1230
+ this.get_container().scrollTop(state.scroll.top);
1231
+ }
1232
+ delete state.scroll;
1233
+ delete state.open;
1234
+ this.set_state(state, callback);
1235
+ return false;
1236
+ }
1237
+ if($.isEmptyObject(state)) {
1238
+ if(callback) { callback.call(this); }
1239
+ this.__callback();
1240
+ return false;
1241
+ }
1242
+ return true;
1243
+ }
1244
+ return false;
1245
+ },
1246
+ /*
1247
+ Function: refresh
1248
+ This function saves the current state, reloads the complete tree and returns it to the saved state.
1249
+
1250
+ Triggers:
1251
+ <refresh>
1252
+
1253
+ Event: refresh
1254
+ This event is triggered in the *jstree* namespace when a refresh call completes.
1255
+
1256
+ Parameters:
1257
+ data.inst - the instance
1258
+ */
1259
+ refresh : function () {
1260
+ this.data.core.state = this.get_state();
1261
+ this.load_node(-1, function (o, s) {
1262
+ if(s) {
1263
+ this.set_state($.extend(true, {}, this.data.core.state), function () { this.__trigger('refresh'); });
1264
+ }
1265
+ this.data.core.state = null;
1266
+ });
1267
+ },
1268
+ /*
1269
+ Function: get_text
1270
+ This function returns the title of the node.
1271
+
1272
+ Parameters:
1273
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
1274
+ remove_html - *boolean* set to _true_ to return plain text instead of HTML
1275
+
1276
+ Returns:
1277
+ string - the title of the node, specified by _obj_
1278
+ */
1279
+ get_text : function (obj, remove_html) {
1280
+ obj = this.get_node(obj);
1281
+ if(!obj || obj === -1 || !obj.length) { return false; }
1282
+ obj = obj.children("a:eq(0)").clone();
1283
+ obj.children(".jstree-icon").remove();
1284
+ return obj[ remove_html ? 'text' : 'html' ]();
1285
+ },
1286
+ /*
1287
+ Function: set_text
1288
+ This function sets the title of the node. This is a low-level function, you'd be better off using <rename>.
1289
+
1290
+ Parameters:
1291
+ obj - *mixed* this is used as a jquery selector - can be jQuery object, DOM node, string, etc.
1292
+ val - *string* the new title of the node (can be HTMl too)
1293
+
1294
+ Returns:
1295
+ boolean - was the rename successfull
1296
+
1297
+ Triggers:
1298
+ <set_text>
1299
+
1300
+ Event: set_text
1301
+ This event is triggered in the *jstree* namespace when a set_text call completes.
1302
+
1303
+ Parameters:
1304
+ data.inst - the instance
1305
+ data.args - *array* the arguments passed to the function
1306
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else)
1307
+ data.rslt - *object* which contains a two keys: _obj_ (the node) and _val_ (the new title).
1308
+
1309
+ Example:
1310
+ > $("div").bind("set_text.jstree", function (e, data) {
1311
+ > alert("Renamed to: " + data.rslt.val);
1312
+ > });
1313
+ */
1314
+ set_text : function (obj, val) {
1315
+ obj = this.get_node(obj);
1316
+ if(!obj || obj === -1 || !obj.length) { return false; }
1317
+ obj = obj.children("a:eq(0)");
1318
+ var tmp = obj.children("INS").clone();
1319
+ obj.html(val).prepend(tmp);
1320
+ this.__callback({ "obj" : obj, "text" : val });
1321
+ return true;
1322
+ },
1323
+ /*
1324
+ Function: parse_json
1325
+ This function returns a jQuery node after parsing a JSON object (a LI node for single elements or an UL node for multiple). This function will use the default title from <jstree.config.core.strings> if none is specified.
1326
+
1327
+ Parameters:
1328
+ node - *mixed* the input to parse
1329
+ > // can be a string
1330
+ > "The title of the parsed node"
1331
+ > // array of strings
1332
+ > [ "Node 1", "Node 2" ]
1333
+ > // an object
1334
+ > { "title" : "The title of the parsed node" }
1335
+ > // you can manipulate the output
1336
+ > { "title" : "The title of the parsed node", "li_attr" : { "id" : "id_for_li" }, "a_attr" : { "href" : "http://jstree.com" } }
1337
+ > // you can supply metadata, which you can later access using $(the_li_node).data()
1338
+ > { "title" : "The title of the parsed node", "data" : { <some-values-here> } }
1339
+ > // you can supply children (they can be objects too)
1340
+ > { "title" : "The title of the parsed node", "children" : [ "Node 1", { "title" : "Node 2" } ] }
1341
+
1342
+ Returns:
1343
+ jQuery - the LI (or UL) node which was produced from the JSON
1344
+ */
1345
+ parse_json : function (node) {
1346
+ var li, a, ul, t;
1347
+ if($.isArray(node)) {
1348
+ ul = $("<ul />");
1349
+ t = this;
1350
+ $.each(node, function (i, v) {
1351
+ ul.append(t.parse_json(v));
1352
+ });
1353
+ return ul;
1354
+ }
1355
+ if(typeof node === "undefined") { node = {}; }
1356
+ if(typeof node === "string") { node = { "title" : node }; }
1357
+ if(!node.li_attr) { node.li_attr = {}; }
1358
+ if(!node.a_attr) { node.a_attr = {}; }
1359
+ if(!node.a_attr.href) { node.a_attr.href = '#'; }
1360
+ if(!node.title) { node.title = this._get_string("New node"); }
1361
+
1362
+ li = $("<li />").attr(node.li_attr);
1363
+ a = $("<a />").attr(node.a_attr).html(node.title);
1364
+ ul = $("<ul />");
1365
+ if(node.data && !$.isEmptyObject(node.data)) { li.data(node.data); }
1366
+ if(
1367
+ node.children === true ||
1368
+ $.isArray(node.children) ||
1369
+ (li.data('jstree') && $.isArray(li.data('jstree').children))
1370
+ ) {
1371
+ if(!li.data('jstree')) {
1372
+ li.data('jstree', {});
1373
+ }
1374
+ li.data('jstree').closed = true;
1375
+ }
1376
+ li.append(a);
1377
+ if($.isArray(node.children)) {
1378
+ $.each(node.children, $.proxy(function (i, n) {
1379
+ ul.append(this.parse_json(n));
1380
+ }, this));
1381
+ li.append(ul);
1382
+ }
1383
+ return li;
1384
+ },
1385
+ /*
1386
+ Function: get_json
1387
+ This function returns the whole tree (or a single node) in JSON format.
1388
+ Each plugin may override this function to include its own source, but keep in mind to do it like that:
1389
+ > get_json : function(obj, is_callback) {
1390
+ > var r = this.__call_old();
1391
+ > if(is_callback) {
1392
+ > if(<some-condition>) { r.data.jstree.<some-key> = <some-value-this-plugin-will-process>; }
1393
+ > }
1394
+ > return r;
1395
+ > }
1396
+
1397
+ Parameters:
1398
+ obj - *mixed* the input to parse
1399
+ is_callback - do not modify this, jstree uses this parameter to keep track of the recursion
1400
+
1401
+ Returns:
1402
+ Array - an array consisting of objects (one for each node)
1403
+ */
1404
+ get_json : function (obj, is_callback) {
1405
+ obj = typeof obj !== 'undefined' ? this.get_node(obj) : false;
1406
+ if(!is_callback) {
1407
+ if(!obj || obj === -1) { obj = this.get_container_ul().children("li"); }
1408
+ }
1409
+ var r, t, li_attr = {}, a_attr = {}, tmp = {};
1410
+ if(!obj || !obj.length) { return false; }
1411
+ if(obj.length > 1 || !is_callback) {
1412
+ r = [];
1413
+ t = this;
1414
+ obj.each(function () {
1415
+ r.push(t.get_json($(this), true));
1416
+ });
1417
+ return r;
1418
+ }
1419
+ tmp = $.vakata.attributes(obj, true);
1420
+ $.each(tmp, function (i, v) {
1421
+ if(i === 'id') { li_attr[i] = v; return true; }
1422
+ v = $.trim(v.replace(/\bjstree[^ ]*/ig,'').replace(/\s+$/ig," "));
1423
+ if(v.length) { li_attr[i] = v; }
1424
+ });
1425
+ tmp = $.vakata.attributes(obj.children('a'), true);
1426
+ $.each(tmp, function (i, v) {
1427
+ if(i === 'id') { a_attr[i] = v; return true; }
1428
+ v = $.trim(v.replace(/\bjstree[^ ]*/ig,'').replace(/\s+$/ig," "));
1429
+ if(v.length) { a_attr[i] = v; }
1430
+ });
1431
+ r = {
1432
+ 'title' : this.get_text(obj),
1433
+ 'data' : $.extend(true, {}, obj.data() || {}),
1434
+ 'children' : false,
1435
+ 'li_attr' : li_attr,
1436
+ 'a_attr' : a_attr
1437
+ };
1438
+
1439
+ if(!r.data.jstree) { r.data.jstree = {}; }
1440
+ if(this.is_open(obj)) { r.data.jstree.opened = true; }
1441
+ if(this.is_closed(obj)) { r.data.jstree.closed = true; }
1442
+
1443
+ obj = obj.find('> ul > li');
1444
+ if(obj.length) {
1445
+ r.children = [];
1446
+ t = this;
1447
+ obj.each(function () {
1448
+ r.children.push(t.get_json($(this), true));
1449
+ });
1450
+ }
1451
+ return r;
1452
+ },
1453
+ /*
1454
+ Function: create_node
1455
+ This function creates a new node.
1456
+
1457
+ Parameters:
1458
+ parent - *mixed* the parent for the newly created node. This is used as a jquery selector, can be jQuery object, DOM node, string, etc. Use -1 to create a new root node.
1459
+ node - *mixed* the input to parse, check <parse_json> for description
1460
+ position - *mixed* where to create the new node. Can be one of "before", "after", "first", "last", "inside" or a numerical index.
1461
+ callback - optional function to be executed once the node is created
1462
+ is_loaded - used internally when a node needs to be loaded - do not pass this
1463
+
1464
+ Returns:
1465
+ jQuery - the LI node which was produced from the JSON (may return _undefined_ if the parent node is not yet loaded, but will create the node)
1466
+
1467
+ Triggers:
1468
+ <create_node>
1469
+
1470
+ Event: create_node
1471
+ This event is triggered in the *jstree* namespace when a new node is created.
1472
+
1473
+ Parameters:
1474
+ data.inst - the instance
1475
+ data.args - *array* the arguments passed to the function
1476
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else)
1477
+ data.rslt - *object* which contains a three keys: _obj_ (the node), _parent_ (the parent) and _position_ which is the numerical index.
1478
+
1479
+ Example:
1480
+ > $("div").bind("create_node.jstree", function (e, data) {
1481
+ > alert("Created `" + data.inst.get_text(data.rslt.obj) + "` inside `" + (data.rslt.parent === -1 ? 'the main container' : data.inst.get_text(data.rslt.parent)) + "` at index " + data.rslt.position);
1482
+ > });
1483
+ */
1484
+ create_node : function (par, node, pos, callback, is_loaded) {
1485
+ par = this.get_node(par);
1486
+ pos = typeof pos === "undefined" ? "last" : pos;
1487
+
1488
+ if(par !== -1 && !par.length) { return false; }
1489
+ if(!pos.match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {
1490
+ return this.load_node(par, function () { this.create_node(par, node, pos, callback, true); });
1491
+ }
1492
+
1493
+ var li = this.parse_json(node),
1494
+ tmp = par === -1 ? this.get_container() : par;
1495
+
1496
+ if(par === -1) {
1497
+ if(pos === "before") { pos = "first"; }
1498
+ if(pos === "after") { pos = "last"; }
1499
+ }
1500
+ switch(pos) {
1501
+ case "before":
1502
+ pos = par.index();
1503
+ par = this.get_parent(par);
1504
+ break;
1505
+ case "after" :
1506
+ pos = par.index() + 1;
1507
+ par = this.get_parent(par);
1508
+ break;
1509
+ case "inside":
1510
+ case "first":
1511
+ pos = 0;
1512
+ break;
1513
+ case "last":
1514
+ pos = tmp.children('ul').children('li').length;
1515
+ break;
1516
+ default:
1517
+ if(!pos) { pos = 0; }
1518
+ break;
1519
+ }
1520
+ if(!this.check("create_node", li, par, pos)) { return false; }
1521
+
1522
+ tmp = par === -1 ? this.get_container() : par;
1523
+ if(!tmp.children("ul").length) { tmp.append("<ul />"); }
1524
+ if(tmp.children("ul").children("li").eq(pos).length) {
1525
+ tmp.children("ul").children("li").eq(pos).before(li);
1526
+ }
1527
+ else {
1528
+ tmp.children("ul").append(li);
1529
+ }
1530
+ this.correct_node(par, true);
1531
+ if(callback) { callback.call(this, li); }
1532
+ this.__callback({ "obj" : li, "parent" : par, "position" : li.index() });
1533
+ return li;
1534
+ },
1535
+ /*
1536
+ Function: rename_node
1537
+ This function renames a new node.
1538
+
1539
+ Parameters:
1540
+ obj - *mixed* the node to rename. This is used as a jquery selector, can be jQuery object, DOM node, string, etc.
1541
+ val - *string* the new title
1542
+
1543
+ Triggers:
1544
+ <rename_node>
1545
+
1546
+ Event: rename_node
1547
+ This event is triggered in the *jstree* namespace when a node is renamed.
1548
+
1549
+ Parameters:
1550
+ data.inst - the instance
1551
+ data.args - *array* the arguments passed to the function
1552
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else)
1553
+ data.rslt - *object* which contains a three keys: _obj_ (the node), _title_ (the new title), _old_ (the old title)
1554
+
1555
+ Example:
1556
+ > $("div").bind("rename_node.jstree", function (e, data) {
1557
+ > alert("Node rename from `" + data.rslt.old + "` to `" + data.rslt.title "`");
1558
+ > });
1559
+ */
1560
+ rename_node : function (obj, val) {
1561
+ obj = this.get_node(obj);
1562
+ var old = this.get_text(obj);
1563
+ if(!this.check("rename_node", obj, this.get_parent(obj), val)) { return false; }
1564
+ if(obj && obj.length) {
1565
+ this.set_text(obj, val); // .apply(this, Array.prototype.slice.call(arguments))
1566
+ this.__callback({ "obj" : obj, "title" : val, "old" : old });
1567
+ }
1568
+ },
1569
+ /*
1570
+ Function: delete_node
1571
+ This function deletes a node.
1572
+
1573
+ Parameters:
1574
+ obj - *mixed* the node to remove. This is used as a jquery selector, can be jQuery object, DOM node, string, etc.
1575
+
1576
+ Returns:
1577
+ mixed - the removed node on success, _false_ on failure
1578
+
1579
+ Triggers:
1580
+ <delete_node>
1581
+
1582
+ Event: delete_node
1583
+ This event is triggered in the *jstree* namespace when a node is deleted.
1584
+
1585
+ Parameters:
1586
+ data.inst - the instance
1587
+ data.args - *array* the arguments passed to the function
1588
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else)
1589
+ data.rslt - *object* which contains a three keys: _obj_ (the removed node), _prev_ (the previous sibling of the removed node), _parent_ (the parent of the removed node)
1590
+
1591
+ Example:
1592
+ > $("div").bind("delete_node.jstree", function (e, data) {
1593
+ > alert("Node deleted!");
1594
+ > });
1595
+ */
1596
+ delete_node : function (obj) {
1597
+ obj = this.get_node(obj);
1598
+ if(!obj || obj === -1 || !obj.length) { return false; }
1599
+ var par = this.get_parent(obj),
1600
+ pre = this.get_prev(obj);
1601
+ if(!this.check("delete_node", obj, par, obj.index())) { return false; }
1602
+ obj = obj.detach();
1603
+ this.correct_node(par);
1604
+ this.correct_node(pre);
1605
+ this.__callback({ "obj" : obj, "prev" : pre, "parent" : par });
1606
+ return obj;
1607
+ },
1608
+ /*
1609
+ Function: check
1610
+ This function checks if a structure modification is valid.
1611
+
1612
+ Parameters:
1613
+ chk - *string* what are we checking (copy_node, move_node, rename_node, create_node, delete_node)
1614
+ obj - *mixed* the node.
1615
+ par - *mixed* the parent (if dealing with a move or copy - the new parent).
1616
+ pos - *mixed* the index among the parent's children (or the new name if dealing with a rename)
1617
+ is_copy - *boolean* is this a copy or a move call
1618
+
1619
+ Returns:
1620
+ boolean - _true_ if the modification is valid, _false_ otherwise
1621
+ */
1622
+ check : function (chk, obj, par, pos) {
1623
+ var tmp = chk.match(/^move_node|copy_node|create_node$/i) ? par : obj;
1624
+ tmp = tmp === -1 ? this.get_container().data('jstree') : tmp.data('jstree');
1625
+ if(tmp && tmp.functions && tmp.functions[chk]) {
1626
+ tmp = tmp.functions[chk];
1627
+ if($.isFunction(tmp)) {
1628
+ tmp = tmp.call(this, chk, obj, par, pos);
1629
+ }
1630
+ if(tmp === false) {
1631
+ return false;
1632
+ }
1633
+ }
1634
+ switch(chk) {
1635
+ case "create_node":
1636
+ break;
1637
+ case "rename_node":
1638
+ break;
1639
+ case "move_node":
1640
+ tmp = par === -1 ? this.get_container() : par;
1641
+ tmp = tmp.children('ul').children('li');
1642
+ if(tmp.length && tmp.index(obj) !== -1 && (pos === obj.index() || pos === obj.index() + 1)) {
1643
+ return false;
1644
+ }
1645
+ if(par !== -1 && par.parentsUntil('.jstree', 'li').andSelf().index(obj) !== -1) {
1646
+ return false;
1647
+ }
1648
+ break;
1649
+ case "copy_node":
1650
+ break;
1651
+ case "delete_node":
1652
+ break;
1653
+ }
1654
+ return true;
1655
+ },
1656
+ /*
1657
+ Function: move_node
1658
+ This function moves a node.
1659
+
1660
+ Parameters:
1661
+ obj - *mixed* the node to move. This is used as a jquery selector, can be jQuery object, DOM node, string, etc.
1662
+ parent - *mixed* the new parent. This is used as a jquery selector, can be jQuery object, DOM node, string, etc. Use -1 to promote to a root node.
1663
+ position - *mixed* where to create the new node. Can be one of "before", "after", "first", "last", "inside" or a numerical index.
1664
+ callback - optional function to be executed once the node is moved
1665
+ is_loaded - used internally when a node needs to be loaded - do not pass this
1666
+
1667
+ Returns:
1668
+ boolean - indicating if the move was successfull (may return _undefined_ if the parent node is not yet loaded, but will move the node)
1669
+
1670
+
1671
+ Triggers:
1672
+ <move_node>
1673
+
1674
+ Event: move_node
1675
+ This event is triggered in the *jstree* namespace when a node is moved.
1676
+
1677
+ Parameters:
1678
+ data.inst - the instance
1679
+ data.args - *array* the arguments passed to the function
1680
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else)
1681
+ data.rslt - *object* which contains a five keys: _obj_ (the node), _parent_ (the new parent) and _position_ which is the numerical index, _old_parent_ (the old parent) and is_multi (a boolean indicating if the node is coming from another tree instance)
1682
+
1683
+ Example:
1684
+ > $("div").bind("move_node.jstree", function (e, data) {
1685
+ > alert("Moved `" + data.inst.get_text(data.rslt.obj) + "` inside `" + (data.rslt.parent === -1 ? 'the main container' : data.inst.get_text(data.rslt.parent)) + "` at index " + data.rslt.position);
1686
+ > });
1687
+ */
1688
+ move_node : function (obj, par, pos, callback, is_loaded) {
1689
+ obj = this.get_node(obj);
1690
+ par = this.get_node(par);
1691
+ pos = typeof pos === "undefined" ? 0 : pos;
1692
+
1693
+ if(!obj || obj === -1 || !obj.length) { return false; }
1694
+ if(par !== -1 && !par.length) { return false; }
1695
+ if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {
1696
+ return this.load_node(par, function () { this.move_node(obj, par, pos, callback, true); });
1697
+ }
1698
+
1699
+ var old_par = this.get_parent(obj),
1700
+ new_par = (!pos.toString().match(/^(before|after)$/) || par === -1) ? par : this.get_parent(par),
1701
+ old_ins = $.jstree._reference(obj),
1702
+ new_ins = par === -1 ? this : $.jstree._reference(par),
1703
+ is_multi = (old_ins.get_index() !== new_ins.get_index());
1704
+ if(new_par === -1) {
1705
+ par = new_ins.get_container();
1706
+ if(pos === "before") { pos = "first"; }
1707
+ if(pos === "after") { pos = "last"; }
1708
+ }
1709
+ switch(pos) {
1710
+ case "before":
1711
+ pos = par.index();
1712
+ break;
1713
+ case "after" :
1714
+ pos = par.index() + 1;
1715
+ break;
1716
+ case "inside":
1717
+ case "first":
1718
+ pos = 0;
1719
+ break;
1720
+ case "last":
1721
+ pos = par.children('ul').children('li').length;
1722
+ break;
1723
+ default:
1724
+ if(!pos) { pos = 0; }
1725
+ break;
1726
+ }
1727
+ if(!this.check("move_node", obj, new_par, pos)) { return false; }
1728
+
1729
+ if(!par.children("ul").length) { par.append("<ul />"); }
1730
+ if(par.children("ul").children("li").eq(pos).length) {
1731
+ par.children("ul").children("li").eq(pos).before(obj);
1732
+ }
1733
+ else {
1734
+ par.children("ul").append(obj);
1735
+ }
1736
+
1737
+ if(is_multi) { // if multitree - clean the node recursively - remove all icons, and call deep clean_node
1738
+ obj.find('.jstree-icon, .jstree-ocl').remove();
1739
+ this.clean_node(obj);
1740
+ }
1741
+ old_ins.correct_node(old_par, true);
1742
+ new_ins.correct_node(new_par, true);
1743
+ if(callback) { callback.call(this, obj, new_par, obj.index()); }
1744
+ this.__callback({ "obj" : obj, "parent" : new_par, "position" : obj.index(), "old_parent" : old_par, "is_multi" : is_multi, 'old_instance' : old_ins, 'new_instance' : new_ins });
1745
+ return true;
1746
+ },
1747
+ /*
1748
+ Function: copy_node
1749
+ This function copies a node.
1750
+
1751
+ Parameters:
1752
+ obj - *mixed* the node to copy. This is used as a jquery selector, can be jQuery object, DOM node, string, etc.
1753
+ parent - *mixed* the new parent. This is used as a jquery selector, can be jQuery object, DOM node, string, etc. Use -1 to promote to a root node.
1754
+ position - *mixed* where to create the new node. Can be one of "before", "after", "first", "last", "inside" or a numerical index.
1755
+ callback - optional function to be executed once the node is moved
1756
+ is_loaded - used internally when a node needs to be loaded - do not pass this
1757
+
1758
+ Returns:
1759
+ boolean - indicating if the move was successfull (may return _undefined_ if the parent node is not yet loaded, but will move the node)
1760
+
1761
+
1762
+ Triggers:
1763
+ <copy_node>
1764
+
1765
+ Event: copy_node
1766
+ This event is triggered in the *jstree* namespace when a node is copied.
1767
+
1768
+ Parameters:
1769
+ data.inst - the instance
1770
+ data.args - *array* the arguments passed to the function
1771
+ data.plugin - *string* the function's plugin (here it will be _"core"_ but if the function is extended it may be something else)
1772
+ data.rslt - *object* which contains a five keys: _obj_ (the node), _parent_ (the new parent) and _position_ which is the numerical index, _original_ (the original object), is_multi (a boolean indicating if the node is coming from another tree instance, _old_instance_ (the source instance) and _new_instance_ (the receiving instance))
1773
+
1774
+ Example:
1775
+ > $("div").bind("copy_node.jstree", function (e, data) {
1776
+ > alert("Copied `" + data.inst.get_text(data.rslt.original) + "` inside `" + (data.rslt.parent === -1 ? 'the main container' : data.inst.get_text(data.rslt.parent)) + "` at index " + data.rslt.position);
1777
+ > });
1778
+ */
1779
+ copy_node : function (obj, par, pos, callback, is_loaded) {
1780
+ obj = this.get_node(obj);
1781
+ par = this.get_node(par);
1782
+ pos = typeof pos === "undefined" ? "last" : pos;
1783
+
1784
+ if(!obj || obj === -1 || !obj.length) { return false; }
1785
+ if(par !== -1 && !par.length) { return false; }
1786
+ if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {
1787
+ return this.load_node(par, function () { this.copy_node(obj, par, pos, callback, true); });
1788
+ }
1789
+ var org_obj = obj,
1790
+ old_par = this.get_parent(obj),
1791
+ new_par = (!pos.toString().match(/^(before|after)$/) || par === -1) ? par : this.get_parent(par),
1792
+ old_ins = $.jstree._reference(obj),
1793
+ new_ins = par === -1 ? this : $.jstree._reference(par),
1794
+ is_multi = (old_ins.get_index() !== new_ins.get_index());
1795
+
1796
+ obj = obj.clone(true);
1797
+ obj.find("*[id]").andSelf().each(function () {
1798
+ if(this.id) { this.id = "copy_" + this.id; }
1799
+ });
1800
+ if(new_par === -1) {
1801
+ par = new_ins.get_container();
1802
+ if(pos === "before") { pos = "first"; }
1803
+ if(pos === "after") { pos = "last"; }
1804
+ }
1805
+ switch(pos) {
1806
+ case "before":
1807
+ pos = par.index();
1808
+ break;
1809
+ case "after" :
1810
+ pos = par.index() + 1;
1811
+ break;
1812
+ case "inside":
1813
+ case "first":
1814
+ pos = 0;
1815
+ break;
1816
+ case "last":
1817
+ pos = par.children('ul').children('li').length;
1818
+ break;
1819
+ default:
1820
+ if(!pos) { pos = 0; }
1821
+ break;
1822
+ }
1823
+
1824
+ if(!this.check("copy_node", org_obj, new_par, pos)) { return false; }
1825
+
1826
+ if(!par.children("ul").length) { par.append("<ul />"); }
1827
+ if(par.children("ul").children("li").eq(pos).length) {
1828
+ par.children("ul").children("li").eq(pos).before(obj);
1829
+ }
1830
+ else {
1831
+ par.children("ul").append(obj);
1832
+ }
1833
+ if(is_multi) { // if multitree - clean the node recursively - remove all icons, and call deep clean_node
1834
+ obj.find('.jstree-icon, .jstree-ocl').remove();
1835
+ }
1836
+ new_ins.clean_node(obj); // always clean so that selected states, etc. are removed
1837
+ new_ins.correct_node(new_par, true); // no need to correct the old parent, as nothing has changed there
1838
+ if(callback) { callback.call(this, obj, new_par, obj.index(), org_obj); }
1839
+ this.__callback({ "obj" : obj, "parent" : new_par, "old_parent" : old_par, "position" : obj.index(), "original" : org_obj, "is_multi" : is_multi, 'old_instance' : old_ins, 'new_instance' : new_ins });
1840
+ return true;
1841
+ },
1842
+
1843
+ cut : function (obj) {
1844
+ obj = this.get_node(obj);
1845
+ if(!obj || obj === -1 || !obj.length) { return false; }
1846
+ ccp_node = obj;
1847
+ ccp_mode = 'move_node';
1848
+ this.__callback({ "obj" : obj });
1849
+ },
1850
+ copy : function (obj) {
1851
+ obj = this.get_node(obj);
1852
+ if(!obj || obj === -1 || !obj.length) { return false; }
1853
+ ccp_node = obj;
1854
+ ccp_mode = 'copy_node';
1855
+ this.__callback({ "obj" : obj });
1856
+ },
1857
+ can_paste : function () {
1858
+ return ccp_mode !== false && ccp_node !== false;
1859
+ },
1860
+ paste : function (obj) {
1861
+ obj = this.get_node(obj);
1862
+ if(!obj || !ccp_mode || !ccp_mode.match(/^(copy_node|move_node)$/) || !ccp_node) { return false; }
1863
+ this[ccp_mode](ccp_node, obj);
1864
+ this.__callback({ "obj" : obj, "nodes" : ccp_node, "mode" : ccp_mode });
1865
+ ccp_node = false;
1866
+ ccp_mode = false;
1867
+ },
1868
+
1869
+ edit : function (obj, default_text) {
1870
+ obj = this.get_node(obj);
1871
+ if(!obj || obj === -1 || !obj.length) { return false; }
1872
+ obj.parentsUntil(".jstree",".jstree-closed").each($.proxy(function (i, v) {
1873
+ this.open_node(v, false, 0);
1874
+ }, this));
1875
+ var rtl = this.data.core.rtl,
1876
+ w = this.get_container().width(),
1877
+ a = obj.children('a:eq(0)'),
1878
+ oi = obj.children("ins"),
1879
+ ai = a.children("ins"),
1880
+ w1 = oi.width() * oi.length,
1881
+ w2 = ai.width() * ai.length,
1882
+ t = typeof default_text === 'string' ? default_text : this.get_text(obj),
1883
+ h1 = $("<div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"),
1884
+ h2 = obj.css("position","relative").append(
1885
+ $("<input />", {
1886
+ "value" : t,
1887
+ "class" : "jstree-rename-input",
1888
+ // "size" : t.length,
1889
+ "css" : {
1890
+ "padding" : "0",
1891
+ "border" : "1px solid silver",
1892
+ "position" : "absolute",
1893
+ "left" : (rtl ? "auto" : (w1 + w2 + 4) + "px"),
1894
+ "right" : (rtl ? (w1 + w2 + 4) + "px" : "auto"),
1895
+ "top" : "0px",
1896
+ "height" : (this.data.core.li_height - 2) + "px",
1897
+ "lineHeight" : (this.data.core.li_height - 2) + "px",
1898
+ "width" : "150px" // will be set a bit further down
1899
+ },
1900
+ "blur" : $.proxy(function () {
1901
+ var i = obj.children(".jstree-rename-input"),
1902
+ v = i.val();
1903
+ if(v === "") { v = t; }
1904
+ h1.remove();
1905
+ i.remove();
1906
+ this.rename_node(obj, v);
1907
+ obj.css("position", "");
1908
+ }, this),
1909
+ "keyup" : function (event) {
1910
+ var key = event.keyCode || event.which;
1911
+ if(key === 27) { this.value = t; this.blur(); return; }
1912
+ else if(key === 13) { this.blur(); return; }
1913
+ else { h2.width(Math.min(h1.text("pW" + this.value).width(),w)); }
1914
+ },
1915
+ "keypress" : function(event) {
1916
+ var key = event.keyCode || event.which;
1917
+ if(key === 13) { return false; }
1918
+ }
1919
+ })
1920
+ ).children(".jstree-rename-input"),
1921
+ fn = {
1922
+ fontFamily : a.css('fontFamily') || '',
1923
+ fontSize : a.css('fontSize') || '',
1924
+ fontWeight : a.css('fontWeight') || '',
1925
+ fontStyle : a.css('fontStyle') || '',
1926
+ fontStretch : a.css('fontStretch') || '',
1927
+ fontVariant : a.css('fontVariant') || '',
1928
+ letterSpacing : a.css('letterSpacing') || '',
1929
+ wordSpacing : a.css('wordSpacing') || ''
1930
+ };
1931
+ this.set_text(obj, "");
1932
+ h1.css(fn);
1933
+ h2.css(fn).width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select();
1934
+ }
1935
+ }
1936
+ });
1937
+
1938
+ // add core CSS
1939
+ $(function() {
1940
+ var css_string = '' +
1941
+ '.jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } ' +
1942
+ '.jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; min-width:18px; } ' +
1943
+ '.jstree-rtl li { margin-left:0; margin-right:18px; } ' +
1944
+ '.jstree > ul > li { margin-left:0px; } ' +
1945
+ '.jstree-rtl > ul > li { margin-right:0px; } ' +
1946
+ '.jstree .jstree-icon { display:inline-block; text-decoration:none; margin:0; padding:0; vertical-align:top; } ' +
1947
+ '.jstree .jstree-ocl { width:18px; height:18px; text-align:center; line-height:18px; cursor:default; vertical-align:top; } ' +
1948
+ '.jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; padding:1px 2px; margin:0; } ' +
1949
+ '.jstree a:focus { outline: none; } ' +
1950
+ 'li.jstree-open > ul { display:block; } ' +
1951
+ 'li.jstree-closed > ul { display:none; } ';
1952
+ // Correct IE 6 (does not support the > CSS selector)
1953
+ if($.jstree.IS_IE6) {
1954
+ try { document.execCommand("BackgroundImageCache", false, true); } catch (err) { } // prevents flickers
1955
+ css_string += '' +
1956
+ '.jstree li { height:18px; margin-left:0; margin-right:0; } ' +
1957
+ '.jstree li li { margin-left:18px; } ' +
1958
+ '.jstree-rtl li li { margin-left:0px; margin-right:18px; } ' +
1959
+ 'li.jstree-open ul { display:block; } ' +
1960
+ 'li.jstree-closed ul { display:none !important; } ' +
1961
+ '.jstree li a { display:inline; border-width:0 !important; padding:0px 2px !important; } ';
1962
+ }
1963
+ // Correct IE 7 (shifts anchor nodes onhover)
1964
+ if($.jstree.IS_IE7) {
1965
+ css_string += '.jstree li a { border-width:0 !important; padding:0px 2px !important; } ';
1966
+ }
1967
+ // Correct ff2 lack of display:inline-block
1968
+ if($.jstree.IS_FF2) {
1969
+ css_string += '' +
1970
+ '.jstree .jstree-icon { display:-moz-inline-box; } ' +
1971
+ '.jstree li { line-height:12px; } ' + // WHY??
1972
+ '.jstree a { display:-moz-inline-box; } ';
1973
+ /* за темите
1974
+ '.jstree .jstree-no-icons .jstree-checkbox { display:-moz-inline-stack !important; } ';
1975
+ */
1976
+ }
1977
+ // the default stylesheet
1978
+ $.vakata.css.add_sheet({ str : css_string, title : "jstree" });
1979
+ });
1980
+ })(jQuery);
1981
+
1982
+ })();