5 * Copyright (c) 2010 Ivan Bozhanov (vakata.com)
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
11 * $Date: 2011-02-09 01:17:14 +0200 (ср, 09 февр 2011) $
15 /*jslint browser: true, onevar: true, undef: true, bitwise: true, strict: true */
16 /*global window : false, clearInterval: false, clearTimeout: false, document: false, setInterval: false, setTimeout: false, jQuery: false, navigator: false, XSLTProcessor: false, DOMParser: false, XMLSerializer: false*/
20 // top wrapper to prevent multiple inclusion (is this OK?)
21 (function () { if(jQuery
&& jQuery
.jstree
) { return; }
22 var is_ie6
= false, is_ie7
= false, is_ff2
= false;
28 // Common functions not related to jsTree
29 // decided to move them to a `vakata` "namespace"
31 // CSS related functions
33 get_css : function(rule_name
, delete_flag
, sheet
) {
34 rule_name
= rule_name
.toLowerCase();
35 var css_rules
= sheet
.cssRules
|| sheet
.rules
,
38 if(css_rules
.length
&& j
> css_rules
.length
+ 5) { return false; }
39 if(css_rules
[j
].selectorText
&& css_rules
[j
].selectorText
.toLowerCase() == rule_name
) {
40 if(delete_flag
=== true) {
41 if(sheet
.removeRule
) { sheet
.removeRule(j
); }
42 if(sheet
.deleteRule
) { sheet
.deleteRule(j
); }
45 else { return css_rules
[j
]; }
48 while (css_rules
[++j
]);
51 add_css : function(rule_name
, sheet
) {
52 if($.jstree
.css
.get_css(rule_name
, false, sheet
)) { return false; }
53 if(sheet
.insertRule
) { sheet
.insertRule(rule_name
+ ' { }', 0); } else { sheet
.addRule(rule_name
, null, 0); }
54 return $.vakata
.css
.get_css(rule_name
);
56 remove_css : function(rule_name
, sheet
) {
57 return $.vakata
.css
.get_css(rule_name
, true, sheet
);
59 add_sheet : function(opts
) {
60 var tmp
= false, is_new
= true;
62 if(opts
.title
) { tmp
= $("style[id='" + opts
.title
+ "-stylesheet']")[0]; }
63 if(tmp
) { is_new
= false; }
65 tmp
= document
.createElement("style");
66 tmp
.setAttribute('type',"text/css");
67 if(opts
.title
) { tmp
.setAttribute("id", opts
.title
+ "-stylesheet"); }
71 document
.getElementsByTagName("head")[0].appendChild(tmp
);
72 //tmp.styleSheet.cssText = opts.str;
73 var setFunc = function(){
75 tmp
.styleSheet
.cssText
= opts
.str
;
78 if(tmp
.styleSheet
.disabled
){
79 setTimeout(setFunc
, 10);
85 tmp
.styleSheet
.cssText
= tmp
.styleSheet
.cssText
+ " " + opts
.str
;
89 tmp
.appendChild(document
.createTextNode(opts
.str
));
90 document
.getElementsByTagName("head")[0].appendChild(tmp
);
92 return tmp
.sheet
|| tmp
.styleSheet
;
95 if(document
.createStyleSheet
) {
96 try { tmp
= document
.createStyleSheet(opts
.url
); } catch (e
) { }
99 tmp
= document
.createElement('link');
100 tmp
.rel
= 'stylesheet';
101 tmp
.type
= 'text/css';
104 document
.getElementsByTagName("head")[0].appendChild(tmp
);
105 return tmp
.styleSheet
;
112 var instances
= [], // instance array (used by $.jstree.reference/create/focused)
113 focused_instance
= -1, // the index in the instance array of the currently focused instance
114 plugins
= {}, // list of included plugins
115 prepared_move
= {}; // for the move_node function
117 // jQuery plugin wrapper (thanks to jquery UI widget function)
118 $.fn
.jstree = function (settings
) {
119 var isMethodCall
= (typeof settings
== 'string'), // is this a method call like $().jstree("open_node")
120 args
= Array
.prototype.slice
.call(arguments
, 1),
123 // if a method call execute the method on all selected instances
125 if(settings
.substring(0, 1) == '_') { return returnValue
; }
126 this.each(function() {
127 var instance
= instances
[$.data(this, "jstree_instance_id")],
128 methodValue
= (instance
&& $.isFunction(instance
[settings
])) ? instance
[settings
].apply(instance
, args
) : instance
;
129 if(typeof methodValue
!== "undefined" && (settings
.indexOf("is_") === 0 || (methodValue
!== true && methodValue
!== false))) { returnValue
= methodValue
; return false; }
133 this.each(function() {
134 // extend settings and allow for multiple hashes and $.data
135 var instance_id
= $.data(this, "jstree_instance_id"),
137 b
= settings
? $.extend({}, true, settings
) : {},
142 if(c
.data("jstree")) { a
.push(c
.data("jstree")); }
143 b
= a
.length
? $.extend
.apply(null, [true, b
].concat(a
)) : b
;
145 // if an instance already exists, destroy it first
146 if(typeof instance_id
!== "undefined" && instances
[instance_id
]) { instances
[instance_id
].destroy(); }
147 // push a new empty object to the instances array
148 instance_id
= parseInt(instances
.push({}),10) - 1;
149 // store the jstree instance id to the container element
150 $.data(this, "jstree_instance_id", instance_id
);
151 // clean up all plugins
152 b
.plugins
= $.isArray(b
.plugins
) ? b
.plugins
: $.jstree
.defaults
.plugins
.slice();
153 b
.plugins
.unshift("core");
154 // only unique plugins
155 b
.plugins
= b
.plugins
.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",");
157 // extend defaults with passed data
158 s
= $.extend(true, {}, $.jstree
.defaults
, b
);
159 s
.plugins
= b
.plugins
;
160 $.each(plugins
, function (i
, val
) {
161 if($.inArray(i
, s
.plugins
) === -1) { s
[i
] = null; delete s
[i
]; }
166 // push the new object to the instances array (at the same time set the default classes to the container) and init
167 instances
[instance_id
] = new $.jstree
._instance(instance_id
, $(this).addClass("jstree jstree-" + instance_id
), s
);
168 // init all activated plugins for this instance
169 $.each(instances
[instance_id
]._get_settings().plugins
, function (i
, val
) { instances
[instance_id
].data
[val
] = {}; });
170 $.each(instances
[instance_id
]._get_settings().plugins
, function (i
, val
) { if(plugins
[val
]) { plugins
[val
].__init
.apply(instances
[instance_id
]); } });
171 // initialize the instance
172 setTimeout(function() { if(instances
[instance_id
]) { instances
[instance_id
].init(); } }, 0);
175 // return the jquery selection (or if it was a method call that returned a value - the returned value)
178 // object to store exposed functions and objects
183 _focused : function () { return instances
[focused_instance
] || null; },
184 _reference : function (needle
) {
185 // get by instance id
186 if(instances
[needle
]) { return instances
[needle
]; }
187 // get by DOM (if still no luck - return null
189 if(!o
.length
&& typeof needle
=== "string") { o
= $("#" + needle
); }
190 if(!o
.length
) { return null; }
191 return instances
[o
.closest(".jstree").data("jstree_instance_id")] || null;
193 _instance : function (index
, container
, settings
) {
194 // for plugins to store data in
195 this.data
= { core
: {} };
196 this.get_settings = function () { return $.extend(true, {}, settings
); };
197 this._get_settings = function () { return settings
; };
198 this.get_index = function () { return index
; };
199 this.get_container = function () { return container
; };
200 this.get_container_ul = function () { return container
.children("ul:eq(0)"); };
201 this._set_settings = function (s
) {
202 settings
= $.extend(true, {}, settings
, s
);
206 plugin : function (pname
, pdata
) {
207 pdata
= $.extend({}, {
213 plugins
[pname
] = pdata
;
215 $.jstree
.defaults
[pname
] = pdata
.defaults
;
216 $.each(pdata
._fn
, function (i
, val
) {
218 val
.old
= $.jstree
._fn
[i
];
219 $.jstree
._fn
[i
] = function () {
222 args
= Array
.prototype.slice
.call(arguments
),
223 evnt
= new $.Event("before.jstree"),
226 if(this.data
.core
.locked
=== true && i
!== "unlock" && i
!== "is_locked") { return; }
228 // Check if function belongs to the included plugins of this instance
230 if(func
&& func
.plugin
&& $.inArray(func
.plugin
, this._get_settings().plugins
) !== -1) { break; }
233 if(!func
) { return; }
235 // context and function to trigger events, then finally call the function
236 if(i
.indexOf("_") === 0) {
237 rslt
= func
.apply(this, args
);
240 rslt
= this.get_container().triggerHandler(evnt
, { "func" : i
, "inst" : this, "args" : args
, "plugin" : func
.plugin
});
241 if(rslt
=== false) { return; }
242 if(typeof rslt
!== "undefined") { args
= rslt
; }
246 __callback : function (data
) {
247 this.get_container().triggerHandler( i
+ '.jstree', { "inst" : this, "args" : args
, "rslt" : data
, "rlbk" : rlbk
});
249 __rollback : function () {
250 rlbk
= this.get_rollback();
253 __call_old : function (replace_arguments
) {
254 return func
.old
.apply(this, (replace_arguments
? Array
.prototype.slice
.call(arguments
, 1) : args
) );
262 $.jstree
._fn
[i
].old
= val
.old
;
263 $.jstree
._fn
[i
].plugin
= pname
;
266 rollback : function (rb
) {
268 if(!$.isArray(rb
)) { rb
= [ rb
]; }
269 $.each(rb
, function (i
, val
) {
270 instances
[val
.i
].set_rollback(val
.h
, val
.d
);
275 // set the prototype for all instances
276 $.jstree
._fn
= $.jstree
._instance
.prototype = {};
278 // load the css when DOM is ready
280 // code is copied from jQuery ($.browser is deprecated + there is a bug in IE)
281 var u
= navigator
.userAgent
.toLowerCase(),
282 v
= (u
.match( /.+?(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
284 '.jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } ' +
285 '.jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; min-width:18px; } ' +
286 '.jstree-rtl li { margin-left:0; margin-right:18px; } ' +
287 '.jstree > ul > li { margin-left:0px; } ' +
288 '.jstree-rtl > ul > li { margin-right:0px; } ' +
289 '.jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } ' +
290 '.jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } ' +
291 '.jstree a:focus { outline: none; } ' +
292 '.jstree a > ins { height:16px; width:16px; } ' +
293 '.jstree a > .jstree-icon { margin-right:3px; } ' +
294 '.jstree-rtl a > .jstree-icon { margin-left:3px; margin-right:0; } ' +
295 'li.jstree-open > ul { display:block; } ' +
296 'li.jstree-closed > ul { display:none; } ';
297 // Correct IE 6 (does not support the > CSS selector)
298 if(/msie/.test(u
) && parseInt(v
, 10) == 6) {
301 // fix image flicker and lack of caching
303 document
.execCommand("BackgroundImageCache", false, true);
307 '.jstree li { height:18px; margin-left:0; margin-right:0; } ' +
308 '.jstree li li { margin-left:18px; } ' +
309 '.jstree-rtl li li { margin-left:0px; margin-right:18px; } ' +
310 'li.jstree-open ul { display:block; } ' +
311 'li.jstree-closed ul { display:none !important; } ' +
312 '.jstree li a { display:inline; border-width:0 !important; padding:0px 2px !important; } ' +
313 '.jstree li a ins { height:16px; width:16px; margin-right:3px; } ' +
314 '.jstree-rtl li a ins { margin-right:0px; margin-left:3px; } ';
316 // Correct IE 7 (shifts anchor nodes onhover)
317 if(/msie/.test(u
) && parseInt(v
, 10) == 7) {
319 css_string
+= '.jstree li a { border-width:0 !important; padding:0px 2px !important; } ';
321 // correct ff2 lack of display:inline-block
322 if(!/compatible/.test(u
) && /mozilla/.test(u
) && parseFloat(v
, 10) < 1.9) {
325 '.jstree ins { display:-moz-inline-box; } ' +
326 '.jstree li { line-height:12px; } ' + // WHY??
327 '.jstree a { display:-moz-inline-box; } ' +
328 '.jstree .jstree-no-icons .jstree-checkbox { display:-moz-inline-stack !important; } ';
329 /* this shouldn't be here as it is theme specific */
331 // the default stylesheet
332 $.vakata
.css
.add_sheet({ str
: css_string
, title
: "jstree" });
335 // core functions (open, close, create, update, delete)
336 $.jstree
.plugin("core", {
337 __init : function () {
338 this.data
.core
.locked
= false;
339 this.data
.core
.to_open
= this.get_settings().core
.initially_open
;
340 this.data
.core
.to_load
= this.get_settings().core
.initially_load
;
348 notify_plugins
: true,
352 loading
: "Loading ...",
353 new_node
: "New node",
354 multiple_selection
: "Multiple selection"
360 if(this._get_settings().core
.rtl
) {
361 this.get_container().addClass("jstree-rtl").css("direction", "rtl");
363 this.get_container().html("<ul><li class='jstree-last jstree-leaf'><ins> </ins><a class='jstree-loading' href='#'><ins class='jstree-icon'> </ins>" + this._get_string("loading") + "</a></li></ul>");
364 this.data
.core
.li_height
= this.get_container_ul().find("li.jstree-closed, li.jstree-leaf").eq(0).height() || 18;
367 .delegate("li > ins", "click.jstree", $.proxy(function (event
) {
368 var trgt
= $(event
.target
);
369 // if(trgt.is("ins") && event.pageY - trgt.offset().top < this.data.core.li_height) { this.toggle_node(trgt); }
370 this.toggle_node(trgt
);
372 .bind("mousedown.jstree", $.proxy(function () {
373 this.set_focus(); // This used to be setTimeout(set_focus,0) - why?
375 .bind("dblclick.jstree", function (event
) {
377 if(document
.selection
&& document
.selection
.empty
) { document
.selection
.empty(); }
379 if(window
.getSelection
) {
380 sel
= window
.getSelection();
382 sel
.removeAllRanges();
388 if(this._get_settings().core
.notify_plugins
) {
390 .bind("load_node.jstree", $.proxy(function (e
, data
) {
391 var o
= this._get_node(data
.rslt
.obj
),
393 if(o
=== -1) { o
= this.get_container_ul(); }
394 if(!o
.length
) { return; }
395 o
.find("li").each(function () {
397 if(th
.data("jstree")) {
398 $.each(th
.data("jstree"), function (plugin
, values
) {
399 if(t
.data
[plugin
] && $.isFunction(t
["_" + plugin
+ "_notify"])) {
400 t
["_" + plugin
+ "_notify"].call(t
, th
, values
);
407 if(this._get_settings().core
.load_open
) {
409 .bind("load_node.jstree", $.proxy(function (e
, data
) {
410 var o
= this._get_node(data
.rslt
.obj
),
412 if(o
=== -1) { o
= this.get_container_ul(); }
413 if(!o
.length
) { return; }
414 o
.find("li.jstree-open:not(:has(ul))").each(function () {
415 t
.load_node(this, $.noop
, $.noop
);
420 this.load_node(-1, function () { this.loaded(); this.reload_nodes(); });
422 destroy : function () {
424 n
= this.get_index(),
425 s
= this._get_settings(),
428 $.each(s
.plugins
, function (i
, val
) {
429 try { plugins
[val
].__destroy
.apply(_this
); } catch(err
) { }
432 // set focus to another instance if this one is focused
433 if(this.is_focused()) {
434 for(i
in instances
) {
435 if(instances
.hasOwnProperty(i
) && i
!= n
) {
436 instances
[i
].set_focus();
441 // if no other instance found
442 if(n
=== focused_instance
) { focused_instance
= -1; }
443 // remove all traces of jstree in the DOM (only the ones set using jstree*) and cleans all events
446 .undelegate(".jstree")
447 .removeData("jstree_instance_id")
448 .find("[class^='jstree']")
450 .attr("class", function () { return this.className
.replace(/jstree[^ ]*|$/ig,''); });
452 .unbind(".jstree-" + n
)
453 .undelegate(".jstree-" + n
);
454 // remove the actual data
459 _core_notify : function (n
, data
) {
461 this.open_node(n
, false, true);
466 this.data
.core
.locked
= true;
467 this.get_container().children("ul").addClass("jstree-locked").css("opacity","0.7");
470 unlock : function () {
471 this.data
.core
.locked
= false;
472 this.get_container().children("ul").removeClass("jstree-locked").css("opacity","1");
475 is_locked : function () { return this.data
.core
.locked
; },
476 save_opened : function () {
478 this.data
.core
.to_open
= [];
479 this.get_container_ul().find("li.jstree-open").each(function () {
480 if(this.id
) { _this
.data
.core
.to_open
.push("#" + this.id
.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:")); }
482 this.__callback(_this
.data
.core
.to_open
);
484 save_loaded : function () { },
485 reload_nodes : function (is_callback
) {
491 this.data
.core
.reopen
= false;
492 this.data
.core
.refreshing
= true;
493 this.data
.core
.to_open
= $.map($.makeArray(this.data
.core
.to_open
), function (n
) { return "#" + n
.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); });
494 this.data
.core
.to_load
= $.map($.makeArray(this.data
.core
.to_load
), function (n
) { return "#" + n
.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); });
495 if(this.data
.core
.to_open
.length
) {
496 this.data
.core
.to_load
= this.data
.core
.to_load
.concat(this.data
.core
.to_open
);
499 if(this.data
.core
.to_load
.length
) {
500 $.each(this.data
.core
.to_load
, function (i
, val
) {
501 if(val
== "#") { return true; }
502 if($(val
).length
) { current
.push(val
); }
503 else { remaining
.push(val
); }
506 this.data
.core
.to_load
= remaining
;
507 $.each(current
, function (i
, val
) {
508 if(!_this
._is_loaded(val
)) {
509 _this
.load_node(val
, function () { _this
.reload_nodes(true); }, function () { _this
.reload_nodes(true); });
515 if(this.data
.core
.to_open
.length
) {
516 $.each(this.data
.core
.to_open
, function (i
, val
) {
517 _this
.open_node(val
, false, true);
521 // TODO: find a more elegant approach to syncronizing returning requests
522 if(this.data
.core
.reopen
) { clearTimeout(this.data
.core
.reopen
); }
523 this.data
.core
.reopen
= setTimeout(function () { _this
.__callback({}, _this
); }, 50);
524 this.data
.core
.refreshing
= false;
528 reopen : function () {
530 if(this.data
.core
.to_open
.length
) {
531 $.each(this.data
.core
.to_open
, function (i
, val
) {
532 _this
.open_node(val
, false, true);
537 refresh : function (obj
) {
540 if(!obj
) { obj
= -1; }
541 obj
= this._get_node(obj
);
542 if(!obj
) { obj
= -1; }
543 if(obj
!== -1) { obj
.children("UL").remove(); }
544 else { this.get_container_ul().empty(); }
545 this.load_node(obj
, function () { _this
.__callback({ "obj" : obj
}); _this
.reload_nodes(); });
547 // Dummy function to fire after the first load (so that there is a jstree.loaded event)
548 loaded : function () {
552 set_focus : function () {
553 if(this.is_focused()) { return; }
554 var f
= $.jstree
._focused();
555 if(f
) { f
.unset_focus(); }
557 this.get_container().addClass("jstree-focused");
558 focused_instance
= this.get_index();
561 is_focused : function () {
562 return focused_instance
== this.get_index();
564 unset_focus : function () {
565 if(this.is_focused()) {
566 this.get_container().removeClass("jstree-focused");
567 focused_instance
= -1;
573 _get_node : function (obj
) {
574 var $obj
= $(obj
, this.get_container());
575 if($obj
.is(".jstree") || obj
== -1) { return -1; }
576 $obj
= $obj
.closest("li", this.get_container());
577 return $obj
.length
? $obj
: false;
579 _get_next : function (obj
, strict
) {
580 obj
= this._get_node(obj
);
581 if(obj
=== -1) { return this.get_container().find("> ul > li:first-child"); }
582 if(!obj
.length
) { return false; }
583 if(strict
) { return (obj
.nextAll("li").size() > 0) ? obj
.nextAll("li:eq(0)") : false; }
585 if(obj
.hasClass("jstree-open")) { return obj
.find("li:eq(0)"); }
586 else if(obj
.nextAll("li").size() > 0) { return obj
.nextAll("li:eq(0)"); }
587 else { return obj
.parentsUntil(".jstree","li").next("li").eq(0); }
589 _get_prev : function (obj
, strict
) {
590 obj
= this._get_node(obj
);
591 if(obj
=== -1) { return this.get_container().find("> ul > li:last-child"); }
592 if(!obj
.length
) { return false; }
593 if(strict
) { return (obj
.prevAll("li").length
> 0) ? obj
.prevAll("li:eq(0)") : false; }
595 if(obj
.prev("li").length
) {
596 obj
= obj
.prev("li").eq(0);
597 while(obj
.hasClass("jstree-open")) { obj
= obj
.children("ul:eq(0)").children("li:last"); }
600 else { var o
= obj
.parentsUntil(".jstree","li:eq(0)"); return o
.length
? o
: false; }
602 _get_parent : function (obj
) {
603 obj
= this._get_node(obj
);
604 if(obj
== -1 || !obj
.length
) { return false; }
605 var o
= obj
.parentsUntil(".jstree", "li:eq(0)");
606 return o
.length
? o
: -1;
608 _get_children : function (obj
) {
609 obj
= this._get_node(obj
);
610 if(obj
=== -1) { return this.get_container().children("ul:eq(0)").children("li"); }
611 if(!obj
.length
) { return false; }
612 return obj
.children("ul:eq(0)").children("li");
614 get_path : function (obj
, id_mode
) {
617 obj
= this._get_node(obj
);
618 if(obj
=== -1 || !obj
|| !obj
.length
) { return false; }
619 obj
.parentsUntil(".jstree", "li").each(function () {
620 p
.push( id_mode
? this.id
: _this
.get_text(this) );
623 p
.push( id_mode
? obj
.attr("id") : this.get_text(obj
) );
628 _get_string : function (key
) {
629 return this._get_settings().core
.strings
[key
] || key
;
632 is_open : function (obj
) { obj
= this._get_node(obj
); return obj
&& obj
!== -1 && obj
.hasClass("jstree-open"); },
633 is_closed : function (obj
) { obj
= this._get_node(obj
); return obj
&& obj
!== -1 && obj
.hasClass("jstree-closed"); },
634 is_leaf : function (obj
) { obj
= this._get_node(obj
); return obj
&& obj
!== -1 && obj
.hasClass("jstree-leaf"); },
635 correct_state : function (obj
) {
636 obj
= this._get_node(obj
);
637 if(!obj
|| obj
=== -1) { return false; }
638 obj
.removeClass("jstree-closed jstree-open").addClass("jstree-leaf").children("ul").remove();
639 this.__callback({ "obj" : obj
});
642 open_node : function (obj
, callback
, skip_animation
) {
643 obj
= this._get_node(obj
);
644 if(!obj
.length
) { return false; }
645 if(!obj
.hasClass("jstree-closed")) { if(callback
) { callback
.call(); } return false; }
646 var s
= skip_animation
|| is_ie6
? 0 : this._get_settings().core
.animation
,
648 if(!this._is_loaded(obj
)) {
649 obj
.children("a").addClass("jstree-loading");
650 this.load_node(obj
, function () { t
.open_node(obj
, callback
, skip_animation
); }, callback
);
653 if(this._get_settings().core
.open_parents
) {
654 obj
.parentsUntil(".jstree",".jstree-closed").each(function () {
655 t
.open_node(this, false, true);
658 if(s
) { obj
.children("ul").css("display","none"); }
659 obj
.removeClass("jstree-closed").addClass("jstree-open").children("a").removeClass("jstree-loading");
660 if(s
) { obj
.children("ul").stop(true, true).slideDown(s
, function () { this.style
.display
= ""; t
.after_open(obj
); }); }
661 else { t
.after_open(obj
); }
662 this.__callback({ "obj" : obj
});
663 if(callback
) { callback
.call(); }
666 after_open : function (obj
) { this.__callback({ "obj" : obj
}); },
667 close_node : function (obj
, skip_animation
) {
668 obj
= this._get_node(obj
);
669 var s
= skip_animation
|| is_ie6
? 0 : this._get_settings().core
.animation
,
671 if(!obj
.length
|| !obj
.hasClass("jstree-open")) { return false; }
672 if(s
) { obj
.children("ul").attr("style","display:block !important"); }
673 obj
.removeClass("jstree-open").addClass("jstree-closed");
674 if(s
) { obj
.children("ul").stop(true, true).slideUp(s
, function () { this.style
.display
= ""; t
.after_close(obj
); }); }
675 else { t
.after_close(obj
); }
676 this.__callback({ "obj" : obj
});
678 after_close : function (obj
) { this.__callback({ "obj" : obj
}); },
679 toggle_node : function (obj
) {
680 obj
= this._get_node(obj
);
681 if(obj
.hasClass("jstree-closed")) { return this.open_node(obj
); }
682 if(obj
.hasClass("jstree-open")) { return this.close_node(obj
); }
684 open_all : function (obj
, do_animation
, original_obj
) {
685 obj
= obj
? this._get_node(obj
) : -1;
686 if(!obj
|| obj
=== -1) { obj
= this.get_container_ul(); }
688 obj
= obj
.find("li.jstree-closed");
692 if(obj
.is(".jstree-closed")) { obj
= obj
.find("li.jstree-closed").andSelf(); }
693 else { obj
= obj
.find("li.jstree-closed"); }
696 obj
.each(function () {
698 if(!_this
._is_loaded(this)) { _this
.open_node(this, function() { _this
.open_all(__this
, do_animation
, original_obj
); }, !do_animation
); }
699 else { _this
.open_node(this, false, !do_animation
); }
701 // so that callback is fired AFTER all nodes are open
702 if(original_obj
.find('li.jstree-closed').length
=== 0) { this.__callback({ "obj" : original_obj
}); }
704 close_all : function (obj
, do_animation
) {
706 obj
= obj
? this._get_node(obj
) : this.get_container();
707 if(!obj
|| obj
=== -1) { obj
= this.get_container_ul(); }
708 obj
.find("li.jstree-open").andSelf().each(function () { _this
.close_node(this, !do_animation
); });
709 this.__callback({ "obj" : obj
});
711 clean_node : function (obj
) {
712 obj
= obj
&& obj
!= -1 ? $(obj
) : this.get_container_ul();
713 obj
= obj
.is("li") ? obj
.find("li").andSelf() : obj
.find("li");
714 obj
.removeClass("jstree-last")
715 .filter("li:last-child").addClass("jstree-last").end()
717 .not(".jstree-open").removeClass("jstree-leaf").addClass("jstree-closed");
718 obj
.not(".jstree-open, .jstree-closed").addClass("jstree-leaf").children("ul").remove();
719 this.__callback({ "obj" : obj
});
722 get_rollback : function () {
724 return { i
: this.get_index(), h
: this.get_container().children("ul").clone(true), d
: this.data
};
726 set_rollback : function (html
, data
) {
727 this.get_container().empty().append(html
);
731 // Dummy functions to be overwritten by any datastore plugin included
732 load_node : function (obj
, s_call
, e_call
) { this.__callback({ "obj" : obj
}); },
733 _is_loaded : function (obj
) { return true; },
735 // Basic operations: create
736 create_node : function (obj
, position
, js
, callback
, is_loaded
) {
737 obj
= this._get_node(obj
);
738 position
= typeof position
=== "undefined" ? "last" : position
;
740 s
= this._get_settings().core
,
743 if(obj
!== -1 && !obj
.length
) { return false; }
744 if(!is_loaded
&& !this._is_loaded(obj
)) { this.load_node(obj
, function () { this.create_node(obj
, position
, js
, callback
, true); }); return false; }
748 if(typeof js
=== "string") { js
= { "data" : js
}; }
750 if(js
.attr
) { d
.attr(js
.attr
); }
751 if(js
.metadata
) { d
.data(js
.metadata
); }
752 if(js
.state
) { d
.addClass("jstree-" + js
.state
); }
753 if(!js
.data
) { js
.data
= this._get_string("new_node"); }
754 if(!$.isArray(js
.data
)) { tmp
= js
.data
; js
.data
= []; js
.data
.push(tmp
); }
755 $.each(js
.data
, function (i
, m
) {
757 if($.isFunction(m
)) { m
= m
.call(this, js
); }
758 if(typeof m
== "string") { tmp
.attr('href','#')[ s
.html_titles
? "html" : "text" ](m
); }
760 if(!m
.attr
) { m
.attr
= {}; }
761 if(!m
.attr
.href
) { m
.attr
.href
= '#'; }
762 tmp
.attr(m
.attr
)[ s
.html_titles
? "html" : "text" ](m
.title
);
763 if(m
.language
) { tmp
.addClass(m
.language
); }
765 tmp
.prepend("<ins class='jstree-icon'> </ins>");
766 if(!m
.icon
&& js
.icon
) { m
.icon
= js
.icon
; }
768 if(m
.icon
.indexOf("/") === -1) { tmp
.children("ins").addClass(m
.icon
); }
769 else { tmp
.children("ins").css("background","url('" + m
.icon
+ "') center center no-repeat"); }
773 d
.prepend("<ins class='jstree-icon'> </ins>");
775 obj
= this.get_container();
776 if(position
=== "before") { position
= "first"; }
777 if(position
=== "after") { position
= "last"; }
780 case "before": obj
.before(d
); tmp
= this._get_parent(obj
); break;
781 case "after" : obj
.after(d
); tmp
= this._get_parent(obj
); break;
784 if(!obj
.children("ul").length
) { obj
.append("<ul />"); }
785 obj
.children("ul").prepend(d
);
789 if(!obj
.children("ul").length
) { obj
.append("<ul />"); }
790 obj
.children("ul").append(d
);
794 if(!obj
.children("ul").length
) { obj
.append("<ul />"); }
795 if(!position
) { position
= 0; }
796 tmp
= obj
.children("ul").children("li").eq(position
);
797 if(tmp
.length
) { tmp
.before(d
); }
798 else { obj
.children("ul").append(d
); }
802 if(tmp
=== -1 || tmp
.get(0) === this.get_container().get(0)) { tmp
= -1; }
803 this.clean_node(tmp
);
804 this.__callback({ "obj" : d
, "parent" : tmp
});
805 if(callback
) { callback
.call(this, d
); }
808 // Basic operations: rename (deal with text)
809 get_text : function (obj
) {
810 obj
= this._get_node(obj
);
811 if(!obj
.length
) { return false; }
812 var s
= this._get_settings().core
.html_titles
;
813 obj
= obj
.children("a:eq(0)");
816 obj
.children("INS").remove();
820 obj
= obj
.contents().filter(function() { return this.nodeType
== 3; })[0];
821 return obj
.nodeValue
;
824 set_text : function (obj
, val
) {
825 obj
= this._get_node(obj
);
826 if(!obj
.length
) { return false; }
827 obj
= obj
.children("a:eq(0)");
828 if(this._get_settings().core
.html_titles
) {
829 var tmp
= obj
.children("INS").clone();
830 obj
.html(val
).prepend(tmp
);
831 this.__callback({ "obj" : obj
, "name" : val
});
835 obj
= obj
.contents().filter(function() { return this.nodeType
== 3; })[0];
836 this.__callback({ "obj" : obj
, "name" : val
});
837 return (obj
.nodeValue
= val
);
840 rename_node : function (obj
, val
) {
841 obj
= this._get_node(obj
);
843 if(obj
&& obj
.length
&& this.set_text
.apply(this, Array
.prototype.slice
.call(arguments
))) { this.__callback({ "obj" : obj
, "name" : val
}); }
845 // Basic operations: deleting nodes
846 delete_node : function (obj
) {
847 obj
= this._get_node(obj
);
848 if(!obj
.length
) { return false; }
850 var p
= this._get_parent(obj
), prev
= $([]), t
= this;
851 obj
.each(function () {
852 prev
= prev
.add(t
._get_prev(this));
855 if(p
!== -1 && p
.find("> ul > li").length
=== 0) {
856 p
.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");
859 this.__callback({ "obj" : obj
, "prev" : prev
, "parent" : p
});
862 prepare_move : function (o
, r
, pos
, cb
, is_cb
) {
865 p
.ot
= $.jstree
._reference(o
) || this;
866 p
.o
= p
.ot
._get_node(o
);
867 p
.r
= r
=== - 1 ? -1 : this._get_node(r
);
868 p
.p
= (typeof pos
=== "undefined" || pos
=== false) ? "last" : pos
; // TODO: move to a setting
869 if(!is_cb
&& prepared_move
.o
&& prepared_move
.o
[0] === p
.o
[0] && prepared_move
.r
[0] === p
.r
[0] && prepared_move
.p
=== p
.p
) {
870 this.__callback(prepared_move
);
871 if(cb
) { cb
.call(this, prepared_move
); }
874 p
.ot
= $.jstree
._reference(p
.o
) || this;
875 p
.rt
= $.jstree
._reference(p
.r
) || this; // r === -1 ? p.ot : $.jstree._reference(p.r) || this
876 if(p
.r
=== -1 || !p
.r
) {
886 p
.cp
= p
.rt
.get_container().find(" > ul > li").length
;
894 if(!/^(before|after)$/.test(p
.p
) && !this._is_loaded(p
.r
)) {
895 return this.load_node(p
.r
, function () { this.prepare_move(o
, r
, pos
, cb
, true); });
900 p
.cr
= p
.rt
._get_parent(p
.r
);
903 p
.cp
= p
.r
.index() + 1;
904 p
.cr
= p
.rt
._get_parent(p
.r
);
912 p
.cp
= p
.r
.find(" > ul > li").length
;
921 p
.np
= p
.cr
== -1 ? p
.rt
.get_container() : p
.cr
;
922 p
.op
= p
.ot
._get_parent(p
.o
);
924 if(p
.op
=== -1) { p
.op
= p
.ot
? p
.ot
.get_container() : this.get_container(); }
925 if(!/^(before|after)$/.test(p
.p
) && p
.op
&& p
.np
&& p
.op
[0] === p
.np
[0] && p
.o
.index() < p
.cp
) { p
.cp
++; }
926 //if(p.p === "before" && p.op && p.np && p.op[0] === p.np[0] && p.o.index() < p.cp) { p.cp--; }
927 p
.or
= p
.np
.find(" > ul > li:nth-child(" + (p
.cp
+ 1) + ")");
929 this.__callback(prepared_move
);
930 if(cb
) { cb
.call(this, prepared_move
); }
932 check_move : function () {
933 var obj
= prepared_move
, ret
= true, r
= obj
.r
=== -1 ? this.get_container() : obj
.r
;
934 if(!obj
|| !obj
.o
|| obj
.or
[0] === obj
.o
[0]) { return false; }
935 if(obj
.op
&& obj
.np
&& obj
.op
[0] === obj
.np
[0] && obj
.cp
- 1 === obj
.o
.index()) { return false; }
936 obj
.o
.each(function () {
937 if(r
.parentsUntil(".jstree", "li").andSelf().index(this) !== -1) { ret
= false; return false; }
941 move_node : function (obj
, ref
, position
, is_copy
, is_prepared
, skip_check
) {
943 return this.prepare_move(obj
, ref
, position
, function (p
) {
944 this.move_node(p
, false, false, is_copy
, true, skip_check
);
948 prepared_move
.cy
= true;
950 if(!skip_check
&& !this.check_move()) { return false; }
955 o
= obj
.o
.clone(true);
956 o
.find("*[id]").andSelf().each(function () {
957 if(this.id
) { this.id
= "copy_" + this.id
; }
962 if(obj
.or
.length
) { obj
.or
.before(o
); }
964 if(!obj
.np
.children("ul").length
) { $("<ul />").appendTo(obj
.np
); }
965 obj
.np
.children("ul:eq(0)").append(o
);
969 obj
.ot
.clean_node(obj
.op
);
970 obj
.rt
.clean_node(obj
.np
);
971 if(!obj
.op
.find("> ul > li").length
) {
972 obj
.op
.removeClass("jstree-open jstree-closed").addClass("jstree-leaf").children("ul").remove();
977 prepared_move
.cy
= true;
978 prepared_move
.oc
= o
;
980 this.__callback(prepared_move
);
981 return prepared_move
;
983 _get_move : function () { return prepared_move
; }
991 * This plugins handles selecting/deselecting/hovering/dehovering nodes
994 var scrollbar_width
, e1
, e2
;
996 if (/msie/.test(navigator
.userAgent
.toLowerCase())) {
997 e1
= $('<textarea cols="10" rows="2"></textarea>').css({ position
: 'absolute', top
: -1000, left
: 0 }).appendTo('body');
998 e2
= $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>').css({ position
: 'absolute', top
: -1000, left
: 0 }).appendTo('body');
999 scrollbar_width
= e1
.width() - e2
.width();
1000 e1
.add(e2
).remove();
1003 e1
= $('<div />').css({ width
: 100, height
: 100, overflow
: 'auto', position
: 'absolute', top
: -1000, left
: 0 })
1004 .prependTo('body').append('<div />').find('div').css({ width
: '100%', height
: 200 });
1005 scrollbar_width
= 100 - e1
.width();
1006 e1
.parent().remove();
1009 $.jstree
.plugin("ui", {
1010 __init : function () {
1011 this.data
.ui
.selected
= $();
1012 this.data
.ui
.last_selected
= false;
1013 this.data
.ui
.hovered
= null;
1014 this.data
.ui
.to_select
= this.get_settings().ui
.initially_select
;
1016 this.get_container()
1017 .delegate("a", "click.jstree", $.proxy(function (event
) {
1018 event
.preventDefault();
1019 event
.currentTarget
.blur();
1020 if(!$(event
.currentTarget
).hasClass("jstree-loading")) {
1021 this.select_node(event
.currentTarget
, true, event
);
1024 .delegate("a", "mouseenter.jstree", $.proxy(function (event
) {
1025 if(!$(event
.currentTarget
).hasClass("jstree-loading")) {
1026 this.hover_node(event
.target
);
1029 .delegate("a", "mouseleave.jstree", $.proxy(function (event
) {
1030 if(!$(event
.currentTarget
).hasClass("jstree-loading")) {
1031 this.dehover_node(event
.target
);
1034 .bind("reopen.jstree", $.proxy(function () {
1037 .bind("get_rollback.jstree", $.proxy(function () {
1038 this.dehover_node();
1039 this.save_selected();
1041 .bind("set_rollback.jstree", $.proxy(function () {
1044 .bind("close_node.jstree", $.proxy(function (event
, data
) {
1045 var s
= this._get_settings().ui
,
1046 obj
= this._get_node(data
.rslt
.obj
),
1047 clk
= (obj
&& obj
.length
) ? obj
.children("ul").find("a.jstree-clicked") : $(),
1049 if(s
.selected_parent_close
=== false || !clk
.length
) { return; }
1050 clk
.each(function () {
1051 _this
.deselect_node(this);
1052 if(s
.selected_parent_close
=== "select_parent") { _this
.select_node(obj
); }
1055 .bind("delete_node.jstree", $.proxy(function (event
, data
) {
1056 var s
= this._get_settings().ui
.select_prev_on_delete
,
1057 obj
= this._get_node(data
.rslt
.obj
),
1058 clk
= (obj
&& obj
.length
) ? obj
.find("a.jstree-clicked") : [],
1060 clk
.each(function () { _this
.deselect_node(this); });
1061 if(s
&& clk
.length
) {
1062 data
.rslt
.prev
.each(function () {
1063 if(this.parentNode
) { _this
.select_node(this); return false; /* if return false is removed all prev nodes will be selected */}
1067 .bind("move_node.jstree", $.proxy(function (event
, data
) {
1069 data
.rslt
.oc
.find("a.jstree-clicked").removeClass("jstree-clicked");
1074 select_limit
: -1, // 0, 1, 2 ... or -1 for unlimited
1075 select_multiple_modifier
: "ctrl", // on, or ctrl, shift, alt
1076 select_range_modifier
: "shift",
1077 selected_parent_close
: "select_parent", // false, "deselect", "select_parent"
1078 selected_parent_open
: true,
1079 select_prev_on_delete
: true,
1080 disable_selecting_children
: false,
1081 initially_select
: []
1084 _get_node : function (obj
, allow_multiple
) {
1085 if(typeof obj
=== "undefined" || obj
=== null) { return allow_multiple
? this.data
.ui
.selected
: this.data
.ui
.last_selected
; }
1086 var $obj
= $(obj
, this.get_container());
1087 if($obj
.is(".jstree") || obj
== -1) { return -1; }
1088 $obj
= $obj
.closest("li", this.get_container());
1089 return $obj
.length
? $obj
: false;
1091 _ui_notify : function (n
, data
) {
1093 this.select_node(n
, false);
1096 save_selected : function () {
1098 this.data
.ui
.to_select
= [];
1099 this.data
.ui
.selected
.each(function () { if(this.id
) { _this
.data
.ui
.to_select
.push("#" + this.id
.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:")); } });
1100 this.__callback(this.data
.ui
.to_select
);
1102 reselect : function () {
1104 s
= this.data
.ui
.to_select
;
1105 s
= $.map($.makeArray(s
), function (n
) { return "#" + n
.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); });
1106 // this.deselect_all(); WHY deselect, breaks plugin state notifier?
1107 $.each(s
, function (i
, val
) { if(val
&& val
!== "#") { _this
.select_node(val
); } });
1108 this.data
.ui
.selected
= this.data
.ui
.selected
.filter(function () { return this.parentNode
; });
1111 refresh : function (obj
) {
1112 this.save_selected();
1113 return this.__call_old();
1115 hover_node : function (obj
) {
1116 obj
= this._get_node(obj
);
1117 if(!obj
.length
) { return false; }
1118 //if(this.data.ui.hovered && obj.get(0) === this.data.ui.hovered.get(0)) { return; }
1119 if(!obj
.hasClass("jstree-hovered")) { this.dehover_node(); }
1120 this.data
.ui
.hovered
= obj
.children("a").addClass("jstree-hovered").parent();
1121 this._fix_scroll(obj
);
1122 this.__callback({ "obj" : obj
});
1124 dehover_node : function () {
1125 var obj
= this.data
.ui
.hovered
, p
;
1126 if(!obj
|| !obj
.length
) { return false; }
1127 p
= obj
.children("a").removeClass("jstree-hovered").parent();
1128 if(this.data
.ui
.hovered
[0] === p
[0]) { this.data
.ui
.hovered
= null; }
1129 this.__callback({ "obj" : obj
});
1131 select_node : function (obj
, check
, e
) {
1132 obj
= this._get_node(obj
);
1133 if(obj
== -1 || !obj
|| !obj
.length
) { return false; }
1134 var s
= this._get_settings().ui
,
1135 is_multiple
= (s
.select_multiple_modifier
== "on" || (s
.select_multiple_modifier
!== false && e
&& e
[s
.select_multiple_modifier
+ "Key"])),
1136 is_range
= (s
.select_range_modifier
!== false && e
&& e
[s
.select_range_modifier
+ "Key"] && this.data
.ui
.last_selected
&& this.data
.ui
.last_selected
[0] !== obj
[0] && this.data
.ui
.last_selected
.parent()[0] === obj
.parent()[0]),
1137 is_selected
= this.is_selected(obj
),
1141 if(s
.disable_selecting_children
&& is_multiple
&&
1143 (obj
.parentsUntil(".jstree","li").children("a.jstree-clicked").length
) ||
1144 (obj
.children("ul").find("a.jstree-clicked:eq(0)").length
)
1152 this.data
.ui
.last_selected
.addClass("jstree-last-selected");
1153 obj
= obj
[ obj
.index() < this.data
.ui
.last_selected
.index() ? "nextUntil" : "prevUntil" ](".jstree-last-selected").andSelf();
1154 if(s
.select_limit
== -1 || obj
.length
< s
.select_limit
) {
1155 this.data
.ui
.last_selected
.removeClass("jstree-last-selected");
1156 this.data
.ui
.selected
.each(function () {
1157 if(this !== t
.data
.ui
.last_selected
[0]) { t
.deselect_node(this); }
1159 is_selected
= false;
1166 case (is_selected
&& !is_multiple
):
1167 this.deselect_all();
1168 is_selected
= false;
1171 case (!is_selected
&& !is_multiple
):
1172 if(s
.select_limit
== -1 || s
.select_limit
> 0) {
1173 this.deselect_all();
1177 case (is_selected
&& is_multiple
):
1178 this.deselect_node(obj
);
1180 case (!is_selected
&& is_multiple
):
1181 if(s
.select_limit
== -1 || this.data
.ui
.selected
.length
+ 1 <= s
.select_limit
) {
1187 if(proceed
&& !is_selected
) {
1188 if(!is_range
) { this.data
.ui
.last_selected
= obj
; }
1189 obj
.children("a").addClass("jstree-clicked");
1190 if(s
.selected_parent_open
) {
1191 obj
.parents(".jstree-closed").each(function () { t
.open_node(this, false, true); });
1193 this.data
.ui
.selected
= this.data
.ui
.selected
.add(obj
);
1194 this._fix_scroll(obj
.eq(0));
1195 this.__callback({ "obj" : obj
, "e" : e
});
1198 _fix_scroll : function (obj
) {
1199 var c
= this.get_container()[0], t
;
1200 if(c
.scrollHeight
> c
.offsetHeight
) {
1201 obj
= this._get_node(obj
);
1202 if(!obj
|| obj
=== -1 || !obj
.length
|| !obj
.is(":visible")) { return; }
1203 t
= obj
.offset().top
- this.get_container().offset().top
;
1205 c
.scrollTop
= c
.scrollTop
+ t
- 1;
1207 if(t
+ this.data
.core
.li_height
+ (c
.scrollWidth
> c
.offsetWidth
? scrollbar_width
: 0) > c
.offsetHeight
) {
1208 c
.scrollTop
= c
.scrollTop
+ (t
- c
.offsetHeight
+ this.data
.core
.li_height
+ 1 + (c
.scrollWidth
> c
.offsetWidth
? scrollbar_width
: 0));
1212 deselect_node : function (obj
) {
1213 obj
= this._get_node(obj
);
1214 if(!obj
.length
) { return false; }
1215 if(this.is_selected(obj
)) {
1216 obj
.children("a").removeClass("jstree-clicked");
1217 this.data
.ui
.selected
= this.data
.ui
.selected
.not(obj
);
1218 if(this.data
.ui
.last_selected
.get(0) === obj
.get(0)) { this.data
.ui
.last_selected
= this.data
.ui
.selected
.eq(0); }
1219 this.__callback({ "obj" : obj
});
1222 toggle_select : function (obj
) {
1223 obj
= this._get_node(obj
);
1224 if(!obj
.length
) { return false; }
1225 if(this.is_selected(obj
)) { this.deselect_node(obj
); }
1226 else { this.select_node(obj
); }
1228 is_selected : function (obj
) { return this.data
.ui
.selected
.index(this._get_node(obj
)) >= 0; },
1229 get_selected : function (context
) {
1230 return context
? $(context
).find("a.jstree-clicked").parent() : this.data
.ui
.selected
;
1232 deselect_all : function (context
) {
1233 var ret
= context
? $(context
).find("a.jstree-clicked").parent() : this.get_container().find("a.jstree-clicked").parent();
1234 ret
.children("a.jstree-clicked").removeClass("jstree-clicked");
1235 this.data
.ui
.selected
= $([]);
1236 this.data
.ui
.last_selected
= false;
1237 this.__callback({ "obj" : ret
});
1241 // include the selection plugin by default
1242 $.jstree
.defaults
.plugins
.push("ui");
1247 * jsTree CRRM plugin
1248 * Handles creating/renaming/removing/moving nodes by user interaction.
1251 $.jstree
.plugin("crrm", {
1252 __init : function () {
1253 this.get_container()
1254 .bind("move_node.jstree", $.proxy(function (e
, data
) {
1255 if(this._get_settings().crrm
.move.open_onmove
) {
1257 data
.rslt
.np
.parentsUntil(".jstree").andSelf().filter(".jstree-closed").each(function () {
1258 t
.open_node(this, false, true);
1264 input_width_limit
: 200,
1266 always_copy
: false, // false, true or "multitree"
1268 default_position
: "last",
1269 check_move : function (m
) { return true; }
1273 _show_input : function (obj
, callback
) {
1274 obj
= this._get_node(obj
);
1275 var rtl
= this._get_settings().core
.rtl
,
1276 w
= this._get_settings().crrm
.input_width_limit
,
1277 w1
= obj
.children("ins").width(),
1278 w2
= obj
.find("> a:visible > ins").width() * obj
.find("> a:visible > ins").length
,
1279 t
= this.get_text(obj
),
1280 h1
= $("<div />", { css
: { "position" : "absolute", "top" : "-200px", "left" : (rtl
? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"),
1281 h2
= obj
.css("position","relative").append(
1284 "class" : "jstree-rename-input",
1285 // "size" : t.length,
1288 "border" : "1px solid silver",
1289 "position" : "absolute",
1290 "left" : (rtl
? "auto" : (w1
+ w2
+ 4) + "px"),
1291 "right" : (rtl
? (w1
+ w2
+ 4) + "px" : "auto"),
1293 "height" : (this.data
.core
.li_height
- 2) + "px",
1294 "lineHeight" : (this.data
.core
.li_height
- 2) + "px",
1295 "width" : "150px" // will be set a bit further down
1297 "blur" : $.proxy(function () {
1298 var i
= obj
.children(".jstree-rename-input"),
1300 if(v
=== "") { v
= t
; }
1302 i
.remove(); // rollback purposes
1303 this.set_text(obj
,t
); // rollback purposes
1304 this.rename_node(obj
, v
);
1305 callback
.call(this, obj
, v
, t
);
1306 obj
.css("position","");
1308 "keyup" : function (event
) {
1309 var key
= event
.keyCode
|| event
.which
;
1310 if(key
== 27) { this.value
= t
; this.blur(); return; }
1311 else if(key
== 13) { this.blur(); return; }
1313 h2
.width(Math
.min(h1
.text("pW" + this.value
).width(),w
));
1316 "keypress" : function(event
) {
1317 var key
= event
.keyCode
|| event
.which
;
1318 if(key
== 13) { return false; }
1321 ).children(".jstree-rename-input");
1322 this.set_text(obj
, "");
1324 fontFamily
: h2
.css('fontFamily') || '',
1325 fontSize
: h2
.css('fontSize') || '',
1326 fontWeight
: h2
.css('fontWeight') || '',
1327 fontStyle
: h2
.css('fontStyle') || '',
1328 fontStretch
: h2
.css('fontStretch') || '',
1329 fontVariant
: h2
.css('fontVariant') || '',
1330 letterSpacing
: h2
.css('letterSpacing') || '',
1331 wordSpacing
: h2
.css('wordSpacing') || ''
1333 h2
.width(Math
.min(h1
.text("pW" + h2
[0].value
).width(),w
))[0].select();
1335 rename : function (obj
) {
1336 obj
= this._get_node(obj
);
1338 var f
= this.__callback
;
1339 this._show_input(obj
, function (obj
, new_name
, old_name
) {
1340 f
.call(this, { "obj" : obj
, "new_name" : new_name
, "old_name" : old_name
});
1343 create : function (obj
, position
, js
, callback
, skip_rename
) {
1344 var t
, _this
= this;
1345 obj
= this._get_node(obj
);
1346 if(!obj
) { obj
= -1; }
1348 t
= this.create_node(obj
, position
, js
, function (t
) {
1349 var p
= this._get_parent(t
),
1351 if(callback
) { callback
.call(this, t
); }
1352 if(p
.length
&& p
.hasClass("jstree-closed")) { this.open_node(p
, false, true); }
1354 this._show_input(t
, function (obj
, new_name
, old_name
) {
1355 _this
.__callback({ "obj" : obj
, "name" : new_name
, "parent" : p
, "position" : pos
});
1358 else { _this
.__callback({ "obj" : t
, "name" : this.get_text(t
), "parent" : p
, "position" : pos
}); }
1362 remove : function (obj
) {
1363 obj
= this._get_node(obj
, true);
1364 var p
= this._get_parent(obj
), prev
= this._get_prev(obj
);
1366 obj
= this.delete_node(obj
);
1367 if(obj
!== false) { this.__callback({ "obj" : obj
, "prev" : prev
, "parent" : p
}); }
1369 check_move : function () {
1370 if(!this.__call_old()) { return false; }
1371 var s
= this._get_settings().crrm
.move;
1372 if(!s
.check_move
.call(this, this._get_move())) { return false; }
1375 move_node : function (obj
, ref
, position
, is_copy
, is_prepared
, skip_check
) {
1376 var s
= this._get_settings().crrm
.move;
1378 if(typeof position
=== "undefined") { position
= s
.default_position
; }
1379 if(position
=== "inside" && !s
.default_position
.match(/^(before|after)$/)) { position
= s
.default_position
; }
1380 return this.__call_old(true, obj
, ref
, position
, is_copy
, false, skip_check
);
1382 // if the move is already prepared
1383 if(s
.always_copy
=== true || (s
.always_copy
=== "multitree" && obj
.rt
.get_index() !== obj
.ot
.get_index() )) {
1386 this.__call_old(true, obj
, ref
, position
, is_copy
, true, skip_check
);
1389 cut : function (obj
) {
1390 obj
= this._get_node(obj
, true);
1391 if(!obj
|| !obj
.length
) { return false; }
1392 this.data
.crrm
.cp_nodes
= false;
1393 this.data
.crrm
.ct_nodes
= obj
;
1394 this.__callback({ "obj" : obj
});
1396 copy : function (obj
) {
1397 obj
= this._get_node(obj
, true);
1398 if(!obj
|| !obj
.length
) { return false; }
1399 this.data
.crrm
.ct_nodes
= false;
1400 this.data
.crrm
.cp_nodes
= obj
;
1401 this.__callback({ "obj" : obj
});
1403 paste : function (obj
) {
1404 obj
= this._get_node(obj
);
1405 if(!obj
|| !obj
.length
) { return false; }
1406 var nodes
= this.data
.crrm
.ct_nodes
? this.data
.crrm
.ct_nodes
: this.data
.crrm
.cp_nodes
;
1407 if(!this.data
.crrm
.ct_nodes
&& !this.data
.crrm
.cp_nodes
) { return false; }
1408 if(this.data
.crrm
.ct_nodes
) { this.move_node(this.data
.crrm
.ct_nodes
, obj
); this.data
.crrm
.ct_nodes
= false; }
1409 if(this.data
.crrm
.cp_nodes
) { this.move_node(this.data
.crrm
.cp_nodes
, obj
, false, true); }
1410 this.__callback({ "obj" : obj
, "nodes" : nodes
});
1414 // include the crr plugin by default
1415 // $.jstree.defaults.plugins.push("crrm");
1420 * jsTree themes plugin
1421 * Handles loading and setting themes, as well as detecting path to themes, etc.
1424 var themes_loaded
= [];
1425 // this variable stores the path to the themes folder - if left as false - it will be autodetected
1426 $.jstree
._themes
= false;
1427 $.jstree
.plugin("themes", {
1428 __init : function () {
1429 this.get_container()
1430 .bind("init.jstree", $.proxy(function () {
1431 var s
= this._get_settings().themes
;
1432 this.data
.themes
.dots
= s
.dots
;
1433 this.data
.themes
.icons
= s
.icons
;
1434 this.set_theme(s
.theme
, s
.url
);
1436 .bind("loaded.jstree", $.proxy(function () {
1437 // bound here too, as simple HTML tree's won't honor dots & icons otherwise
1438 if(!this.data
.themes
.dots
) { this.hide_dots(); }
1439 else { this.show_dots(); }
1440 if(!this.data
.themes
.icons
) { this.hide_icons(); }
1441 else { this.show_icons(); }
1451 set_theme : function (theme_name
, theme_url
) {
1452 if(!theme_name
) { return false; }
1453 if(!theme_url
) { theme_url
= $.jstree
._themes
+ theme_name
+ '/style.css'; }
1454 if($.inArray(theme_url
, themes_loaded
) == -1) {
1455 $.vakata
.css
.add_sheet({ "url" : theme_url
});
1456 themes_loaded
.push(theme_url
);
1458 if(this.data
.themes
.theme
!= theme_name
) {
1459 this.get_container().removeClass('jstree-' + this.data
.themes
.theme
);
1460 this.data
.themes
.theme
= theme_name
;
1462 this.get_container().addClass('jstree-' + theme_name
);
1463 if(!this.data
.themes
.dots
) { this.hide_dots(); }
1464 else { this.show_dots(); }
1465 if(!this.data
.themes
.icons
) { this.hide_icons(); }
1466 else { this.show_icons(); }
1469 get_theme : function () { return this.data
.themes
.theme
; },
1471 show_dots : function () { this.data
.themes
.dots
= true; this.get_container().children("ul").removeClass("jstree-no-dots"); },
1472 hide_dots : function () { this.data
.themes
.dots
= false; this.get_container().children("ul").addClass("jstree-no-dots"); },
1473 toggle_dots : function () { if(this.data
.themes
.dots
) { this.hide_dots(); } else { this.show_dots(); } },
1475 show_icons : function () { this.data
.themes
.icons
= true; this.get_container().children("ul").removeClass("jstree-no-icons"); },
1476 hide_icons : function () { this.data
.themes
.icons
= false; this.get_container().children("ul").addClass("jstree-no-icons"); },
1477 toggle_icons: function () { if(this.data
.themes
.icons
) { this.hide_icons(); } else { this.show_icons(); } }
1480 // autodetect themes path
1482 if($.jstree
._themes
=== false) {
1483 $("script").each(function () {
1484 if(this.src
.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)) {
1485 $.jstree
._themes
= this.src
.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/, "") + 'themes/';
1490 if($.jstree
._themes
=== false) { $.jstree
._themes
= "themes/"; }
1492 // include the themes plugin by default
1493 $.jstree
.defaults
.plugins
.push("themes");
1498 * jsTree hotkeys plugin
1499 * Enables keyboard navigation for all tree instances
1500 * Depends on the jstree ui & jquery hotkeys plugins
1504 function exec(i
, event
) {
1505 var f
= $.jstree
._focused(), tmp
;
1506 if(f
&& f
.data
&& f
.data
.hotkeys
&& f
.data
.hotkeys
.enabled
) {
1507 tmp
= f
._get_settings().hotkeys
[i
];
1508 if(tmp
) { return tmp
.call(f
, event
); }
1511 $.jstree
.plugin("hotkeys", {
1512 __init : function () {
1513 if(typeof $.hotkeys
=== "undefined") { throw "jsTree hotkeys: jQuery hotkeys plugin not included."; }
1514 if(!this.data
.ui
) { throw "jsTree hotkeys: jsTree UI plugin not included."; }
1515 $.each(this._get_settings().hotkeys
, function (i
, v
) {
1516 if(v
!== false && $.inArray(i
, bound
) == -1) {
1517 $(document
).bind("keydown", i
, function (event
) { return exec(i
, event
); });
1521 this.get_container()
1522 .bind("lock.jstree", $.proxy(function () {
1523 if(this.data
.hotkeys
.enabled
) { this.data
.hotkeys
.enabled
= false; this.data
.hotkeys
.revert
= true; }
1525 .bind("unlock.jstree", $.proxy(function () {
1526 if(this.data
.hotkeys
.revert
) { this.data
.hotkeys
.enabled
= true; }
1528 this.enable_hotkeys();
1531 "up" : function () {
1532 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
|| -1;
1533 this.hover_node(this._get_prev(o
));
1536 "ctrl+up" : function () {
1537 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
|| -1;
1538 this.hover_node(this._get_prev(o
));
1541 "shift+up" : function () {
1542 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
|| -1;
1543 this.hover_node(this._get_prev(o
));
1546 "down" : function () {
1547 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
|| -1;
1548 this.hover_node(this._get_next(o
));
1551 "ctrl+down" : function () {
1552 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
|| -1;
1553 this.hover_node(this._get_next(o
));
1556 "shift+down" : function () {
1557 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
|| -1;
1558 this.hover_node(this._get_next(o
));
1561 "left" : function () {
1562 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
;
1564 if(o
.hasClass("jstree-open")) { this.close_node(o
); }
1565 else { this.hover_node(this._get_prev(o
)); }
1569 "ctrl+left" : function () {
1570 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
;
1572 if(o
.hasClass("jstree-open")) { this.close_node(o
); }
1573 else { this.hover_node(this._get_prev(o
)); }
1577 "shift+left" : function () {
1578 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
;
1580 if(o
.hasClass("jstree-open")) { this.close_node(o
); }
1581 else { this.hover_node(this._get_prev(o
)); }
1585 "right" : function () {
1586 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
;
1588 if(o
.hasClass("jstree-closed")) { this.open_node(o
); }
1589 else { this.hover_node(this._get_next(o
)); }
1593 "ctrl+right" : function () {
1594 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
;
1596 if(o
.hasClass("jstree-closed")) { this.open_node(o
); }
1597 else { this.hover_node(this._get_next(o
)); }
1601 "shift+right" : function () {
1602 var o
= this.data
.ui
.hovered
|| this.data
.ui
.last_selected
;
1604 if(o
.hasClass("jstree-closed")) { this.open_node(o
); }
1605 else { this.hover_node(this._get_next(o
)); }
1609 "space" : function () {
1610 if(this.data
.ui
.hovered
) { this.data
.ui
.hovered
.children("a:eq(0)").click(); }
1613 "ctrl+space" : function (event
) {
1614 event
.type
= "click";
1615 if(this.data
.ui
.hovered
) { this.data
.ui
.hovered
.children("a:eq(0)").trigger(event
); }
1618 "shift+space" : function (event
) {
1619 event
.type
= "click";
1620 if(this.data
.ui
.hovered
) { this.data
.ui
.hovered
.children("a:eq(0)").trigger(event
); }
1623 "f2" : function () { this.rename(this.data
.ui
.hovered
|| this.data
.ui
.last_selected
); },
1624 "del" : function () { this.remove(this.data
.ui
.hovered
|| this._get_node(null)); }
1627 enable_hotkeys : function () {
1628 this.data
.hotkeys
.enabled
= true;
1630 disable_hotkeys : function () {
1631 this.data
.hotkeys
.enabled
= false;
1639 * jsTree JSON plugin
1640 * The JSON data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions.
1643 $.jstree
.plugin("json_data", {
1644 __init : function() {
1645 var s
= this._get_settings().json_data
;
1646 if(s
.progressive_unload
) {
1647 this.get_container().bind("after_close.jstree", function (e
, data
) {
1648 data
.rslt
.obj
.children("ul").remove();
1653 // `data` can be a function:
1654 // * accepts two arguments - node being loaded and a callback to pass the result to
1655 // * will be executed in the current tree's scope & ajax won't be supported
1658 correct_state
: true,
1659 progressive_render
: false,
1660 progressive_unload
: false
1663 load_node : function (obj
, s_call
, e_call
) { var _this
= this; this.load_node_json(obj
, function () { _this
.__callback({ "obj" : _this
._get_node(obj
) }); s_call
.call(this); }, e_call
); },
1664 _is_loaded : function (obj
) {
1665 var s
= this._get_settings().json_data
;
1666 obj
= this._get_node(obj
);
1667 return obj
== -1 || !obj
|| (!s
.ajax
&& !s
.progressive_render
&& !$.isFunction(s
.data
)) || obj
.is(".jstree-open, .jstree-leaf") || obj
.children("ul").children("li").length
> 0;
1669 refresh : function (obj
) {
1670 obj
= this._get_node(obj
);
1671 var s
= this._get_settings().json_data
;
1672 if(obj
&& obj
!== -1 && s
.progressive_unload
&& ($.isFunction(s
.data
) || !!s
.ajax
)) {
1673 obj
.removeData("jstree_children");
1675 return this.__call_old();
1677 load_node_json : function (obj
, s_call
, e_call
) {
1678 var s
= this.get_settings().json_data
, d
,
1679 error_func = function () {},
1680 success_func = function () {};
1681 obj
= this._get_node(obj
);
1683 if(obj
&& obj
!== -1 && (s
.progressive_render
|| s
.progressive_unload
) && !obj
.is(".jstree-open, .jstree-leaf") && obj
.children("ul").children("li").length
=== 0 && obj
.data("jstree_children")) {
1684 d
= this._parse_json(obj
.data("jstree_children"), obj
);
1687 if(!s
.progressive_unload
) { obj
.removeData("jstree_children"); }
1689 this.clean_node(obj
);
1690 if(s_call
) { s_call
.call(this); }
1694 if(obj
&& obj
!== -1) {
1695 if(obj
.data("jstree_is_loading")) { return; }
1696 else { obj
.data("jstree_is_loading",true); }
1699 case (!s
.data
&& !s
.ajax
): throw "Neither data nor ajax settings supplied.";
1700 // function option added here for easier model integration (also supporting async - see callback)
1701 case ($.isFunction(s
.data
)):
1702 s
.data
.call(this, obj
, $.proxy(function (d
) {
1703 d
= this._parse_json(d
, obj
);
1705 if(obj
=== -1 || !obj
) {
1706 if(s
.correct_state
) { this.get_container().children("ul").empty(); }
1709 obj
.children("a.jstree-loading").removeClass("jstree-loading");
1710 obj
.removeData("jstree_is_loading");
1711 if(s
.correct_state
) { this.correct_state(obj
); }
1713 if(e_call
) { e_call
.call(this); }
1716 if(obj
=== -1 || !obj
) { this.get_container().children("ul").empty().append(d
.children()); }
1717 else { obj
.append(d
).children("a.jstree-loading").removeClass("jstree-loading"); obj
.removeData("jstree_is_loading"); }
1718 this.clean_node(obj
);
1719 if(s_call
) { s_call
.call(this); }
1723 case (!!s
.data
&& !s
.ajax
) || (!!s
.data
&& !!s
.ajax
&& (!obj
|| obj
=== -1)):
1724 if(!obj
|| obj
== -1) {
1725 d
= this._parse_json(s
.data
, obj
);
1727 this.get_container().children("ul").empty().append(d
.children());
1731 if(s
.correct_state
) { this.get_container().children("ul").empty(); }
1734 if(s_call
) { s_call
.call(this); }
1736 case (!s
.data
&& !!s
.ajax
) || (!!s
.data
&& !!s
.ajax
&& obj
&& obj
!== -1):
1737 error_func = function (x
, t
, e
) {
1738 var ef
= this.get_settings().json_data
.ajax
.error
;
1739 if(ef
) { ef
.call(this, x
, t
, e
); }
1740 if(obj
!= -1 && obj
.length
) {
1741 obj
.children("a.jstree-loading").removeClass("jstree-loading");
1742 obj
.removeData("jstree_is_loading");
1743 if(t
=== "success" && s
.correct_state
) { this.correct_state(obj
); }
1746 if(t
=== "success" && s
.correct_state
) { this.get_container().children("ul").empty(); }
1748 if(e_call
) { e_call
.call(this); }
1750 success_func = function (d
, t
, x
) {
1751 var sf
= this.get_settings().json_data
.ajax
.success
;
1752 if(sf
) { d
= sf
.call(this,d
,t
,x
) || d
; }
1753 if(d
=== "" || (d
&& d
.toString
&& d
.toString().replace(/^[\s\n]+$/,"") === "") || (!$.isArray(d
) && !$.isPlainObject(d
))) {
1754 return error_func
.call(this, x
, t
, "");
1756 d
= this._parse_json(d
, obj
);
1758 if(obj
=== -1 || !obj
) { this.get_container().children("ul").empty().append(d
.children()); }
1759 else { obj
.append(d
).children("a.jstree-loading").removeClass("jstree-loading"); obj
.removeData("jstree_is_loading"); }
1760 this.clean_node(obj
);
1761 if(s_call
) { s_call
.call(this); }
1764 if(obj
=== -1 || !obj
) {
1765 if(s
.correct_state
) {
1766 this.get_container().children("ul").empty();
1767 if(s_call
) { s_call
.call(this); }
1771 obj
.children("a.jstree-loading").removeClass("jstree-loading");
1772 obj
.removeData("jstree_is_loading");
1773 if(s
.correct_state
) {
1774 this.correct_state(obj
);
1775 if(s_call
) { s_call
.call(this); }
1780 s
.ajax
.context
= this;
1781 s
.ajax
.error
= error_func
;
1782 s
.ajax
.success
= success_func
;
1783 if(!s
.ajax
.dataType
) { s
.ajax
.dataType
= "json"; }
1784 if($.isFunction(s
.ajax
.url
)) { s
.ajax
.url
= s
.ajax
.url
.call(this, obj
); }
1785 if($.isFunction(s
.ajax
.data
)) { s
.ajax
.data
= s
.ajax
.data
.call(this, obj
); }
1790 _parse_json : function (js
, obj
, is_callback
) {
1792 p
= this._get_settings(),
1794 t
= p
.core
.html_titles
,
1795 tmp
, i
, j
, ul1
, ul2
;
1797 if(!js
) { return d
; }
1798 if(s
.progressive_unload
&& obj
&& obj
!== -1) {
1799 obj
.data("jstree_children", d
);
1803 if(!js
.length
) { return false; }
1804 for(i
= 0, j
= js
.length
; i
< j
; i
++) {
1805 tmp
= this._parse_json(js
[i
], obj
, true);
1806 if(tmp
.length
) { d
= d
.add(tmp
); }
1810 if(typeof js
== "string") { js
= { data
: js
}; }
1811 if(!js
.data
&& js
.data
!== "") { return d
; }
1813 if(js
.attr
) { d
.attr(js
.attr
); }
1814 if(js
.metadata
) { d
.data(js
.metadata
); }
1815 if(js
.state
) { d
.addClass("jstree-" + js
.state
); }
1816 if(!$.isArray(js
.data
)) { tmp
= js
.data
; js
.data
= []; js
.data
.push(tmp
); }
1817 $.each(js
.data
, function (i
, m
) {
1819 if($.isFunction(m
)) { m
= m
.call(this, js
); }
1820 if(typeof m
== "string") { tmp
.attr('href','#')[ t
? "html" : "text" ](m
); }
1822 if(!m
.attr
) { m
.attr
= {}; }
1823 if(!m
.attr
.href
) { m
.attr
.href
= '#'; }
1824 tmp
.attr(m
.attr
)[ t
? "html" : "text" ](m
.title
);
1825 if(m
.language
) { tmp
.addClass(m
.language
); }
1827 tmp
.prepend("<ins class='jstree-icon'> </ins>");
1828 if(!m
.icon
&& js
.icon
) { m
.icon
= js
.icon
; }
1830 if(m
.icon
.indexOf("/") === -1) { tmp
.children("ins").addClass(m
.icon
); }
1831 else { tmp
.children("ins").css("background","url('" + m
.icon
+ "') center center no-repeat"); }
1835 d
.prepend("<ins class='jstree-icon'> </ins>");
1837 if(s
.progressive_render
&& js
.state
!== "open") {
1838 d
.addClass("jstree-closed").data("jstree_children", js
.children
);
1841 if(s
.progressive_unload
) { d
.data("jstree_children", js
.children
); }
1842 if($.isArray(js
.children
) && js
.children
.length
) {
1843 tmp
= this._parse_json(js
.children
, obj
, true);
1860 get_json : function (obj
, li_attr
, a_attr
, is_callback
) {
1862 s
= this._get_settings(),
1864 tmp1
, tmp2
, li
, a
, t
, lang
;
1865 obj
= this._get_node(obj
);
1866 if(!obj
|| obj
=== -1) { obj
= this.get_container().find("> ul > li"); }
1867 li_attr
= $.isArray(li_attr
) ? li_attr
: [ "id", "class" ];
1868 if(!is_callback
&& this.data
.types
) { li_attr
.push(s
.types
.type_attr
); }
1869 a_attr
= $.isArray(a_attr
) ? a_attr
: [ ];
1871 obj
.each(function () {
1873 tmp1
= { data
: [] };
1874 if(li_attr
.length
) { tmp1
.attr
= { }; }
1875 $.each(li_attr
, function (i
, v
) {
1877 if(tmp2
&& tmp2
.length
&& tmp2
.replace(/jstree[^ ]*/ig,'').length
) {
1878 tmp1
.attr
[v
] = (" " + tmp2
).replace(/ jstree
[^ ]*/ig
,'').replace(/\s
+$/ig," ").replace(/^ /,"").replace(/ $/,"");
1881 if(li
.hasClass("jstree-open")) { tmp1
.state
= "open"; }
1882 if(li
.hasClass("jstree-closed")) { tmp1
.state
= "closed"; }
1883 if(li
.data()) { tmp1
.metadata
= li
.data(); }
1884 a
= li
.children("a");
1885 a
.each(function () {
1889 $.inArray("languages", s
.plugins
) !== -1 ||
1890 t
.children("ins").get(0).style
.backgroundImage
.length
||
1891 (t
.children("ins").get(0).className
&& t
.children("ins").get(0).className
.replace(/jstree[^ ]*|$/ig,'').length
)
1894 if($.inArray("languages", s
.plugins
) !== -1 && $.isArray(s
.languages
) && s
.languages
.length
) {
1895 $.each(s
.languages
, function (l
, lv
) {
1896 if(t
.hasClass(lv
)) {
1902 tmp2
= { attr
: { }, title
: _this
.get_text(t
, lang
) };
1903 $.each(a_attr
, function (k
, z
) {
1904 tmp2
.attr
[z
] = (" " + (t
.attr(z
) || "")).replace(/ jstree
[^ ]*/ig
,'').replace(/\s
+$/ig," ").replace(/^ /,"").replace(/ $/,"");
1906 if($.inArray("languages", s
.plugins
) !== -1 && $.isArray(s
.languages
) && s
.languages
.length
) {
1907 $.each(s
.languages
, function (k
, z
) {
1908 if(t
.hasClass(z
)) { tmp2
.language
= z
; return true; }
1911 if(t
.children("ins").get(0).className
.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length
) {
1912 tmp2
.icon
= t
.children("ins").get(0).className
.replace(/jstree[^ ]*|$/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"");
1914 if(t
.children("ins").get(0).style
.backgroundImage
.length
) {
1915 tmp2
.icon
= t
.children("ins").get(0).style
.backgroundImage
.replace("url(","").replace(")","");
1919 tmp2
= _this
.get_text(t
);
1921 if(a
.length
> 1) { tmp1
.data
.push(tmp2
); }
1922 else { tmp1
.data
= tmp2
; }
1924 li
= li
.find("> ul > li");
1925 if(li
.length
) { tmp1
.children
= _this
.get_json(li
, li_attr
, a_attr
, true); }
1936 * jsTree languages plugin
1937 * Adds support for multiple language versions in one tree
1938 * This basically allows for many titles coexisting in one node, but only one of them being visible at any given time
1939 * This is useful for maintaining the same structure in many languages (hence the name of the plugin)
1942 $.jstree
.plugin("languages", {
1943 __init : function () { this._load_css(); },
1946 set_lang : function (i
) {
1947 var langs
= this._get_settings().languages
,
1949 selector
= ".jstree-" + this.get_index() + ' a';
1950 if(!$.isArray(langs
) || langs
.length
=== 0) { return false; }
1951 if($.inArray(i
,langs
) == -1) {
1952 if(!!langs
[i
]) { i
= langs
[i
]; }
1953 else { return false; }
1955 if(i
== this.data
.languages
.current_language
) { return true; }
1956 st
= $.vakata
.css
.get_css(selector
+ "." + this.data
.languages
.current_language
, false, this.data
.languages
.language_css
);
1957 if(st
!== false) { st
.style
.display
= "none"; }
1958 st
= $.vakata
.css
.get_css(selector
+ "." + i
, false, this.data
.languages
.language_css
);
1959 if(st
!== false) { st
.style
.display
= ""; }
1960 this.data
.languages
.current_language
= i
;
1964 get_lang : function () {
1965 return this.data
.languages
.current_language
;
1967 _get_string : function (key
, lang
) {
1968 var langs
= this._get_settings().languages
,
1969 s
= this._get_settings().core
.strings
;
1970 if($.isArray(langs
) && langs
.length
) {
1971 lang
= (lang
&& $.inArray(lang
,langs
) != -1) ? lang
: this.data
.languages
.current_language
;
1973 if(s
[lang
] && s
[lang
][key
]) { return s
[lang
][key
]; }
1974 if(s
[key
]) { return s
[key
]; }
1977 get_text : function (obj
, lang
) {
1978 obj
= this._get_node(obj
) || this.data
.ui
.last_selected
;
1979 if(!obj
.size()) { return false; }
1980 var langs
= this._get_settings().languages
,
1981 s
= this._get_settings().core
.html_titles
;
1982 if($.isArray(langs
) && langs
.length
) {
1983 lang
= (lang
&& $.inArray(lang
,langs
) != -1) ? lang
: this.data
.languages
.current_language
;
1984 obj
= obj
.children("a." + lang
);
1986 else { obj
= obj
.children("a:eq(0)"); }
1989 obj
.children("INS").remove();
1993 obj
= obj
.contents().filter(function() { return this.nodeType
== 3; })[0];
1994 return obj
.nodeValue
;
1997 set_text : function (obj
, val
, lang
) {
1998 obj
= this._get_node(obj
) || this.data
.ui
.last_selected
;
1999 if(!obj
.size()) { return false; }
2000 var langs
= this._get_settings().languages
,
2001 s
= this._get_settings().core
.html_titles
,
2003 if($.isArray(langs
) && langs
.length
) {
2004 lang
= (lang
&& $.inArray(lang
,langs
) != -1) ? lang
: this.data
.languages
.current_language
;
2005 obj
= obj
.children("a." + lang
);
2007 else { obj
= obj
.children("a:eq(0)"); }
2009 tmp
= obj
.children("INS").clone();
2010 obj
.html(val
).prepend(tmp
);
2011 this.__callback({ "obj" : obj
, "name" : val
, "lang" : lang
});
2015 obj
= obj
.contents().filter(function() { return this.nodeType
== 3; })[0];
2016 this.__callback({ "obj" : obj
, "name" : val
, "lang" : lang
});
2017 return (obj
.nodeValue
= val
);
2020 _load_css : function () {
2021 var langs
= this._get_settings().languages
,
2022 str
= "/* languages css */",
2023 selector
= ".jstree-" + this.get_index() + ' a',
2025 if($.isArray(langs
) && langs
.length
) {
2026 this.data
.languages
.current_language
= langs
[0];
2027 for(ln
= 0; ln
< langs
.length
; ln
++) {
2028 str
+= selector
+ "." + langs
[ln
] + " {";
2029 if(langs
[ln
] != this.data
.languages
.current_language
) { str
+= " display:none; "; }
2032 this.data
.languages
.language_css
= $.vakata
.css
.add_sheet({ 'str' : str
, 'title' : "jstree-languages" });
2035 create_node : function (obj
, position
, js
, callback
) {
2036 var t
= this.__call_old(true, obj
, position
, js
, function (t
) {
2037 var langs
= this._get_settings().languages
,
2038 a
= t
.children("a"),
2040 if($.isArray(langs
) && langs
.length
) {
2041 for(ln
= 0; ln
< langs
.length
; ln
++) {
2042 if(!a
.is("." + langs
[ln
])) {
2043 t
.append(a
.eq(0).clone().removeClass(langs
.join(" ")).addClass(langs
[ln
]));
2046 a
.not("." + langs
.join(", .")).remove();
2048 if(callback
) { callback
.call(this, t
); }
2058 * jsTree cookies plugin
2059 * Stores the currently opened/selected nodes in a cookie and then restores them
2060 * Depends on the jquery.cookie plugin
2063 $.jstree
.plugin("cookies", {
2064 __init : function () {
2065 if(typeof $.cookie
=== "undefined") { throw "jsTree cookie: jQuery cookie plugin not included."; }
2067 var s
= this._get_settings().cookies
,
2069 if(!!s
.save_loaded
) {
2070 tmp
= $.cookie(s
.save_loaded
);
2071 if(tmp
&& tmp
.length
) { this.data
.core
.to_load
= tmp
.split(","); }
2073 if(!!s
.save_opened
) {
2074 tmp
= $.cookie(s
.save_opened
);
2075 if(tmp
&& tmp
.length
) { this.data
.core
.to_open
= tmp
.split(","); }
2077 if(!!s
.save_selected
) {
2078 tmp
= $.cookie(s
.save_selected
);
2079 if(tmp
&& tmp
.length
&& this.data
.ui
) { this.data
.ui
.to_select
= tmp
.split(","); }
2081 this.get_container()
2082 .one( ( this.data
.ui
? "reselect" : "reopen" ) + ".jstree", $.proxy(function () {
2083 this.get_container()
2084 .bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree", $.proxy(function (e
) {
2085 if(this._get_settings().cookies
.auto_save
) { this.save_cookie((e
.handleObj
.namespace + e
.handleObj
.type
).replace("jstree","")); }
2090 save_loaded
: "jstree_load",
2091 save_opened
: "jstree_open",
2092 save_selected
: "jstree_select",
2097 save_cookie : function (c
) {
2098 if(this.data
.core
.refreshing
) { return; }
2099 var s
= this._get_settings().cookies
;
2100 if(!c
) { // if called manually and not by event
2103 $.cookie(s
.save_loaded
, this.data
.core
.to_load
.join(","), s
.cookie_options
);
2107 $.cookie(s
.save_opened
, this.data
.core
.to_open
.join(","), s
.cookie_options
);
2109 if(s
.save_selected
&& this.data
.ui
) {
2110 this.save_selected();
2111 $.cookie(s
.save_selected
, this.data
.ui
.to_select
.join(","), s
.cookie_options
);
2118 if(!!s
.save_opened
) {
2120 $.cookie(s
.save_opened
, this.data
.core
.to_open
.join(","), s
.cookie_options
);
2122 if(!!s
.save_loaded
) {
2124 $.cookie(s
.save_loaded
, this.data
.core
.to_load
.join(","), s
.cookie_options
);
2128 case "deselect_node":
2129 if(!!s
.save_selected
&& this.data
.ui
) {
2130 this.save_selected();
2131 $.cookie(s
.save_selected
, this.data
.ui
.to_select
.join(","), s
.cookie_options
);
2138 // include cookies by default
2139 // $.jstree.defaults.plugins.push("cookies");
2144 * jsTree sort plugin
2145 * Sorts items alphabetically (or using any other function)
2148 $.jstree
.plugin("sort", {
2149 __init : function () {
2150 this.get_container()
2151 .bind("load_node.jstree", $.proxy(function (e
, data
) {
2152 var obj
= this._get_node(data
.rslt
.obj
);
2153 obj
= obj
=== -1 ? this.get_container().children("ul") : obj
.children("ul");
2156 .bind("rename_node.jstree create_node.jstree create.jstree", $.proxy(function (e
, data
) {
2157 this.sort(data
.rslt
.obj
.parent());
2159 .bind("move_node.jstree", $.proxy(function (e
, data
) {
2160 var m
= data
.rslt
.np
== -1 ? this.get_container() : data
.rslt
.np
;
2161 this.sort(m
.children("ul"));
2164 defaults : function (a
, b
) { return this.get_text(a
) > this.get_text(b
) ? 1 : -1; },
2166 sort : function (obj
) {
2167 var s
= this._get_settings().sort
,
2169 obj
.append($.makeArray(obj
.children("li")).sort($.proxy(s
, t
)));
2170 obj
.find("> li > ul").each(function() { t
.sort($(this)); });
2171 this.clean_node(obj
);
2180 * Drag and drop plugin for moving/copying nodes
2204 drag_start : function (e
, data
, html
) {
2205 if($.vakata
.dnd
.is_drag
) { $.vakata
.drag_stop({}); }
2207 e
.currentTarget
.unselectable
= "on";
2208 e
.currentTarget
.onselectstart = function() { return false; };
2209 if(e
.currentTarget
.style
) { e
.currentTarget
.style
.MozUserSelect
= "none"; }
2211 $.vakata
.dnd
.init_x
= e
.pageX
;
2212 $.vakata
.dnd
.init_y
= e
.pageY
;
2213 $.vakata
.dnd
.user_data
= data
;
2214 $.vakata
.dnd
.is_down
= true;
2215 $.vakata
.dnd
.helper
= $("<div id='vakata-dragged' />").html(html
); //.fadeTo(10,0.25);
2216 $(document
).bind("mousemove", $.vakata
.dnd
.drag
);
2217 $(document
).bind("mouseup", $.vakata
.dnd
.drag_stop
);
2220 drag : function (e
) {
2221 if(!$.vakata
.dnd
.is_down
) { return; }
2222 if(!$.vakata
.dnd
.is_drag
) {
2223 if(Math
.abs(e
.pageX
- $.vakata
.dnd
.init_x
) > 5 || Math
.abs(e
.pageY
- $.vakata
.dnd
.init_y
) > 5) {
2224 $.vakata
.dnd
.helper
.appendTo("body");
2225 $.vakata
.dnd
.is_drag
= true;
2226 $(document
).triggerHandler("drag_start.vakata", { "event" : e
, "data" : $.vakata
.dnd
.user_data
});
2231 // maybe use a scrolling parent element instead of document?
2232 if(e
.type
=== "mousemove") { // thought of adding scroll in order to move the helper, but mouse poisition is n/a
2233 var d
= $(document
), t
= d
.scrollTop(), l
= d
.scrollLeft();
2234 if(e
.pageY
- t
< 20) {
2235 if(sti
&& dir1
=== "down") { clearInterval(sti
); sti
= false; }
2236 if(!sti
) { dir1
= "up"; sti
= setInterval(function () { $(document
).scrollTop($(document
).scrollTop() - $.vakata
.dnd
.scroll_spd
); }, 150); }
2239 if(sti
&& dir1
=== "up") { clearInterval(sti
); sti
= false; }
2241 if($(window
).height() - (e
.pageY
- t
) < 20) {
2242 if(sti
&& dir1
=== "up") { clearInterval(sti
); sti
= false; }
2243 if(!sti
) { dir1
= "down"; sti
= setInterval(function () { $(document
).scrollTop($(document
).scrollTop() + $.vakata
.dnd
.scroll_spd
); }, 150); }
2246 if(sti
&& dir1
=== "down") { clearInterval(sti
); sti
= false; }
2249 if(e
.pageX
- l
< 20) {
2250 if(sli
&& dir2
=== "right") { clearInterval(sli
); sli
= false; }
2251 if(!sli
) { dir2
= "left"; sli
= setInterval(function () { $(document
).scrollLeft($(document
).scrollLeft() - $.vakata
.dnd
.scroll_spd
); }, 150); }
2254 if(sli
&& dir2
=== "left") { clearInterval(sli
); sli
= false; }
2256 if($(window
).width() - (e
.pageX
- l
) < 20) {
2257 if(sli
&& dir2
=== "left") { clearInterval(sli
); sli
= false; }
2258 if(!sli
) { dir2
= "right"; sli
= setInterval(function () { $(document
).scrollLeft($(document
).scrollLeft() + $.vakata
.dnd
.scroll_spd
); }, 150); }
2261 if(sli
&& dir2
=== "right") { clearInterval(sli
); sli
= false; }
2265 $.vakata
.dnd
.helper
.css({ left
: (e
.pageX
+ $.vakata
.dnd
.helper_left
) + "px", top
: (e
.pageY
+ $.vakata
.dnd
.helper_top
) + "px" });
2266 $(document
).triggerHandler("drag.vakata", { "event" : e
, "data" : $.vakata
.dnd
.user_data
});
2268 drag_stop : function (e
) {
2269 if(sli
) { clearInterval(sli
); }
2270 if(sti
) { clearInterval(sti
); }
2271 $(document
).unbind("mousemove", $.vakata
.dnd
.drag
);
2272 $(document
).unbind("mouseup", $.vakata
.dnd
.drag_stop
);
2273 $(document
).triggerHandler("drag_stop.vakata", { "event" : e
, "data" : $.vakata
.dnd
.user_data
});
2274 $.vakata
.dnd
.helper
.remove();
2275 $.vakata
.dnd
.init_x
= 0;
2276 $.vakata
.dnd
.init_y
= 0;
2277 $.vakata
.dnd
.user_data
= {};
2278 $.vakata
.dnd
.is_down
= false;
2279 $.vakata
.dnd
.is_drag
= false;
2283 var css_string
= '#vakata-dragged { display:block; margin:0 0 0 0; padding:4px 4px 4px 24px; position:absolute; top:-2000px; line-height:16px; z-index:10000; } ';
2284 $.vakata
.css
.add_sheet({ str
: css_string
, title
: "vakata" });
2287 $.jstree
.plugin("dnd", {
2288 __init : function () {
2306 this.get_container()
2307 .bind("mouseenter.jstree", $.proxy(function (e
) {
2308 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
) {
2309 if(this.data
.themes
) {
2310 m
.attr("class", "jstree-" + this.data
.themes
.theme
);
2311 if(ml
) { ml
.attr("class", "jstree-" + this.data
.themes
.theme
); }
2312 $.vakata
.dnd
.helper
.attr("class", "jstree-dnd-helper jstree-" + this.data
.themes
.theme
);
2314 //if($(e.currentTarget).find("> ul > li").length === 0) {
2315 if(e
.currentTarget
=== e
.target
&& $.vakata
.dnd
.user_data
.obj
&& $($.vakata
.dnd
.user_data
.obj
).length
&& $($.vakata
.dnd
.user_data
.obj
).parents(".jstree:eq(0)")[0] !== e
.target
) { // node should not be from the same tree
2316 var tr
= $.jstree
._reference(e
.target
), dc
;
2317 if(tr
.data
.dnd
.foreign
) {
2318 dc
= tr
._get_settings().dnd
.drag_check
.call(this, { "o" : o
, "r" : tr
.get_container(), is_root
: true });
2319 if(dc
=== true || dc
.inside
=== true || dc
.before
=== true || dc
.after
=== true) {
2320 $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-ok");
2324 tr
.prepare_move(o
, tr
.get_container(), "last");
2325 if(tr
.check_move()) {
2326 $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-ok");
2332 .bind("mouseup.jstree", $.proxy(function (e
) {
2333 //if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && $(e.currentTarget).find("> ul > li").length === 0) {
2334 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
&& e
.currentTarget
=== e
.target
&& $.vakata
.dnd
.user_data
.obj
&& $($.vakata
.dnd
.user_data
.obj
).length
&& $($.vakata
.dnd
.user_data
.obj
).parents(".jstree:eq(0)")[0] !== e
.target
) { // node should not be from the same tree
2335 var tr
= $.jstree
._reference(e
.currentTarget
), dc
;
2336 if(tr
.data
.dnd
.foreign
) {
2337 dc
= tr
._get_settings().dnd
.drag_check
.call(this, { "o" : o
, "r" : tr
.get_container(), is_root
: true });
2338 if(dc
=== true || dc
.inside
=== true || dc
.before
=== true || dc
.after
=== true) {
2339 tr
._get_settings().dnd
.drag_finish
.call(this, { "o" : o
, "r" : tr
.get_container(), is_root
: true });
2343 tr
.move_node(o
, tr
.get_container(), "last", e
[tr
._get_settings().dnd
.copy_modifier
+ "Key"]);
2347 .bind("mouseleave.jstree", $.proxy(function (e
) {
2348 if(e
.relatedTarget
&& e
.relatedTarget
.id
&& e
.relatedTarget
.id
=== "jstree-marker-line") {
2351 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
) {
2352 if(this.data
.dnd
.i1
) { clearInterval(this.data
.dnd
.i1
); }
2353 if(this.data
.dnd
.i2
) { clearInterval(this.data
.dnd
.i2
); }
2354 if(this.data
.dnd
.to1
) { clearTimeout(this.data
.dnd
.to1
); }
2355 if(this.data
.dnd
.to2
) { clearTimeout(this.data
.dnd
.to2
); }
2356 if($.vakata
.dnd
.helper
.children("ins").hasClass("jstree-ok")) {
2357 $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-invalid");
2361 .bind("mousemove.jstree", $.proxy(function (e
) {
2362 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
) {
2363 var cnt
= this.get_container()[0];
2365 // Horizontal scroll
2366 if(e
.pageX
+ 24 > this.data
.dnd
.cof
.left
+ this.data
.dnd
.cw
) {
2367 if(this.data
.dnd
.i1
) { clearInterval(this.data
.dnd
.i1
); }
2368 this.data
.dnd
.i1
= setInterval($.proxy(function () { this.scrollLeft
+= $.vakata
.dnd
.scroll_spd
; }, cnt
), 100);
2370 else if(e
.pageX
- 24 < this.data
.dnd
.cof
.left
) {
2371 if(this.data
.dnd
.i1
) { clearInterval(this.data
.dnd
.i1
); }
2372 this.data
.dnd
.i1
= setInterval($.proxy(function () { this.scrollLeft
-= $.vakata
.dnd
.scroll_spd
; }, cnt
), 100);
2375 if(this.data
.dnd
.i1
) { clearInterval(this.data
.dnd
.i1
); }
2379 if(e
.pageY
+ 24 > this.data
.dnd
.cof
.top
+ this.data
.dnd
.ch
) {
2380 if(this.data
.dnd
.i2
) { clearInterval(this.data
.dnd
.i2
); }
2381 this.data
.dnd
.i2
= setInterval($.proxy(function () { this.scrollTop
+= $.vakata
.dnd
.scroll_spd
; }, cnt
), 100);
2383 else if(e
.pageY
- 24 < this.data
.dnd
.cof
.top
) {
2384 if(this.data
.dnd
.i2
) { clearInterval(this.data
.dnd
.i2
); }
2385 this.data
.dnd
.i2
= setInterval($.proxy(function () { this.scrollTop
-= $.vakata
.dnd
.scroll_spd
; }, cnt
), 100);
2388 if(this.data
.dnd
.i2
) { clearInterval(this.data
.dnd
.i2
); }
2393 .bind("scroll.jstree", $.proxy(function (e
) {
2394 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
&& m
&& ml
) {
2399 .delegate("a", "mousedown.jstree", $.proxy(function (e
) {
2401 this.start_drag(e
.currentTarget
, e
);
2405 .delegate("a", "mouseenter.jstree", $.proxy(function (e
) {
2406 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
) {
2407 this.dnd_enter(e
.currentTarget
);
2410 .delegate("a", "mousemove.jstree", $.proxy(function (e
) {
2411 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
) {
2412 if(!r
|| !r
.length
|| r
.children("a")[0] !== e
.currentTarget
) {
2413 this.dnd_enter(e
.currentTarget
);
2415 if(typeof this.data
.dnd
.off
.top
=== "undefined") { this.data
.dnd
.off
= $(e
.target
).offset(); }
2416 this.data
.dnd
.w
= (e
.pageY
- (this.data
.dnd
.off
.top
|| 0)) % this.data
.core
.li_height
;
2417 if(this.data
.dnd
.w
< 0) { this.data
.dnd
.w
+= this.data
.core
.li_height
; }
2421 .delegate("a", "mouseleave.jstree", $.proxy(function (e
) {
2422 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
) {
2423 if(e
.relatedTarget
&& e
.relatedTarget
.id
&& e
.relatedTarget
.id
=== "jstree-marker-line") {
2427 if(ml
) { ml
.hide(); }
2429 var ec = $(e.currentTarget).closest("li"),
2430 er = $(e.relatedTarget).closest("li");
2431 if(er[0] !== ec.prev()[0] && er[0] !== ec.next()[0]) {
2433 if(ml) { ml.hide(); }
2436 this.data
.dnd
.mto
= setTimeout(
2437 (function (t
) { return function () { t
.dnd_leave(e
); }; })(this),
2441 .delegate("a", "mouseup.jstree", $.proxy(function (e
) {
2442 if($.vakata
.dnd
.is_drag
&& $.vakata
.dnd
.user_data
.jstree
) {
2448 .bind("drag_stop.vakata", $.proxy(function () {
2449 if(this.data
.dnd
.to1
) { clearTimeout(this.data
.dnd
.to1
); }
2450 if(this.data
.dnd
.to2
) { clearTimeout(this.data
.dnd
.to2
); }
2451 if(this.data
.dnd
.i1
) { clearInterval(this.data
.dnd
.i1
); }
2452 if(this.data
.dnd
.i2
) { clearInterval(this.data
.dnd
.i2
); }
2453 this.data
.dnd
.after
= false;
2454 this.data
.dnd
.before
= false;
2455 this.data
.dnd
.inside
= false;
2456 this.data
.dnd
.off
= false;
2457 this.data
.dnd
.prepared
= false;
2458 this.data
.dnd
.w
= false;
2459 this.data
.dnd
.to1
= false;
2460 this.data
.dnd
.to2
= false;
2461 this.data
.dnd
.i1
= false;
2462 this.data
.dnd
.i2
= false;
2463 this.data
.dnd
.active
= false;
2464 this.data
.dnd
.foreign
= false;
2465 if(m
) { m
.css({ "top" : "-2000px" }); }
2466 if(ml
) { ml
.css({ "top" : "-2000px" }); }
2468 .bind("drag_start.vakata", $.proxy(function (e
, data
) {
2469 if(data
.data
.jstree
) {
2470 var et
= $(data
.event
.target
);
2471 if(et
.closest(".jstree").hasClass("jstree-" + this.get_index())) {
2477 .bind("keydown.jstree-" + this.get_index() + " keyup.jstree-" + this.get_index(), $.proxy(function(e) {
2478 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && !this.data.dnd.foreign) {
2479 var h = $.vakata.dnd.helper.children("ins");
2480 if(e[this._get_settings().dnd.copy_modifier + "Key"] && h.hasClass("jstree-ok")) {
2481 h.parent().html(h.parent().html().replace(/ \(Copy\)$/, "") + " (Copy)");
2484 h.parent().html(h.parent().html().replace(/ \(Copy\)$/, ""));
2491 var s
= this._get_settings().dnd
;
2494 .delegate(s
.drag_target
, "mousedown.jstree-" + this.get_index(), $.proxy(function (e
) {
2496 $.vakata
.dnd
.drag_start(e
, { jstree
: true, obj
: e
.target
}, "<ins class='jstree-icon'></ins>" + $(e
.target
).text() );
2497 if(this.data
.themes
) {
2498 if(m
) { m
.attr("class", "jstree-" + this.data
.themes
.theme
); }
2499 if(ml
) { ml
.attr("class", "jstree-" + this.data
.themes
.theme
); }
2500 $.vakata
.dnd
.helper
.attr("class", "jstree-dnd-helper jstree-" + this.data
.themes
.theme
);
2502 $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-invalid");
2503 var cnt
= this.get_container();
2504 this.data
.dnd
.cof
= cnt
.offset();
2505 this.data
.dnd
.cw
= parseInt(cnt
.width(),10);
2506 this.data
.dnd
.ch
= parseInt(cnt
.height(),10);
2507 this.data
.dnd
.foreign
= true;
2513 .delegate(s
.drop_target
, "mouseenter.jstree-" + this.get_index(), $.proxy(function (e
) {
2514 if(this.data
.dnd
.active
&& this._get_settings().dnd
.drop_check
.call(this, { "o" : o
, "r" : $(e
.target
), "e" : e
})) {
2515 $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-ok");
2518 .delegate(s
.drop_target
, "mouseleave.jstree-" + this.get_index(), $.proxy(function (e
) {
2519 if(this.data
.dnd
.active
) {
2520 $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-invalid");
2523 .delegate(s
.drop_target
, "mouseup.jstree-" + this.get_index(), $.proxy(function (e
) {
2524 if(this.data
.dnd
.active
&& $.vakata
.dnd
.helper
.children("ins").hasClass("jstree-ok")) {
2525 this._get_settings().dnd
.drop_finish
.call(this, { "o" : o
, "r" : $(e
.target
), "e" : e
});
2531 copy_modifier
: "ctrl",
2532 check_timeout
: 100,
2534 drop_target
: ".jstree-drop",
2535 drop_check : function (data
) { return true; },
2536 drop_finish
: $.noop
,
2537 drag_target
: ".jstree-draggable",
2538 drag_finish
: $.noop
,
2539 drag_check : function (data
) { return { after
: false, before
: false, inside
: true }; }
2542 dnd_prepare : function () {
2543 if(!r
|| !r
.length
) { return; }
2544 this.data
.dnd
.off
= r
.offset();
2545 if(this._get_settings().core
.rtl
) {
2546 this.data
.dnd
.off
.right
= this.data
.dnd
.off
.left
+ r
.width();
2548 if(this.data
.dnd
.foreign
) {
2549 var a
= this._get_settings().dnd
.drag_check
.call(this, { "o" : o
, "r" : r
});
2550 this.data
.dnd
.after
= a
.after
;
2551 this.data
.dnd
.before
= a
.before
;
2552 this.data
.dnd
.inside
= a
.inside
;
2553 this.data
.dnd
.prepared
= true;
2554 return this.dnd_show();
2556 this.prepare_move(o
, r
, "before");
2557 this.data
.dnd
.before
= this.check_move();
2558 this.prepare_move(o
, r
, "after");
2559 this.data
.dnd
.after
= this.check_move();
2560 if(this._is_loaded(r
)) {
2561 this.prepare_move(o
, r
, "inside");
2562 this.data
.dnd
.inside
= this.check_move();
2565 this.data
.dnd
.inside
= false;
2567 this.data
.dnd
.prepared
= true;
2568 return this.dnd_show();
2570 dnd_show : function () {
2571 if(!this.data
.dnd
.prepared
) { return; }
2572 var o
= ["before","inside","after"],
2574 rtl
= this._get_settings().core
.rtl
,
2576 if(this.data
.dnd
.w
< this.data
.core
.li_height
/3) { o
= ["before","inside","after"]; }
2577 else if(this.data
.dnd
.w
<= this.data
.core
.li_height
*2/3) {
2578 o
= this.data
.dnd
.w
< this.data
.core
.li_height
/2 ? ["inside","before","after"] : ["inside","after","before"];
2580 else { o
= ["after","inside","before"]; }
2581 $.each(o
, $.proxy(function (i
, val
) {
2582 if(this.data
.dnd
[val
]) {
2583 $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-ok");
2588 if(r
=== false) { $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-invalid"); }
2590 pos
= rtl
? (this.data
.dnd
.off
.right
- 18) : (this.data
.dnd
.off
.left
+ 10);
2593 m
.css({ "left" : pos
+ "px", "top" : (this.data
.dnd
.off
.top
- 6) + "px" }).show();
2594 if(ml
) { ml
.css({ "left" : (pos
+ 8) + "px", "top" : (this.data
.dnd
.off
.top
- 1) + "px" }).show(); }
2597 m
.css({ "left" : pos
+ "px", "top" : (this.data
.dnd
.off
.top
+ this.data
.core
.li_height
- 6) + "px" }).show();
2598 if(ml
) { ml
.css({ "left" : (pos
+ 8) + "px", "top" : (this.data
.dnd
.off
.top
+ this.data
.core
.li_height
- 1) + "px" }).show(); }
2601 m
.css({ "left" : pos
+ ( rtl
? -4 : 4) + "px", "top" : (this.data
.dnd
.off
.top
+ this.data
.core
.li_height
/2 - 5) + "px" }).show();
2602 if(ml
) { ml
.hide(); }
2606 if(ml
) { ml
.hide(); }
2612 dnd_open : function () {
2613 this.data
.dnd
.to2
= false;
2614 this.open_node(r
, $.proxy(this.dnd_prepare
,this), true);
2616 dnd_finish : function (e
) {
2617 if(this.data
.dnd
.foreign
) {
2618 if(this.data
.dnd
.after
|| this.data
.dnd
.before
|| this.data
.dnd
.inside
) {
2619 this._get_settings().dnd
.drag_finish
.call(this, { "o" : o
, "r" : r
, "p" : last_pos
});
2624 this.move_node(o
, r
, last_pos
, e
[this._get_settings().dnd
.copy_modifier
+ "Key"]);
2629 if(ml
) { ml
.hide(); }
2631 dnd_enter : function (obj
) {
2632 if(this.data
.dnd
.mto
) {
2633 clearTimeout(this.data
.dnd
.mto
);
2634 this.data
.dnd
.mto
= false;
2636 var s
= this._get_settings().dnd
;
2637 this.data
.dnd
.prepared
= false;
2638 r
= this._get_node(obj
);
2639 if(s
.check_timeout
) {
2640 // do the calculations after a minimal timeout (users tend to drag quickly to the desired location)
2641 if(this.data
.dnd
.to1
) { clearTimeout(this.data
.dnd
.to1
); }
2642 this.data
.dnd
.to1
= setTimeout($.proxy(this.dnd_prepare
, this), s
.check_timeout
);
2647 if(s
.open_timeout
) {
2648 if(this.data
.dnd
.to2
) { clearTimeout(this.data
.dnd
.to2
); }
2649 if(r
&& r
.length
&& r
.hasClass("jstree-closed")) {
2650 // if the node is closed - open it, then recalculate
2651 this.data
.dnd
.to2
= setTimeout($.proxy(this.dnd_open
, this), s
.open_timeout
);
2655 if(r
&& r
.length
&& r
.hasClass("jstree-closed")) {
2660 dnd_leave : function (e
) {
2661 this.data
.dnd
.after
= false;
2662 this.data
.dnd
.before
= false;
2663 this.data
.dnd
.inside
= false;
2664 $.vakata
.dnd
.helper
.children("ins").attr("class","jstree-invalid");
2666 if(ml
) { ml
.hide(); }
2667 if(r
&& r
[0] === e
.target
.parentNode
) {
2668 if(this.data
.dnd
.to1
) {
2669 clearTimeout(this.data
.dnd
.to1
);
2670 this.data
.dnd
.to1
= false;
2672 if(this.data
.dnd
.to2
) {
2673 clearTimeout(this.data
.dnd
.to2
);
2674 this.data
.dnd
.to2
= false;
2678 start_drag : function (obj
, e
) {
2679 o
= this._get_node(obj
);
2680 if(this.data
.ui
&& this.is_selected(o
)) { o
= this._get_node(null, true); }
2681 var dt
= o
.length
> 1 ? this._get_string("multiple_selection") : this.get_text(o
),
2682 cnt
= this.get_container();
2683 if(!this._get_settings().core
.html_titles
) { dt
= dt
.replace(/</ig,"<").replace(/>/ig
,">"); }
2684 $.vakata
.dnd
.drag_start(e
, { jstree
: true, obj
: o
}, "<ins class='jstree-icon'></ins>" + dt
);
2685 if(this.data
.themes
) {
2686 if(m
) { m
.attr("class", "jstree-" + this.data
.themes
.theme
); }
2687 if(ml
) { ml
.attr("class", "jstree-" + this.data
.themes
.theme
); }
2688 $.vakata
.dnd
.helper
.attr("class", "jstree-dnd-helper jstree-" + this.data
.themes
.theme
);
2690 this.data
.dnd
.cof
= cnt
.offset();
2691 this.data
.dnd
.cw
= parseInt(cnt
.width(),10);
2692 this.data
.dnd
.ch
= parseInt(cnt
.height(),10);
2693 this.data
.dnd
.active
= true;
2698 var css_string
= '' +
2699 '#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; ' +
2700 ' -moz-border-radius:4px; border-radius:4px; -webkit-border-radius:4px; ' +
2702 '#vakata-dragged .jstree-ok { background:green; } ' +
2703 '#vakata-dragged .jstree-invalid { background:red; } ' +
2704 '#jstree-marker { padding:0; margin:0; font-size:12px; overflow:hidden; height:12px; width:8px; position:absolute; top:-30px; z-index:10001; background-repeat:no-repeat; display:none; background-color:transparent; text-shadow:1px 1px 1px white; color:black; line-height:10px; } ' +
2705 '#jstree-marker-line { padding:0; margin:0; line-height:0%; font-size:1px; overflow:hidden; height:1px; width:100px; position:absolute; top:-30px; z-index:10000; background-repeat:no-repeat; display:none; background-color:#456c43; ' +
2706 ' cursor:pointer; border:1px solid #eeeeee; border-left:0; -moz-box-shadow: 0px 0px 2px #666; -webkit-box-shadow: 0px 0px 2px #666; box-shadow: 0px 0px 2px #666; ' +
2707 ' -moz-border-radius:1px; border-radius:1px; -webkit-border-radius:1px; ' +
2710 $.vakata
.css
.add_sheet({ str
: css_string
, title
: "jstree" });
2711 m
= $("<div />").attr({ id
: "jstree-marker" }).hide().html("»")
2712 .bind("mouseleave mouseenter", function (e
) {
2716 e
.stopImmediatePropagation();
2720 ml
= $("<div />").attr({ id
: "jstree-marker-line" }).hide()
2721 .bind("mouseup", function (e
) {
2723 r
.children("a").trigger(e
);
2725 e
.stopImmediatePropagation();
2729 .bind("mouseleave", function (e
) {
2730 var rt
= $(e
.relatedTarget
);
2731 if(rt
.is(".jstree") || rt
.closest(".jstree").length
=== 0) {
2733 r
.children("a").trigger(e
);
2737 e
.stopImmediatePropagation();
2743 $(document
).bind("drag_start.vakata", function (e
, data
) {
2744 if(data
.data
.jstree
) { m
.show(); if(ml
) { ml
.show(); } }
2746 $(document
).bind("drag_stop.vakata", function (e
, data
) {
2747 if(data
.data
.jstree
) { m
.hide(); if(ml
) { ml
.hide(); } }
2754 * jsTree checkbox plugin
2755 * Inserts checkboxes in front of every node
2756 * Depends on the ui plugin
2757 * DOES NOT WORK NICELY WITH MULTITREE DRAG'N'DROP
2760 $.jstree
.plugin("checkbox", {
2761 __init : function () {
2762 this.data
.checkbox
.noui
= this._get_settings().checkbox
.override_ui
;
2763 if(this.data
.ui
&& this.data
.checkbox
.noui
) {
2764 this.select_node
= this.deselect_node
= this.deselect_all
= $.noop
;
2765 this.get_selected
= this.get_checked
;
2768 this.get_container()
2769 .bind("open_node.jstree create_node.jstree clean_node.jstree refresh.jstree", $.proxy(function (e
, data
) {
2770 this._prepare_checkboxes(data
.rslt
.obj
);
2772 .bind("loaded.jstree", $.proxy(function (e
) {
2773 this._prepare_checkboxes();
2775 .delegate( (this.data
.ui
&& this.data
.checkbox
.noui
? "a" : "ins.jstree-checkbox") , "click.jstree", $.proxy(function (e
) {
2777 if(this._get_node(e
.target
).hasClass("jstree-checked")) { this.uncheck_node(e
.target
); }
2778 else { this.check_node(e
.target
); }
2779 if(this.data
.ui
&& this.data
.checkbox
.noui
) {
2780 this.save_selected();
2781 if(this.data
.cookies
) { this.save_cookie("select_node"); }
2784 e
.stopImmediatePropagation();
2790 override_ui
: false,
2792 real_checkboxes
: false,
2793 checked_parent_open
: true,
2794 real_checkboxes_names : function (n
) { return [ ("check_" + (n
[0].id
|| Math
.ceil(Math
.random() * 10000))) , 1]; }
2796 __destroy : function () {
2797 this.get_container()
2798 .find("input.jstree-real-checkbox").removeClass("jstree-real-checkbox").end()
2799 .find("ins.jstree-checkbox").remove();
2802 _checkbox_notify : function (n
, data
) {
2804 this.check_node(n
, false);
2807 _prepare_checkboxes : function (obj
) {
2808 obj
= !obj
|| obj
== -1 ? this.get_container().find("> ul > li") : this._get_node(obj
);
2809 if(obj
=== false) { return; } // added for removing root nodes
2810 var c
, _this
= this, t
, ts
= this._get_settings().checkbox
.two_state
, rc
= this._get_settings().checkbox
.real_checkboxes
, rcn
= this._get_settings().checkbox
.real_checkboxes_names
;
2811 obj
.each(function () {
2813 c
= t
.is("li") && (t
.hasClass("jstree-checked") || (rc
&& t
.children(":checked").length
)) ? "jstree-checked" : "jstree-unchecked";
2814 t
.find("li").andSelf().each(function () {
2815 var $t
= $(this), nm
;
2816 $t
.children("a" + (_this
.data
.languages
? "" : ":eq(0)") ).not(":has(.jstree-checkbox)").prepend("<ins class='jstree-checkbox'> </ins>").parent().not(".jstree-checked, .jstree-unchecked").addClass( ts
? "jstree-unchecked" : c
);
2818 if(!$t
.children(":checkbox").length
) {
2819 nm
= rcn
.call(_this
, $t
);
2820 $t
.prepend("<input type='checkbox' class='jstree-real-checkbox' id='" + nm
[0] + "' name='" + nm
[0] + "' value='" + nm
[1] + "' />");
2823 $t
.children(":checkbox").addClass("jstree-real-checkbox");
2827 if(c
=== "jstree-checked" || $t
.hasClass("jstree-checked") || $t
.children(':checked').length
) {
2828 $t
.find("li").andSelf().addClass("jstree-checked").children(":checkbox").prop("checked", true);
2832 if($t
.hasClass("jstree-checked") || $t
.children(':checked').length
) {
2833 $t
.addClass("jstree-checked").children(":checkbox").prop("checked", true);
2839 obj
.find(".jstree-checked").parent().parent().each(function () { _this
._repair_state(this); });
2842 change_state : function (obj
, state
) {
2843 obj
= this._get_node(obj
);
2844 var coll
= false, rc
= this._get_settings().checkbox
.real_checkboxes
;
2845 if(!obj
|| obj
=== -1) { return false; }
2846 state
= (state
=== false || state
=== true) ? state
: obj
.hasClass("jstree-checked");
2847 if(this._get_settings().checkbox
.two_state
) {
2849 obj
.removeClass("jstree-checked").addClass("jstree-unchecked");
2850 if(rc
) { obj
.children(":checkbox").prop("checked", false); }
2853 obj
.removeClass("jstree-unchecked").addClass("jstree-checked");
2854 if(rc
) { obj
.children(":checkbox").prop("checked", true); }
2859 coll
= obj
.find("li").andSelf();
2860 if(!coll
.filter(".jstree-checked, .jstree-undetermined").length
) { return false; }
2861 coll
.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");
2862 if(rc
) { coll
.children(":checkbox").prop("checked", false); }
2865 coll
= obj
.find("li").andSelf();
2866 if(!coll
.filter(".jstree-unchecked, .jstree-undetermined").length
) { return false; }
2867 coll
.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");
2868 if(rc
) { coll
.children(":checkbox").prop("checked", true); }
2869 if(this.data
.ui
) { this.data
.ui
.last_selected
= obj
; }
2870 this.data
.checkbox
.last_selected
= obj
;
2872 obj
.parentsUntil(".jstree", "li").each(function () {
2873 var $this = $(this);
2875 if($this.children("ul").children("li.jstree-checked, li.jstree-undetermined").length
) {
2876 $this.parentsUntil(".jstree", "li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
2877 if(rc
) { $this.parentsUntil(".jstree", "li").andSelf().children(":checkbox").prop("checked", false); }
2881 $this.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");
2882 if(rc
) { $this.children(":checkbox").prop("checked", false); }
2886 if($this.children("ul").children("li.jstree-unchecked, li.jstree-undetermined").length
) {
2887 $this.parentsUntil(".jstree", "li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
2888 if(rc
) { $this.parentsUntil(".jstree", "li").andSelf().children(":checkbox").prop("checked", false); }
2892 $this.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");
2893 if(rc
) { $this.children(":checkbox").prop("checked", true); }
2898 if(this.data
.ui
&& this.data
.checkbox
.noui
) { this.data
.ui
.selected
= this.get_checked(); }
2899 this.__callback(obj
);
2902 check_node : function (obj
) {
2903 if(this.change_state(obj
, false)) {
2904 obj
= this._get_node(obj
);
2905 if(this._get_settings().checkbox
.checked_parent_open
) {
2907 obj
.parents(".jstree-closed").each(function () { t
.open_node(this, false, true); });
2909 this.__callback({ "obj" : obj
});
2912 uncheck_node : function (obj
) {
2913 if(this.change_state(obj
, true)) { this.__callback({ "obj" : this._get_node(obj
) }); }
2915 check_all : function () {
2917 coll
= this._get_settings().checkbox
.two_state
? this.get_container_ul().find("li") : this.get_container_ul().children("li");
2918 coll
.each(function () {
2919 _this
.change_state(this, false);
2923 uncheck_all : function () {
2925 coll
= this._get_settings().checkbox
.two_state
? this.get_container_ul().find("li") : this.get_container_ul().children("li");
2926 coll
.each(function () {
2927 _this
.change_state(this, true);
2932 is_checked : function(obj
) {
2933 obj
= this._get_node(obj
);
2934 return obj
.length
? obj
.is(".jstree-checked") : false;
2936 get_checked : function (obj
, get_all
) {
2937 obj
= !obj
|| obj
=== -1 ? this.get_container() : this._get_node(obj
);
2938 return get_all
|| this._get_settings().checkbox
.two_state
? obj
.find(".jstree-checked") : obj
.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked");
2940 get_unchecked : function (obj
, get_all
) {
2941 obj
= !obj
|| obj
=== -1 ? this.get_container() : this._get_node(obj
);
2942 return get_all
|| this._get_settings().checkbox
.two_state
? obj
.find(".jstree-unchecked") : obj
.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked");
2945 show_checkboxes : function () { this.get_container().children("ul").removeClass("jstree-no-checkboxes"); },
2946 hide_checkboxes : function () { this.get_container().children("ul").addClass("jstree-no-checkboxes"); },
2948 _repair_state : function (obj
) {
2949 obj
= this._get_node(obj
);
2950 if(!obj
.length
) { return; }
2951 if(this._get_settings().checkbox
.two_state
) {
2952 obj
.find('li').andSelf().not('.jstree-checked').removeClass('jstree-undetermined').addClass('jstree-unchecked').children(':checkbox').prop('checked', true);
2955 var rc
= this._get_settings().checkbox
.real_checkboxes
,
2956 a
= obj
.find("> ul > .jstree-checked").length
,
2957 b
= obj
.find("> ul > .jstree-undetermined").length
,
2958 c
= obj
.find("> ul > li").length
;
2959 if(c
=== 0) { if(obj
.hasClass("jstree-undetermined")) { this.change_state(obj
, false); } }
2960 else if(a
=== 0 && b
=== 0) { this.change_state(obj
, true); }
2961 else if(a
=== c
) { this.change_state(obj
, false); }
2963 obj
.parentsUntil(".jstree","li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
2964 if(rc
) { obj
.parentsUntil(".jstree", "li").andSelf().children(":checkbox").prop("checked", false); }
2967 reselect : function () {
2968 if(this.data
.ui
&& this.data
.checkbox
.noui
) {
2970 s
= this.data
.ui
.to_select
;
2971 s
= $.map($.makeArray(s
), function (n
) { return "#" + n
.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); });
2972 this.deselect_all();
2973 $.each(s
, function (i
, val
) { _this
.check_node(val
); });
2980 save_loaded : function () {
2982 this.data
.core
.to_load
= [];
2983 this.get_container_ul().find("li.jstree-closed.jstree-undetermined").each(function () {
2984 if(this.id
) { _this
.data
.core
.to_load
.push("#" + this.id
); }
2990 var css_string
= '.jstree .jstree-real-checkbox { display:none; } ';
2991 $.vakata
.css
.add_sheet({ str
: css_string
, title
: "jstree" });
2998 * The XML data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions.
3001 $.vakata
.xslt = function (xml
, xsl
, callback
) {
3002 var rs
= "", xm
, xs
, processor
, support
;
3003 // TODO: IE9 no XSLTProcessor, no document.recalc
3004 if(document
.recalc
) {
3005 xm
= document
.createElement('xml');
3006 xs
= document
.createElement('xml');
3009 $("body").append(xm
).append(xs
);
3010 setTimeout( (function (xm
, xs
, callback
) {
3011 return function () {
3012 callback
.call(null, xm
.transformNode(xs
.XMLDocument
));
3013 setTimeout( (function (xm
, xs
) { return function () { $(xm
).remove(); $(xs
).remove(); }; })(xm
, xs
), 200);
3015 })(xm
, xs
, callback
), 100);
3018 if(typeof window
.DOMParser
!== "undefined" && typeof window
.XMLHttpRequest
!== "undefined" && typeof window
.XSLTProcessor
=== "undefined") {
3019 xml
= new DOMParser().parseFromString(xml
, "text/xml");
3020 xsl
= new DOMParser().parseFromString(xsl
, "text/xml");
3021 // alert(xml.transformNode());
3022 // callback.call(null, new XMLSerializer().serializeToString(rs));
3025 if(typeof window
.DOMParser
!== "undefined" && typeof window
.XMLHttpRequest
!== "undefined" && typeof window
.XSLTProcessor
!== "undefined") {
3026 processor
= new XSLTProcessor();
3027 support
= $.isFunction(processor
.transformDocument
) ? (typeof window
.XMLSerializer
!== "undefined") : true;
3028 if(!support
) { return false; }
3029 xml
= new DOMParser().parseFromString(xml
, "text/xml");
3030 xsl
= new DOMParser().parseFromString(xsl
, "text/xml");
3031 if($.isFunction(processor
.transformDocument
)) {
3032 rs
= document
.implementation
.createDocument("", "", null);
3033 processor
.transformDocument(xml
, xsl
, rs
, null);
3034 callback
.call(null, new XMLSerializer().serializeToString(rs
));
3038 processor
.importStylesheet(xsl
);
3039 rs
= processor
.transformToFragment(xml
, document
);
3040 callback
.call(null, $("<div />").append(rs
).html());
3047 'nest' : '<' + '?xml version="1.0" encoding="utf-8" ?>' +
3048 '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' +
3049 '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/html" />' +
3050 '<xsl:template match="/">' +
3051 ' <xsl:call-template name="nodes">' +
3052 ' <xsl:with-param name="node" select="/root" />' +
3053 ' </xsl:call-template>' +
3055 '<xsl:template name="nodes">' +
3056 ' <xsl:param name="node" />' +
3058 ' <xsl:for-each select="$node/item">' +
3059 ' <xsl:variable name="children" select="count(./item) > 0" />' +
3061 ' <xsl:attribute name="class">' +
3062 ' <xsl:if test="position() = last()">jstree-last </xsl:if>' +
3064 ' <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' +
3065 ' <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' +
3066 ' <xsl:otherwise>jstree-leaf </xsl:otherwise>' +
3068 ' <xsl:value-of select="@class" />' +
3069 ' </xsl:attribute>' +
3070 ' <xsl:for-each select="@*">' +
3071 ' <xsl:if test="name() != \'class\' and name() != \'state\' and name() != \'hasChildren\'">' +
3072 ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' +
3074 ' </xsl:for-each>' +
3075 ' <ins class="jstree-icon"><xsl:text> </xsl:text></ins>' +
3076 ' <xsl:for-each select="content/name">' +
3078 ' <xsl:attribute name="href">' +
3080 ' <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' +
3081 ' <xsl:otherwise>#</xsl:otherwise>' +
3083 ' </xsl:attribute>' +
3084 ' <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' +
3085 ' <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' +
3086 ' <xsl:for-each select="@*">' +
3087 ' <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' +
3088 ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' +
3090 ' </xsl:for-each>' +
3092 ' <xsl:attribute name="class">jstree-icon ' +
3093 ' <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' +
3094 ' </xsl:attribute>' +
3095 ' <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' +
3096 ' <xsl:text> </xsl:text>' +
3098 ' <xsl:copy-of select="./child::node()" />' +
3100 ' </xsl:for-each>' +
3101 ' <xsl:if test="$children or @hasChildren"><xsl:call-template name="nodes"><xsl:with-param name="node" select="current()" /></xsl:call-template></xsl:if>' +
3103 ' </xsl:for-each>' +
3106 '</xsl:stylesheet>',
3108 'flat' : '<' + '?xml version="1.0" encoding="utf-8" ?>' +
3109 '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' +
3110 '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/xml" />' +
3111 '<xsl:template match="/">' +
3113 ' <xsl:for-each select="//item[not(@parent_id) or @parent_id=0 or not(@parent_id = //item/@id)]">' + /* the last `or` may be removed */
3114 ' <xsl:call-template name="nodes">' +
3115 ' <xsl:with-param name="node" select="." />' +
3116 ' <xsl:with-param name="is_last" select="number(position() = last())" />' +
3117 ' </xsl:call-template>' +
3118 ' </xsl:for-each>' +
3121 '<xsl:template name="nodes">' +
3122 ' <xsl:param name="node" />' +
3123 ' <xsl:param name="is_last" />' +
3124 ' <xsl:variable name="children" select="count(//item[@parent_id=$node/attribute::id]) > 0" />' +
3126 ' <xsl:attribute name="class">' +
3127 ' <xsl:if test="$is_last = true()">jstree-last </xsl:if>' +
3129 ' <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' +
3130 ' <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' +
3131 ' <xsl:otherwise>jstree-leaf </xsl:otherwise>' +
3133 ' <xsl:value-of select="@class" />' +
3134 ' </xsl:attribute>' +
3135 ' <xsl:for-each select="@*">' +
3136 ' <xsl:if test="name() != \'parent_id\' and name() != \'hasChildren\' and name() != \'class\' and name() != \'state\'">' +
3137 ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' +
3139 ' </xsl:for-each>' +
3140 ' <ins class="jstree-icon"><xsl:text> </xsl:text></ins>' +
3141 ' <xsl:for-each select="content/name">' +
3143 ' <xsl:attribute name="href">' +
3145 ' <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' +
3146 ' <xsl:otherwise>#</xsl:otherwise>' +
3148 ' </xsl:attribute>' +
3149 ' <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' +
3150 ' <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' +
3151 ' <xsl:for-each select="@*">' +
3152 ' <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' +
3153 ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' +
3155 ' </xsl:for-each>' +
3157 ' <xsl:attribute name="class">jstree-icon ' +
3158 ' <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' +
3159 ' </xsl:attribute>' +
3160 ' <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' +
3161 ' <xsl:text> </xsl:text>' +
3163 ' <xsl:copy-of select="./child::node()" />' +
3165 ' </xsl:for-each>' +
3166 ' <xsl:if test="$children">' +
3168 ' <xsl:for-each select="//item[@parent_id=$node/attribute::id]">' +
3169 ' <xsl:call-template name="nodes">' +
3170 ' <xsl:with-param name="node" select="." />' +
3171 ' <xsl:with-param name="is_last" select="number(position() = last())" />' +
3172 ' </xsl:call-template>' +
3173 ' </xsl:for-each>' +
3180 escape_xml = function(string
) {
3183 .replace(/&/g
, '&')
3184 .replace(/</g
, '<')
3185 .replace(/>/g
, '>')
3186 .replace(/"/g, '"')
3187 .replace(/'/g, ''');
3189 $.jstree.plugin("xml_data
", {
3195 correct_state : true,
3196 get_skip_empty : false,
3197 get_include_preamble : true
3200 load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_xml(obj, function () { _this.__callback({ "obj
" : _this._get_node(obj) }); s_call.call(this); }, e_call); },
3201 _is_loaded : function (obj) {
3202 var s = this._get_settings().xml_data;
3203 obj = this._get_node(obj);
3204 return obj == -1 || !obj || (!s.ajax && !$.isFunction(s.data)) || obj.is(".jstree
-open
, .jstree
-leaf
") || obj.children("ul
").children("li
").size() > 0;
3206 load_node_xml : function (obj, s_call, e_call) {
3207 var s = this.get_settings().xml_data,
3208 error_func = function () {},
3209 success_func = function () {};
3211 obj = this._get_node(obj);
3212 if(obj && obj !== -1) {
3213 if(obj.data("jstree_is_loading
")) { return; }
3214 else { obj.data("jstree_is_loading
",true); }
3217 case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied
.";
3218 case ($.isFunction(s.data)):
3219 s.data.call(this, obj, $.proxy(function (d) {
3220 this.parse_xml(d, $.proxy(function (d) {
3222 d = d.replace(/ ?xmlns="[^"]*"/ig
, "");
3225 if(obj
=== -1 || !obj
) { this.get_container().children("ul").empty().append(d
.children()); }
3226 else { obj
.children("a.jstree-loading").removeClass("jstree-loading"); obj
.append(d
); obj
.removeData("jstree_is_loading"); }
3227 if(s
.clean_node
) { this.clean_node(obj
); }
3228 if(s_call
) { s_call
.call(this); }
3231 if(obj
&& obj
!== -1) {
3232 obj
.children("a.jstree-loading").removeClass("jstree-loading");
3233 obj
.removeData("jstree_is_loading");
3234 if(s
.correct_state
) {
3235 this.correct_state(obj
);
3236 if(s_call
) { s_call
.call(this); }
3240 if(s
.correct_state
) {
3241 this.get_container().children("ul").empty();
3242 if(s_call
) { s_call
.call(this); }
3250 case (!!s
.data
&& !s
.ajax
) || (!!s
.data
&& !!s
.ajax
&& (!obj
|| obj
=== -1)):
3251 if(!obj
|| obj
== -1) {
3252 this.parse_xml(s
.data
, $.proxy(function (d
) {
3254 d
= d
.replace(/ ?xmlns
="[^"]*"/ig, "");
3257 this.get_container().children("ul
").empty().append(d.children());
3258 if(s.clean_node) { this.clean_node(obj); }
3259 if(s_call) { s_call.call(this); }
3263 if(s.correct_state) {
3264 this.get_container().children("ul
").empty();
3265 if(s_call) { s_call.call(this); }
3271 case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
3272 error_func = function (x, t, e) {
3273 var ef = this.get_settings().xml_data.ajax.error;
3274 if(ef) { ef.call(this, x, t, e); }
3275 if(obj !== -1 && obj.length) {
3276 obj.children("a
.jstree
-loading
").removeClass("jstree
-loading
");
3277 obj.removeData("jstree_is_loading
");
3278 if(t === "success
" && s.correct_state) { this.correct_state(obj); }
3281 if(t === "success
" && s.correct_state) { this.get_container().children("ul
").empty(); }
3283 if(e_call) { e_call.call(this); }
3285 success_func = function (d, t, x) {
3287 var sf = this.get_settings().xml_data.ajax.success;
3288 if(sf) { d = sf.call(this,d,t,x) || d; }
3289 if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "")) {
3290 return error_func.call(this, x, t, "");
3292 this.parse_xml(d, $.proxy(function (d) {
3294 d = d.replace(/ ?xmlns="[^"]*"/ig
, "");
3297 if(obj
=== -1 || !obj
) { this.get_container().children("ul").empty().append(d
.children()); }
3298 else { obj
.children("a.jstree-loading").removeClass("jstree-loading"); obj
.append(d
); obj
.removeData("jstree_is_loading"); }
3299 if(s
.clean_node
) { this.clean_node(obj
); }
3300 if(s_call
) { s_call
.call(this); }
3303 if(obj
&& obj
!== -1) {
3304 obj
.children("a.jstree-loading").removeClass("jstree-loading");
3305 obj
.removeData("jstree_is_loading");
3306 if(s
.correct_state
) {
3307 this.correct_state(obj
);
3308 if(s_call
) { s_call
.call(this); }
3312 if(s
.correct_state
) {
3313 this.get_container().children("ul").empty();
3314 if(s_call
) { s_call
.call(this); }
3321 s
.ajax
.context
= this;
3322 s
.ajax
.error
= error_func
;
3323 s
.ajax
.success
= success_func
;
3324 if(!s
.ajax
.dataType
) { s
.ajax
.dataType
= "xml"; }
3325 if($.isFunction(s
.ajax
.url
)) { s
.ajax
.url
= s
.ajax
.url
.call(this, obj
); }
3326 if($.isFunction(s
.ajax
.data
)) { s
.ajax
.data
= s
.ajax
.data
.call(this, obj
); }
3331 parse_xml : function (xml
, callback
) {
3332 var s
= this._get_settings().xml_data
;
3333 $.vakata
.xslt(xml
, xsl
[s
.xsl
], callback
);
3335 get_xml : function (tp
, obj
, li_attr
, a_attr
, is_callback
) {
3337 s
= this._get_settings(),
3339 tmp1
, tmp2
, li
, a
, lang
;
3340 if(!tp
) { tp
= "flat"; }
3341 if(!is_callback
) { is_callback
= 0; }
3342 obj
= this._get_node(obj
);
3343 if(!obj
|| obj
=== -1) { obj
= this.get_container().find("> ul > li"); }
3344 li_attr
= $.isArray(li_attr
) ? li_attr
: [ "id", "class" ];
3345 if(!is_callback
&& this.data
.types
&& $.inArray(s
.types
.type_attr
, li_attr
) === -1) { li_attr
.push(s
.types
.type_attr
); }
3347 a_attr
= $.isArray(a_attr
) ? a_attr
: [ ];
3350 if(s
.xml_data
.get_include_preamble
) {
3351 result
+= '<' + '?xml version="1.0" encoding="UTF-8"?' + '>';
3355 obj
.each(function () {
3358 $.each(li_attr
, function (i
, v
) {
3360 if(!s
.xml_data
.get_skip_empty
|| typeof t
!== "undefined") {
3361 result
+= " " + v
+ "=\"" + escape_xml((" " + (t
|| "")).replace(/ jstree
[^ ]*/ig
,'').replace(/\s
+$/ig," ").replace(/^ /,"").replace(/ $/,"")) + "\"";
3364 if(li
.hasClass("jstree-open")) { result
+= " state=\"open\""; }
3365 if(li
.hasClass("jstree-closed")) { result
+= " state=\"closed\""; }
3366 if(tp
=== "flat") { result
+= " parent_id=\"" + escape_xml(is_callback
) + "\""; }
3368 result
+= "<content>";
3369 a
= li
.children("a");
3370 a
.each(function () {
3374 if($.inArray("languages", s
.plugins
) !== -1) {
3375 $.each(s
.languages
, function (k
, z
) {
3376 if(tmp1
.hasClass(z
)) { result
+= " lang=\"" + escape_xml(z
) + "\""; lang
= z
; return false; }
3380 $.each(a_attr
, function (k
, z
) {
3381 var t
= tmp1
.attr(z
);
3382 if(!s
.xml_data
.get_skip_empty
|| typeof t
!== "undefined") {
3383 result
+= " " + z
+ "=\"" + escape_xml((" " + t
|| "").replace(/ jstree
[^ ]*/ig
,'').replace(/\s
+$/ig," ").replace(/^ /,"").replace(/ $/,"")) + "\"";
3387 if(tmp1
.children("ins").get(0).className
.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length
) {
3388 result
+= ' icon="' + escape_xml(tmp1
.children("ins").get(0).className
.replace(/jstree[^ ]*|$/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"")) + '"';
3390 if(tmp1
.children("ins").get(0).style
.backgroundImage
.length
) {
3391 result
+= ' icon="' + escape_xml(tmp1
.children("ins").get(0).style
.backgroundImage
.replace("url(","").replace(")","").replace(/'/ig,"").replace(/"/ig,"")) + '"';
3394 result += "<![CDATA[" + _this.get_text(tmp1, lang) + "]]>";
3395 result += "</name>";
3397 result += "</content>";
3398 tmp2 = li[0].id || true;
3399 li = li.find("> ul > li");
3400 if(li.length) { tmp2 = _this.get_xml(tp, li, li_attr, a_attr, tmp2); }
3402 if(tp == "nest") { result += tmp2; }
3403 result += "</item>";
3404 if(tp == "flat") { result += tmp2; }
3406 if(!is_callback) { result += "</root>"; }
3415 * jsTree search plugin
3416 * Enables both sync and async search on the tree
3417 * DOES NOT WORK WITH JSON PROGRESSIVE RENDER
3420 $.expr[':'].jstree_contains = function(a,i,m){
3421 return (a.textContent || a.innerText || "").toLowerCase().indexOf(m[3].toLowerCase())>=0;
3423 $.expr[':'].jstree_title_contains = function(a,i,m) {
3424 return (a.getAttribute("title") || "").toLowerCase().indexOf(m[3].toLowerCase())>=0;
3426 $.jstree.plugin("search", {
3427 __init : function () {
3428 this.data.search.str = "";
3429 this.data.search.result = $();
3430 if(this._get_settings().search.show_only_matches) {
3431 this.get_container()
3432 .bind("search.jstree", function (e, data) {
3433 $(this).children("ul").find("li").hide().removeClass("jstree-last");
3434 data.rslt.nodes.parentsUntil(".jstree").andSelf().show()
3435 .filter("ul").each(function () { $(this).children("li:visible").eq(-1).addClass("jstree-last"); });
3437 .bind("clear_search.jstree", function () {
3438 $(this).children("ul").find("li").css("display","").end().end().jstree("clean_node", -1);
3444 search_method : "jstree_contains", // for case insensitive - jstree_contains
3445 show_only_matches : false
3448 search : function (str, skip_async) {
3449 if($.trim(str) === "") { this.clear_search(); return; }
3450 var s = this.get_settings().search,
3452 error_func = function () { },
3453 success_func = function () { };
3454 this.data.search.str = str;
3456 if(!skip_async && s.ajax !== false && this.get_container_ul().find("li.jstree-closed:not(:has(ul)):eq(0)").length > 0) {
3457 this.search.supress_callback = true;
3458 error_func = function () { };
3459 success_func = function (d, t, x) {
3460 var sf = this.get_settings().search.ajax.success;
3461 if(sf) { d = sf.call(this,d,t,x) || d; }
3462 this.data.search.to_open = d;
3463 this._search_open();
3465 s.ajax.context = this;
3466 s.ajax.error = error_func;
3467 s.ajax.success = success_func;
3468 if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, str); }
3469 if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, str); }
3470 if(!s.ajax.data) { s.ajax.data = { "search_string" : str }; }
3471 if(!s.ajax.dataType || /^json/.exec(s.ajax.dataType)) { s.ajax.dataType = "json"; }
3475 if(this.data.search.result.length) { this.clear_search(); }
3476 this.data.search.result = this.get_container().find("a" + (this.data.languages ? "." + this.get_lang() : "" ) + ":" + (s.search_method) + "(" + this.data.search.str + ")");
3477 this.data.search.result.addClass("jstree-search").parent().parents(".jstree-closed").each(function () {
3478 t.open_node(this, false, true);
3480 this.__callback({ nodes : this.data.search.result, str : str });
3482 clear_search : function (str) {
3483 this.data.search.result.removeClass("jstree-search");
3484 this.__callback(this.data.search.result);
3485 this.data.search.result = $();
3487 _search_open : function (is_callback) {
3492 if(this.data.search.to_open.length) {
3493 $.each(this.data.search.to_open, function (i, val) {
3494 if(val == "#") { return true; }
3495 if($(val).length && $(val).is(".jstree-closed")) { current.push(val); }
3496 else { remaining.push(val); }
3498 if(current.length) {
3499 this.data.search.to_open = remaining;
3500 $.each(current, function (i, val) {
3501 _this.open_node(val, function () { _this._search_open(true); });
3506 if(done) { this.search(this.data.search.str, true); }
3514 * jsTree contextmenu plugin
3517 $.vakata.context = {
3518 hide_on_mouseleave : false,
3520 cnt : $("<div id='vakata
-contextmenu
' />"),
3527 show : function (s, t, x, y, d, p, rtl) {
3528 $.vakata.context.rtl = !!rtl;
3529 var html = $.vakata.context.parse(s), h, w;
3530 if(!html) { return; }
3531 $.vakata.context.vis = true;
3532 $.vakata.context.tgt = t;
3533 $.vakata.context.par = p || t || null;
3534 $.vakata.context.data = d || null;
3535 $.vakata.context.cnt
3537 .css({ "visibility" : "hidden", "display" : "block", "left" : 0, "top" : 0 });
3539 if($.vakata.context.hide_on_mouseleave) {
3540 $.vakata.context.cnt
3541 .one("mouseleave", function(e) { $.vakata.context.hide(); });
3544 h = $.vakata.context.cnt.height();
3545 w = $.vakata.context.cnt.width();
3546 if(x + w > $(document).width()) {
3547 x = $(document).width() - (w + 5);
3548 $.vakata.context.cnt.find("li > ul").addClass("right");
3550 if(y + h > $(document).height()) {
3551 y = y - (h + t[0].offsetHeight);
3552 $.vakata.context.cnt.find("li > ul").addClass("bottom");
3555 $.vakata.context.cnt
3556 .css({ "left" : x, "top" : y })
3558 .bind("mouseenter", function (e) {
3559 var w = $(document).width(),
3560 h = $(document).height(),
3561 ul = $(this).children("ul").show();
3562 if(w !== $(document).width()) { ul.toggleClass("right"); }
3563 if(h !== $(document).height()) { ul.toggleClass("bottom"); }
3565 .bind("mouseleave", function (e) {
3566 $(this).children("ul").hide();
3569 .css({ "visibility" : "visible" })
3571 $(document).triggerHandler("context_show.vakata");
3573 hide : function () {
3574 $.vakata.context.vis = false;
3575 $.vakata.context.cnt.attr("class","").css({ "visibility" : "hidden" });
3576 $(document).triggerHandler("context_hide.vakata");
3578 parse : function (s, is_callback) {
3579 if(!s) { return false; }
3583 if(!is_callback) { $.vakata.context.func = {}; }
3585 $.each(s, function (i, val) {
3586 if(!val) { return true; }
3587 $.vakata.context.func[i] = val.action;
3588 if(!was_sep && val.separator_before) {
3589 str += "<li class='vakata
-separator vakata
-separator
-before
'></li>";
3592 str += "<li class='" + (val._class || "") + (val._disabled ? " jstree
-contextmenu
-disabled
" : "") + "'><ins ";
3593 if(val.icon && val.icon.indexOf("/") === -1) { str += " class='" + val.icon + "' "; }
3594 if(val.icon && val.icon.indexOf("/") !== -1) { str += " style='background
:url(" + val.icon + ") center center no
-repeat
;' "; }
3595 str += "> </ins><a href='#' rel='" + i + "'>";
3597 str += "<span style='float:" + ($.vakata.context.rtl ? "left
" : "right
") + ";'>»</span>";
3599 str += val.label + "</a>";
3601 tmp = $.vakata.context.parse(val.submenu, true);
3602 if(tmp) { str += tmp; }
3605 if(val.separator_after) {
3606 str += "<li class='vakata
-separator vakata
-separator
-after
'></li>";
3610 str = str.replace(/<li class\='vakata
-separator vakata
-separator
-after
'\><\/li\>$/,"");
3612 $(document).triggerHandler("context_parse.vakata");
3613 return str.length > 10 ? str : false;
3615 exec : function (i) {
3616 if($.isFunction($.vakata.context.func[i])) {
3617 // if is string - eval and call it!
3618 $.vakata.context.func[i].call($.vakata.context.data, $.vakata.context.par);
3621 else { return false; }
3625 var css_string = '' +
3626 '#vakata
-contextmenu
{ display
:block
; visibility
:hidden
; left
:0; top
:-200px
; position
:absolute
; margin
:0; padding
:0; min
-width
:180px
; background
:#ebebeb
; border
:1px solid silver
; z
-index
:10000; *width
:180px
; } ' +
3627 '#vakata
-contextmenu ul
{ min
-width
:180px
; *width
:180px
; } ' +
3628 '#vakata
-contextmenu ul
, #vakata
-contextmenu li
{ margin
:0; padding
:0; list
-style
-type
:none
; display
:block
; } ' +
3629 '#vakata
-contextmenu li
{ line
-height
:20px
; min
-height
:20px
; position
:relative
; padding
:0px
; } ' +
3630 '#vakata
-contextmenu li a
{ padding
:1px
6px
; line
-height
:17px
; display
:block
; text
-decoration
:none
; margin
:1px
1px
0 1px
; } ' +
3631 '#vakata
-contextmenu li ins
{ float:left
; width
:16px
; height
:16px
; text
-decoration
:none
; margin
-right
:2px
; } ' +
3632 '#vakata
-contextmenu li a
:hover
, #vakata
-contextmenu li
.vakata
-hover
> a
{ background
:gray
; color
:white
; } ' +
3633 '#vakata
-contextmenu li ul
{ display
:none
; position
:absolute
; top
:-2px
; left
:100%; background
:#ebebeb
; border
:1px solid gray
; } ' +
3634 '#vakata
-contextmenu
.right
{ right
:100%; left
:auto
; } ' +
3635 '#vakata
-contextmenu
.bottom
{ bottom
:-1px
; top
:auto
; } ' +
3636 '#vakata
-contextmenu li
.vakata
-separator
{ min
-height
:0; height
:1px
; line
-height
:1px
; font
-size
:1px
; overflow
:hidden
; margin
:0 2px
; background
:silver
; /* border-top:1px solid #fefefe; */ padding
:0; } ';
3637 $.vakata.css.add_sheet({ str : css_string, title : "vakata" });
3638 $.vakata.context.cnt
3639 .delegate("a","click", function (e) { e.preventDefault(); })
3640 .delegate("a","mouseup", function (e) {
3641 if(!$(this).parent().hasClass("jstree-contextmenu-disabled") && $.vakata.context.exec($(this).attr("rel"))) {
3642 $.vakata.context.hide();
3644 else { $(this).blur(); }
3646 .delegate("a","mouseover", function () {
3647 $.vakata.context.cnt.find(".vakata-hover").removeClass("vakata-hover");
3650 $(document).bind("mousedown", function (e) { if($.vakata.context.vis && !$.contains($.vakata.context.cnt[0], e.target)) { $.vakata.context.hide(); } });
3651 if(typeof $.hotkeys !== "undefined") {
3653 .bind("keydown", "up", function (e) {
3654 if($.vakata.context.vis) {
3655 var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first();
3656 if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last(); }
3657 o.addClass("vakata-hover");
3658 e.stopImmediatePropagation();
3662 .bind("keydown", "down", function (e) {
3663 if($.vakata.context.vis) {
3664 var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first();
3665 if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first(); }
3666 o.addClass("vakata-hover");
3667 e.stopImmediatePropagation();
3671 .bind("keydown", "right", function (e) {
3672 if($.vakata.context.vis) {
3673 $.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover");
3674 e.stopImmediatePropagation();
3678 .bind("keydown", "left", function (e) {
3679 if($.vakata.context.vis) {
3680 $.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover");
3681 e.stopImmediatePropagation();
3685 .bind("keydown", "esc", function (e) {
3686 $.vakata.context.hide();
3689 .bind("keydown", "space", function (e) {
3690 $.vakata.context.cnt.find(".vakata-hover").last().children("a").click();
3696 $.jstree.plugin("contextmenu", {
3697 __init : function () {
3698 this.get_container()
3699 .delegate("a", "contextmenu.jstree", $.proxy(function (e) {
3701 if(!$(e.currentTarget).hasClass("jstree-loading")) {
3702 this.show_contextmenu(e.currentTarget, e.pageX, e.pageY);
3705 .delegate("a", "click.jstree", $.proxy(function (e) {
3706 if(this.data.contextmenu) {
3707 $.vakata.context.hide();
3710 .bind("destroy.jstree", $.proxy(function () {
3711 // TODO: move this to descruct method
3712 if(this.data.contextmenu) {
3713 $.vakata.context.hide();
3716 $(document).bind("context_hide.vakata", $.proxy(function () { this.data.contextmenu = false; }, this));
3719 select_node : false, // requires UI plugin
3720 show_at_node : true,
3721 items : { // Could be a function that should return an object like this one
3723 "separator_before" : false,
3724 "separator_after" : true,
3726 "action" : function (obj) { this.create(obj); }
3729 "separator_before" : false,
3730 "separator_after" : false,
3732 "action" : function (obj) { this.rename(obj); }
3735 "separator_before" : false,
3737 "separator_after" : false,
3739 "action" : function (obj) { if(this.is_selected(obj)) { this.remove(); } else { this.remove(obj); } }
3742 "separator_before" : true,
3744 "separator_after" : false,
3749 "separator_before" : false,
3750 "separator_after" : false,
3752 "action" : function (obj) { this.cut(obj); }
3755 "separator_before" : false,
3757 "separator_after" : false,
3759 "action" : function (obj) { this.copy(obj); }
3762 "separator_before" : false,
3764 "separator_after" : false,
3766 "action" : function (obj) { this.paste(obj); }
3773 show_contextmenu : function (obj, x, y) {
3774 obj = this._get_node(obj);
3775 var s = this.get_settings().contextmenu,
3776 a = obj.children("a:visible:eq(0)"),
3779 if(s.select_node && this.data.ui && !this.is_selected(obj)) {
3780 this.deselect_all();
3781 this.select_node(obj, true);
3783 if(s.show_at_node || typeof x === "undefined" || typeof y === "undefined") {
3786 y = o.top + this.data.core.li_height;
3788 i = obj.data("jstree") && obj.data("jstree").contextmenu ? obj.data("jstree").contextmenu : s.items;
3789 if($.isFunction(i)) { i = i.call(this, obj); }
3790 this.data.contextmenu = true;
3791 $.vakata.context.show(i, a, x, y, this, obj, this._get_settings().core.rtl);
3792 if(this.data.themes) { $.vakata.context.cnt.attr("class", "jstree-" + this.data.themes.theme + "-context"); }
3800 * jsTree types plugin
3801 * Adds support types of nodes
3802 * You can set an attribute on each li node, that represents its type.
3803 * According to the type setting the node may get custom icon/validation rules
3806 $.jstree.plugin("types", {
3807 __init : function () {
3808 var s = this._get_settings().types;
3809 this.data.types.attach_to = [];
3810 this.get_container()
3811 .bind("init.jstree", $.proxy(function () {
3812 var types = s.types,
3817 $.each(types, function (i, tp) {
3818 $.each(tp, function (k, v) {
3819 if(!/^(max_depth|max_children|icon|valid_children)$/.test(k)) { _this.data.types.attach_to.push(k); }
3821 if(!tp.icon) { return true; }
3822 if( tp.icon.image || tp.icon.position) {
3823 if(i == "default") { icons_css += '.jstree
-' + _this.get_index() + ' a
> .jstree
-icon
{ '; }
3824 else { icons_css += '.jstree
-' + _this.get_index() + ' li
[' + attr + '="' + i + '"] > a
> .jstree
-icon
{ '; }
3825 if(tp.icon.image) { icons_css += ' background
-image
:url(' + tp.icon.image + '); '; }
3826 if(tp.icon.position){ icons_css += ' background
-position
:' + tp.icon.position + '; '; }
3827 else { icons_css += ' background
-position
:0 0; '; }
3831 if(icons_css !== "") { $.vakata.css.add_sheet({ 'str
' : icons_css, title : "jstree-types" }); }
3833 .bind("before.jstree", $.proxy(function (e, data) {
3835 o = this._get_settings().types.use_data ? this._get_node(data.args[0]) : false,
3836 d = o && o !== -1 && o.length ? o.data("jstree") : false;
3837 if(d && d.types && d.types[data.func] === false) { e.stopImmediatePropagation(); return false; }
3838 if($.inArray(data.func, this.data.types.attach_to) !== -1) {
3839 if(!data.args[0] || (!data.args[0].tagName && !data.args[0].jquery)) { return; }
3840 s = this._get_settings().types.types;
3841 t = this._get_type(data.args[0]);
3844 (s[t] && typeof s[t][data.func] !== "undefined") ||
3845 (s["default"] && typeof s["default"][data.func] !== "undefined")
3846 ) && this._check(data.func, data.args[0]) === false
3848 e.stopImmediatePropagation();
3854 this.get_container()
3855 .bind("load_node.jstree set_type.jstree", $.proxy(function (e, data) {
3856 var r = data && data.rslt && data.rslt.obj && data.rslt.obj !== -1 ? this._get_node(data.rslt.obj).parent() : this.get_container_ul(),
3858 s = this._get_settings().types;
3859 $.each(s.types, function (i, tp) {
3860 if(tp.icon && (tp.icon.image || tp.icon.position)) {
3861 c = i === "default" ? r.find("li > a > .jstree-icon") : r.find("li[" + s.type_attr + "='" + i + "'] > a > .jstree-icon");
3862 if(tp.icon.image) { c.css("backgroundImage","url(" + tp.icon.image + ")"); }
3863 c.css("backgroundPosition", tp.icon.position || "0 0");
3870 // defines maximum number of root nodes (-1 means unlimited, -2 means disable max_children checking)
3872 // defines the maximum depth of the tree (-1 means unlimited, -2 means disable max_depth checking)
3874 // defines valid node types for the root nodes
3875 valid_children : "all",
3877 // whether to use $.data
3879 // where is the type stores (the rel attribute of the LI element)
3885 "max_children" : -1,
3887 "valid_children": "all"
3889 // Bound functions - you can bind any other function here (using boolean or function)
3890 //"select_node" : true
3895 _types_notify : function (n, data) {
3896 if(data.type && this._get_settings().types.use_data) {
3897 this.set_type(data.type, n);
3900 _get_type : function (obj) {
3901 obj = this._get_node(obj);
3902 return (!obj || !obj.length) ? false : obj.attr(this._get_settings().types.type_attr) || "default";
3904 set_type : function (str, obj) {
3905 obj = this._get_node(obj);
3906 var ret = (!obj.length || !str) ? false : obj.attr(this._get_settings().types.type_attr, str);
3907 if(ret) { this.__callback({ obj : obj, type : str}); }
3910 _check : function (rule, obj, opts) {
3911 obj = this._get_node(obj);
3912 var v = false, t = this._get_type(obj), d = 0, _this = this, s = this._get_settings().types, data = false;
3914 if(!!s[rule]) { v = s[rule]; }
3918 if(t === false) { return; }
3919 data = s.use_data ? obj.data("jstree") : false;
3920 if(data && data.types && typeof data.types[rule] !== "undefined") { v = data.types[rule]; }
3921 else if(!!s.types[t] && typeof s.types[t][rule] !== "undefined") { v = s.types[t][rule]; }
3922 else if(!!s.types["default"] && typeof s.types["default"][rule] !== "undefined") { v = s.types["default"][rule]; }
3924 if($.isFunction(v)) { v = v.call(this, obj); }
3925 if(rule === "max_depth" && obj !== -1 && opts !== false && s.max_depth !== -2 && v !== 0) {
3926 // also include the node itself - otherwise if root node it is not checked
3927 obj.children("a:eq(0)").parentsUntil(".jstree","li").each(function (i) {
3928 // check if current depth already exceeds global tree depth
3929 if(s.max_depth !== -1 && s.max_depth - (i + 1) <= 0) { v = 0; return false; }
3930 d = (i === 0) ? v : _this._check(rule, this, false);
3931 // check if current node max depth is already matched or exceeded
3932 if(d !== -1 && d - (i + 1) <= 0) { v = 0; return false; }
3933 // otherwise - set the max depth to the current value minus current depth
3934 if(d >= 0 && (d - (i + 1) < v || v < 0) ) { v = d - (i + 1); }
3935 // if the global tree depth exists and it minus the nodes calculated so far is less than `v` or `v` is unlimited
3936 if(s.max_depth >= 0 && (s.max_depth - (i + 1) < v || v < 0) ) { v = s.max_depth - (i + 1); }
3941 check_move : function () {
3942 if(!this.__call_old()) { return false; }
3943 var m = this._get_move(),
3944 s = m.rt._get_settings().types,
3945 mc = m.rt._check("max_children", m.cr),
3946 md = m.rt._check("max_depth", m.cr),
3947 vc = m.rt._check("valid_children", m.cr),
3950 if(vc === "none") { return false; }
3951 if($.isArray(vc) && m.ot && m.ot._get_type) {
3952 m.o.each(function () {
3953 if($.inArray(m.ot._get_type(this), vc) === -1) { d = false; return false; }
3955 if(d === false) { return false; }
3957 if(s.max_children !== -2 && mc !== -1) {
3958 ch = m.cr === -1 ? this.get_container().find("> ul > li").not(m.o).length : m.cr.find("> ul > li").not(m.o).length;
3959 if(ch + m.o.length > mc) { return false; }
3961 if(s.max_depth !== -2 && md !== -1) {
3963 if(md === 0) { return false; }
3964 if(typeof m.o.d === "undefined") {
3965 // TODO: deal with progressive rendering and async when checking max_depth (how to know the depth of the moved node)
3967 while(t.length > 0) {
3968 t = t.find("> ul > li");
3973 if(md - m.o.d < 0) { return false; }
3977 create_node : function (obj, position, js, callback, is_loaded, skip_check) {
3978 if(!skip_check && (is_loaded || this._is_loaded(obj))) {
3979 var p = (typeof position == "string" && position.match(/^before|after$/i) && obj !== -1) ? this._get_parent(obj) : this._get_node(obj),
3980 s = this._get_settings().types,
3981 mc = this._check("max_children", p),
3982 md = this._check("max_depth", p),
3983 vc = this._check("valid_children", p),
3985 if(typeof js === "string") { js = { data : js }; }
3986 if(!js) { js = {}; }
3987 if(vc === "none") { return false; }
3989 if(!js.attr || !js.attr[s.type_attr]) {
3990 if(!js.attr) { js.attr = {}; }
3991 js.attr[s.type_attr] = vc[0];
3994 if($.inArray(js.attr[s.type_attr], vc) === -1) { return false; }
3997 if(s.max_children !== -2 && mc !== -1) {
3998 ch = p === -1 ? this.get_container().find("> ul > li").length : p.find("> ul > li").length;
3999 if(ch + 1 > mc) { return false; }
4001 if(s.max_depth !== -2 && md !== -1 && (md - 1) < 0) { return false; }
4003 return this.__call_old(true, obj, position, js, callback, is_loaded, skip_check);
4011 * jsTree HTML plugin
4012 * The HTML data store. Datastores are build by replacing the `load_node` and `_is_loaded` functions.
4015 $.jstree.plugin("html_data", {
4016 __init : function () {
4017 // this used to use html() and clean the whitespace, but this way any attached data was lost
4018 this.data.html_data.original_container_html = this.get_container().find(" > ul > li").clone(true);
4019 // remove white space from LI node - otherwise nodes appear a bit to the right
4020 this.data.html_data.original_container_html.find("li").andSelf().contents().filter(function() { return this.nodeType == 3; }).remove();
4025 correct_state : true
4028 load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_html(obj, function () { _this.__callback({ "obj" : _this._get_node(obj) }); s_call.call(this); }, e_call); },
4029 _is_loaded : function (obj) {
4030 obj = this._get_node(obj);
4031 return obj == -1 || !obj || (!this._get_settings().html_data.ajax && !$.isFunction(this._get_settings().html_data.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0;
4033 load_node_html : function (obj, s_call, e_call) {
4035 s = this.get_settings().html_data,
4036 error_func = function () {},
4037 success_func = function () {};
4038 obj = this._get_node(obj);
4039 if(obj && obj !== -1) {
4040 if(obj.data("jstree_is_loading")) { return; }
4041 else { obj.data("jstree_is_loading",true); }
4044 case ($.isFunction(s.data)):
4045 s.data.call(this, obj, $.proxy(function (d) {
4046 if(d && d !== "" && d.toString && d.toString().replace(/^[\s\n]+$/,"") !== "") {
4048 if(!d.is("ul")) { d = $("<ul />").append(d); }
4049 if(obj == -1 || !obj) { this.get_container().children("ul").empty().append(d.children()).find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree
-icon
'> </ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); }
4050 else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.append(d).children("ul").find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree
-icon
'> </ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); obj.removeData("jstree_is_loading"); }
4051 this.clean_node(obj);
4052 if(s_call) { s_call.call(this); }
4055 if(obj && obj !== -1) {
4056 obj.children("a.jstree-loading").removeClass("jstree-loading");
4057 obj.removeData("jstree_is_loading");
4058 if(s.correct_state) {
4059 this.correct_state(obj);
4060 if(s_call) { s_call.call(this); }
4064 if(s.correct_state) {
4065 this.get_container().children("ul").empty();
4066 if(s_call) { s_call.call(this); }
4072 case (!s.data && !s.ajax):
4073 if(!obj || obj == -1) {
4074 this.get_container()
4075 .children("ul").empty()
4076 .append(this.data.html_data.original_container_html)
4077 .find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree
-icon
'> </ins>").end()
4078 .filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");
4081 if(s_call) { s_call.call(this); }
4083 case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
4084 if(!obj || obj == -1) {
4086 if(!d.is("ul")) { d = $("<ul />").append(d); }
4087 this.get_container()
4088 .children("ul").empty().append(d.children())
4089 .find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree
-icon
'> </ins>").end()
4090 .filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");
4093 if(s_call) { s_call.call(this); }
4095 case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
4096 obj = this._get_node(obj);
4097 error_func = function (x, t, e) {
4098 var ef = this.get_settings().html_data.ajax.error;
4099 if(ef) { ef.call(this, x, t, e); }
4100 if(obj != -1 && obj.length) {
4101 obj.children("a.jstree-loading").removeClass("jstree-loading");
4102 obj.removeData("jstree_is_loading");
4103 if(t === "success" && s.correct_state) { this.correct_state(obj); }
4106 if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); }
4108 if(e_call) { e_call.call(this); }
4110 success_func = function (d, t, x) {
4111 var sf = this.get_settings().html_data.ajax.success;
4112 if(sf) { d = sf.call(this,d,t,x) || d; }
4113 if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "")) {
4114 return error_func.call(this, x, t, "");
4118 if(!d.is("ul")) { d = $("<ul />").append(d); }
4119 if(obj == -1 || !obj) { this.get_container().children("ul").empty().append(d.children()).find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree
-icon
'> </ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); }
4120 else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.append(d).children("ul").find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree
-icon
'> </ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); obj.removeData("jstree_is_loading"); }
4121 this.clean_node(obj);
4122 if(s_call) { s_call.call(this); }
4125 if(obj && obj !== -1) {
4126 obj.children("a.jstree-loading").removeClass("jstree-loading");
4127 obj.removeData("jstree_is_loading");
4128 if(s.correct_state) {
4129 this.correct_state(obj);
4130 if(s_call) { s_call.call(this); }
4134 if(s.correct_state) {
4135 this.get_container().children("ul").empty();
4136 if(s_call) { s_call.call(this); }
4141 s.ajax.context = this;
4142 s.ajax.error = error_func;
4143 s.ajax.success = success_func;
4144 if(!s.ajax.dataType) { s.ajax.dataType = "html"; }
4145 if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); }
4146 if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
4153 // include the HTML data plugin by default
4154 $.jstree.defaults.plugins.push("html_data");
4159 * jsTree themeroller plugin
4160 * Adds support for jQuery UI themes. Include this at the end of your plugins list, also make sure "themes" is not included.
4163 $.jstree.plugin("themeroller", {
4164 __init : function () {
4165 var s = this._get_settings().themeroller;
4166 this.get_container()
4167 .addClass("ui-widget-content")
4168 .addClass("jstree-themeroller")
4169 .delegate("a","mouseenter.jstree", function (e) {
4170 if(!$(e.currentTarget).hasClass("jstree-loading")) {
4171 $(this).addClass(s.item_h);
4174 .delegate("a","mouseleave.jstree", function () {
4175 $(this).removeClass(s.item_h);
4177 .bind("init.jstree", $.proxy(function (e, data) {
4178 data.inst.get_container().find("> ul > li > .jstree-loading > ins").addClass("ui-icon-refresh");
4179 this._themeroller(data.inst.get_container().find("> ul > li"));
4181 .bind("open_node.jstree create_node.jstree", $.proxy(function (e, data) {
4182 this._themeroller(data.rslt.obj);
4184 .bind("loaded.jstree refresh.jstree", $.proxy(function (e) {
4185 this._themeroller();
4187 .bind("close_node.jstree", $.proxy(function (e, data) {
4188 this._themeroller(data.rslt.obj);
4190 .bind("delete_node.jstree", $.proxy(function (e, data) {
4191 this._themeroller(data.rslt.parent);
4193 .bind("correct_state.jstree", $.proxy(function (e, data) {
4195 .children("ins.jstree-icon").removeClass(s.opened + " " + s.closed + " ui-icon").end()
4196 .find("> a > ins.ui-icon")
4197 .filter(function() {
4198 return this.className.toString()
4199 .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"")
4200 .indexOf("ui-icon-") === -1;
4201 }).removeClass(s.item_open + " " + s.item_clsd).addClass(s.item_leaf || "jstree-no-icon");
4203 .bind("select_node.jstree", $.proxy(function (e, data) {
4204 data.rslt.obj.children("a").addClass(s.item_a);
4206 .bind("deselect_node.jstree deselect_all.jstree", $.proxy(function (e, data) {
4207 this.get_container()
4208 .find("a." + s.item_a).removeClass(s.item_a).end()
4209 .find("a.jstree-clicked").addClass(s.item_a);
4211 .bind("dehover_node.jstree", $.proxy(function (e, data) {
4212 data.rslt.obj.children("a").removeClass(s.item_h);
4214 .bind("hover_node.jstree", $.proxy(function (e, data) {
4215 this.get_container()
4216 .find("a." + s.item_h).not(data.rslt.obj).removeClass(s.item_h);
4217 data.rslt.obj.children("a").addClass(s.item_h);
4219 .bind("move_node.jstree", $.proxy(function (e, data) {
4220 this._themeroller(data.rslt.o);
4221 this._themeroller(data.rslt.op);
4224 __destroy : function () {
4225 var s = this._get_settings().themeroller,
4227 $.each(s, function (i, v) {
4229 if(v.length) { c = c.concat(v); }
4231 this.get_container()
4232 .removeClass("ui-widget-content")
4233 .find("." + c.join(", .")).removeClass(c.join(" "));
4236 _themeroller : function (obj) {
4237 var s = this._get_settings().themeroller;
4238 obj = !obj || obj == -1 ? this.get_container_ul() : this._get_node(obj).parent();
4240 .find("li.jstree-closed")
4241 .children("ins.jstree-icon").removeClass(s.opened).addClass("ui-icon " + s.closed).end()
4242 .children("a").addClass(s.item)
4243 .children("ins.jstree-icon").addClass("ui-icon")
4244 .filter(function() {
4245 return this.className.toString()
4246 .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"")
4247 .indexOf("ui-icon-") === -1;
4248 }).removeClass(s.item_leaf + " " + s.item_open).addClass(s.item_clsd || "jstree-no-icon")
4253 .find("li.jstree-open")
4254 .children("ins.jstree-icon").removeClass(s.closed).addClass("ui-icon " + s.opened).end()
4255 .children("a").addClass(s.item)
4256 .children("ins.jstree-icon").addClass("ui-icon")
4257 .filter(function() {
4258 return this.className.toString()
4259 .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"")
4260 .indexOf("ui-icon-") === -1;
4261 }).removeClass(s.item_leaf + " " + s.item_clsd).addClass(s.item_open || "jstree-no-icon")
4266 .find("li.jstree-leaf")
4267 .children("ins.jstree-icon").removeClass(s.closed + " ui-icon " + s.opened).end()
4268 .children("a").addClass(s.item)
4269 .children("ins.jstree-icon").addClass("ui-icon")
4270 .filter(function() {
4271 return this.className.toString()
4272 .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"")
4273 .indexOf("ui-icon-") === -1;
4274 }).removeClass(s.item_clsd + " " + s.item_open).addClass(s.item_leaf || "jstree-no-icon");
4278 "opened" : "ui-icon-triangle-1-se",
4279 "closed" : "ui-icon-triangle-1-e",
4280 "item" : "ui-state-default",
4281 "item_h" : "ui-state-hover",
4282 "item_a" : "ui-state-active",
4283 "item_open" : "ui-icon-folder-open",
4284 "item_clsd" : "ui-icon-folder-collapsed",
4285 "item_leaf" : "ui-icon-document"
4289 var css_string = '' +
4290 '.jstree
-themeroller
.ui
-icon
{ overflow
:visible
; } ' +
4291 '.jstree
-themeroller a
{ padding
:0 2px
; } ' +
4292 '.jstree
-themeroller
.jstree
-no
-icon
{ display
:none
; }';
4293 $.vakata.css.add_sheet({ str : css_string, title : "jstree" });
4299 * jsTree unique plugin
4300 * Forces different names amongst siblings (still a bit experimental)
4301 * NOTE: does not check language versions (it will not be possible to have nodes with the same title, even in different languages)
4304 $.jstree.plugin("unique", {
4305 __init : function () {
4306 this.get_container()
4307 .bind("before.jstree", $.proxy(function (e, data) {
4308 var nms = [], res = true, p, t;
4309 if(data.func == "move_node") {
4310 // obj, ref, position, is_copy, is_prepared, skip_check
4311 if(data.args[4] === true) {
4312 if(data.args[0].o && data.args[0].o.length) {
4313 data.args[0].o.children("a").each(function () { nms.push($(this).text().replace(/^\s+/g,"")); });
4314 res = this._check_unique(nms, data.args[0].np.find("> ul > li").not(data.args[0].o), "move_node");
4318 if(data.func == "create_node") {
4319 // obj, position, js, callback, is_loaded
4320 if(data.args[4] || this._is_loaded(data.args[0])) {
4321 p = this._get_node(data.args[0]);
4322 if(data.args[1] && (data.args[1] === "before" || data.args[1] === "after")) {
4323 p = this._get_parent(data.args[0]);
4324 if(!p || p === -1) { p = this.get_container(); }
4326 if(typeof data.args[2] === "string") { nms.push(data.args[2]); }
4327 else if(!data.args[2] || !data.args[2].data) { nms.push(this._get_string("new_node")); }
4328 else { nms.push(data.args[2].data); }
4329 res = this._check_unique(nms, p.find("> ul > li"), "create_node");
4332 if(data.func == "rename_node") {
4334 nms.push(data.args[1]);
4335 t = this._get_node(data.args[0]);
4336 p = this._get_parent(t);
4337 if(!p || p === -1) { p = this.get_container(); }
4338 res = this._check_unique(nms, p.find("> ul > li").not(t), "rename_node");
4341 e.stopPropagation();
4347 error_callback : $.noop
4350 _check_unique : function (nms, p, func) {
4352 p.children("a").each(function () { cnms.push($(this).text().replace(/^\s+/g,"")); });
4353 if(!cnms.length || !nms.length) { return true; }
4354 cnms = cnms.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",");
4355 if((cnms.length + nms.length) != cnms.concat(nms).sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",").length) {
4356 this._get_settings().unique.error_callback.call(null, nms, p, func);
4361 check_move : function () {
4362 if(!this.__call_old()) { return false; }
4363 var p = this._get_move(), nms = [];
4364 if(p.o && p.o.length) {
4365 p.o.children("a").each(function () { nms.push($(this).text().replace(/^\s+/g,"")); });
4366 return this._check_unique(nms, p.np.find("> ul > li").not(p.o), "check_move");
4376 * jsTree wholerow plugin
4377 * Makes select and hover work on the entire width of the node
4378 * MAY BE HEAVY IN LARGE DOM
4381 $.jstree.plugin("wholerow", {
4382 __init : function () {
4383 if(!this.data.ui) { throw "jsTree wholerow: jsTree UI plugin not included."; }
4384 this.data.wholerow.html = false;
4385 this.data.wholerow.to = false;
4386 this.get_container()
4387 .bind("init.jstree", $.proxy(function (e, data) {
4388 this._get_settings().core.animation = 0;
4390 .bind("open_node.jstree create_node.jstree clean_node.jstree loaded.jstree", $.proxy(function (e, data) {
4391 this._prepare_wholerow_span( data && data.rslt && data.rslt.obj ? data.rslt.obj : -1 );
4393 .bind("search.jstree clear_search.jstree reopen.jstree after_open.jstree after_close.jstree create_node.jstree delete_node.jstree clean_node.jstree", $.proxy(function (e, data) {
4394 if(this.data.to) { clearTimeout(this.data.to); }
4395 this.data.to = setTimeout( (function (t, o) { return function() { t._prepare_wholerow_ul(o); }; })(this, data && data.rslt && data.rslt.obj ? data.rslt.obj : -1), 0);
4397 .bind("deselect_all.jstree", $.proxy(function (e, data) {
4398 this.get_container().find(" > .jstree-wholerow .jstree-clicked").removeClass("jstree-clicked " + (this.data.themeroller ? this._get_settings().themeroller.item_a : "" ));
4400 .bind("select_node.jstree deselect_node.jstree ", $.proxy(function (e, data) {
4401 data.rslt.obj.each(function () {
4402 var ref = data.inst.get_container().find(" > .jstree-wholerow li:visible:eq(" + ( parseInt((($(this).offset().top - data.inst.get_container().offset().top + data.inst.get_container()[0].scrollTop) / data.inst.data.core.li_height),10)) + ")");
4403 // ref.children("a")[e.type === "select_node" ? "addClass" : "removeClass"]("jstree-clicked");
4404 ref.children("a").attr("class",data.rslt.obj.children("a").attr("class"));
4407 .bind("hover_node.jstree dehover_node.jstree", $.proxy(function (e, data) {
4408 this.get_container().find(" > .jstree-wholerow .jstree-hovered").removeClass("jstree-hovered " + (this.data.themeroller ? this._get_settings().themeroller.item_h : "" ));
4409 if(e.type === "hover_node") {
4410 var ref = this.get_container().find(" > .jstree-wholerow li:visible:eq(" + ( parseInt(((data.rslt.obj.offset().top - this.get_container().offset().top + this.get_container()[0].scrollTop) / this.data.core.li_height),10)) + ")");
4411 // ref.children("a").addClass("jstree-hovered");
4412 ref.children("a").attr("class",data.rslt.obj.children(".jstree-hovered").attr("class"));
4415 .delegate(".jstree-wholerow-span, ins.jstree-icon, li", "click.jstree", function (e) {
4416 var n = $(e.currentTarget);
4417 if(e.target.tagName === "A" || (e.target.tagName === "INS" && n.closest("li").is(".jstree-open, .jstree-closed"))) { return; }
4418 n.closest("li").children("a:visible:eq(0)").click();
4419 e.stopImmediatePropagation();
4421 .delegate("li", "mouseover.jstree", $.proxy(function (e) {
4422 e.stopImmediatePropagation();
4423 if($(e.currentTarget).children(".jstree-hovered, .jstree-clicked").length) { return false; }
4424 this.hover_node(e.currentTarget);
4427 .delegate("li", "mouseleave.jstree", $.proxy(function (e) {
4428 if($(e.currentTarget).children("a").hasClass("jstree-hovered").length) { return; }
4429 this.dehover_node(e.currentTarget);
4431 if(is_ie7 || is_ie6) {
4432 $.vakata.css.add_sheet({ str : ".jstree-" + this.get_index() + " { position:relative; } ", title : "jstree" });
4437 __destroy : function () {
4438 this.get_container().children(".jstree-wholerow").remove();
4439 this.get_container().find(".jstree-wholerow-span").remove();
4442 _prepare_wholerow_span : function (obj) {
4443 obj = !obj || obj == -1 ? this.get_container().find("> ul > li") : this._get_node(obj);
4444 if(obj === false) { return; } // added for removing root nodes
4445 obj.each(function () {
4446 $(this).find("li").andSelf().each(function () {
4448 if($t.children(".jstree-wholerow-span").length) { return true; }
4449 $t.prepend("<span class='jstree
-wholerow
-span
' style='width
:" + ($t.parentsUntil(".jstree
","li
").length * 18) + "px
;'> </span>");
4453 _prepare_wholerow_ul : function () {
4454 var o = this.get_container().children("ul").eq(0), h = o.html();
4455 o.addClass("jstree-wholerow-real");
4456 if(this.data.wholerow.last_html !== h) {
4457 this.data.wholerow.last_html = h;
4458 this.get_container().children(".jstree-wholerow").remove();
4459 this.get_container().append(
4460 o.clone().removeClass("jstree-wholerow-real")
4461 .wrapAll("<div class='jstree
-wholerow
' />").parent()
4462 .width(o.parent()[0].scrollWidth)
4463 .css("top", (o.height() + ( is_ie7 ? 5 : 0)) * -1 )
4464 .find("li[id]").each(function () { this.removeAttribute("id"); }).end()
4471 var css_string = '' +
4472 '.jstree
.jstree
-wholerow
-real
{ position
:relative
; z
-index
:1; } ' +
4473 '.jstree
.jstree
-wholerow
-real li
{ cursor
:pointer
; } ' +
4474 '.jstree
.jstree
-wholerow
-real a
{ border
-left
-color
:transparent
!important
; border
-right
-color
:transparent
!important
; } ' +
4475 '.jstree
.jstree
-wholerow
{ position
:relative
; z
-index
:0; height
:0; } ' +
4476 '.jstree
.jstree
-wholerow ul
, .jstree
.jstree
-wholerow li
{ width
:100%; } ' +
4477 '.jstree
.jstree
-wholerow
, .jstree
.jstree
-wholerow ul
, .jstree
.jstree
-wholerow li
, .jstree
.jstree
-wholerow a
{ margin
:0 !important
; padding
:0 !important
; } ' +
4478 '.jstree
.jstree
-wholerow
, .jstree
.jstree
-wholerow ul
, .jstree
.jstree
-wholerow li
{ background
:transparent
!important
; }' +
4479 '.jstree
.jstree
-wholerow ins
, .jstree
.jstree
-wholerow span
, .jstree
.jstree
-wholerow input
{ display
:none
!important
; }' +
4480 '.jstree
.jstree
-wholerow a
, .jstree
.jstree
-wholerow a
:hover
{ text
-indent
:-9999px
; !important
; width
:100%; padding
:0 !important
; border
-right
-width
:0px
!important
; border
-left
-width
:0px
!important
; } ' +
4481 '.jstree
.jstree
-wholerow
-span
{ position
:absolute
; left
:0; margin
:0px
; padding
:0; height
:18px
; border
-width
:0; padding
:0; z
-index
:0; }';
4484 '.jstree
.jstree
-wholerow a
{ display
:block
; height
:18px
; margin
:0; padding
:0; border
:0; } ' +
4485 '.jstree
.jstree
-wholerow
-real a
{ border
-color
:transparent
!important
; } ';
4487 if(is_ie7 || is_ie6) {
4489 '.jstree
.jstree
-wholerow
, .jstree
.jstree
-wholerow li
, .jstree
.jstree
-wholerow ul
, .jstree
.jstree
-wholerow a
{ margin
:0; padding
:0; line
-height
:18px
; } ' +
4490 '.jstree
.jstree
-wholerow a
{ display
:block
; height
:18px
; line
-height
:18px
; overflow
:hidden
; } ';
4492 $.vakata.css.add_sheet({ str : css_string, title : "jstree" });
4498 * jsTree model plugin
4499 * This plugin gets jstree to use a class model to retrieve data, creating great dynamism
4502 var nodeInterface = ["getChildren","getChildrenCount","getAttr","getName","getProps"],
4503 validateInterface = function(obj, inter) {
4506 inter = [].concat(inter);
4507 $.each(inter, function (i, v) {
4508 if(!$.isFunction(obj[v])) { valid = false; return false; }
4512 $.jstree.plugin("model", {
4513 __init : function () {
4514 if(!this.data.json_data) { throw "jsTree model: jsTree json_data plugin not included."; }
4515 this._get_settings().json_data.data = function (n, b) {
4516 var obj = (n == -1) ? this._get_settings().model.object : n.data("jstree_model");
4517 if(!validateInterface(obj, nodeInterface)) { return b.call(null, false); }
4518 if(this._get_settings().model.async) {
4519 obj.getChildren($.proxy(function (data) {
4520 this.model_done(data, b);
4524 this.model_done(obj.getChildren(), b);
4534 model_done : function (data, callback) {
4536 s = this._get_settings(),
4539 if(!$.isArray(data)) { data = [data]; }
4540 $.each(data, function (i, nd) {
4541 var r = nd.getProps() || {};
4542 r.attr = nd.getAttr() || {};
4543 if(nd.getChildrenCount()) { r.state = "closed"; }
4544 r.data = nd.getName();
4545 if(!$.isArray(r.data)) { r.data = [r.data]; }
4546 if(_this.data.types && $.isFunction(nd.getType)) {
4547 r.attr[s.types.type_attr] = nd.getType();
4549 if(r.attr.id && s.model.id_prefix) { r.attr.id = s.model.id_prefix + r.attr.id; }
4550 if(!r.metadata) { r.metadata = { }; }
4551 r.metadata.jstree_model = nd;
4554 callback.call(null, ret);