jstree-rails 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
+ })();