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, ActiveXObject: 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; 
 
  75                                                 tmp.styleSheet.cssText = tmp.styleSheet.cssText + " " + opts.str; 
 
  79                                         tmp.appendChild(document.createTextNode(opts.str));
 
  80                                         document.getElementsByTagName("head")[0].appendChild(tmp);
 
  82                                 return tmp.sheet || tmp.styleSheet;
 
  85                                 if(document.createStyleSheet) {
 
  86                                         try { tmp = document.createStyleSheet(opts.url); } catch (e) { }
 
  89                                         tmp                     = document.createElement('link');
 
  90                                         tmp.rel         = 'stylesheet';
 
  91                                         tmp.type        = 'text/css';
 
  94                                         document.getElementsByTagName("head")[0].appendChild(tmp);
 
  95                                         return tmp.styleSheet;
 
 102         var instances = [],                     // instance array (used by $.jstree.reference/create/focused)
 
 103                 focused_instance = -1,  // the index in the instance array of the currently focused instance
 
 104                 plugins = {},                   // list of included plugins
 
 105                 prepared_move = {};             // for the move_node function
 
 107         // jQuery plugin wrapper (thanks to jquery UI widget function)
 
 108         $.fn.jstree = function (settings) {
 
 109                 var isMethodCall = (typeof settings == 'string'), // is this a method call like $().jstree("open_node")
 
 110                         args = Array.prototype.slice.call(arguments, 1), 
 
 113                 // if a method call execute the method on all selected instances
 
 115                         if(settings.substring(0, 1) == '_') { return returnValue; }
 
 116                         this.each(function() {
 
 117                                 var instance = instances[$.data(this, "jstree_instance_id")],
 
 118                                         methodValue = (instance && $.isFunction(instance[settings])) ? instance[settings].apply(instance, args) : instance;
 
 119                                         if(typeof methodValue !== "undefined" && (settings.indexOf("is_") === 0 || (methodValue !== true && methodValue !== false))) { returnValue = methodValue; return false; }
 
 123                         this.each(function() {
 
 124                                 // extend settings and allow for multiple hashes and $.data
 
 125                                 var instance_id = $.data(this, "jstree_instance_id"),
 
 127                                         b = settings ? $.extend({}, true, settings) : {},
 
 132                                 if(c.data("jstree")) { a.push(c.data("jstree")); }
 
 133                                 b = a.length ? $.extend.apply(null, [true, b].concat(a)) : b;
 
 135                                 // if an instance already exists, destroy it first
 
 136                                 if(typeof instance_id !== "undefined" && instances[instance_id]) { instances[instance_id].destroy(); }
 
 137                                 // push a new empty object to the instances array
 
 138                                 instance_id = parseInt(instances.push({}),10) - 1;
 
 139                                 // store the jstree instance id to the container element
 
 140                                 $.data(this, "jstree_instance_id", instance_id);
 
 141                                 // clean up all plugins
 
 142                                 b.plugins = $.isArray(b.plugins) ? b.plugins : $.jstree.defaults.plugins.slice();
 
 143                                 b.plugins.unshift("core");
 
 144                                 // only unique plugins
 
 145                                 b.plugins = b.plugins.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",");
 
 147                                 // extend defaults with passed data
 
 148                                 s = $.extend(true, {}, $.jstree.defaults, b);
 
 149                                 s.plugins = b.plugins;
 
 150                                 $.each(plugins, function (i, val) { 
 
 151                                         if($.inArray(i, s.plugins) === -1) { s[i] = null; delete s[i]; } 
 
 156                                 // push the new object to the instances array (at the same time set the default classes to the container) and init
 
 157                                 instances[instance_id] = new $.jstree._instance(instance_id, $(this).addClass("jstree jstree-" + instance_id), s); 
 
 158                                 // init all activated plugins for this instance
 
 159                                 $.each(instances[instance_id]._get_settings().plugins, function (i, val) { instances[instance_id].data[val] = {}; });
 
 160                                 $.each(instances[instance_id]._get_settings().plugins, function (i, val) { if(plugins[val]) { plugins[val].__init.apply(instances[instance_id]); } });
 
 161                                 // initialize the instance
 
 162                                 setTimeout(function() { if(instances[instance_id]) { instances[instance_id].init(); } }, 0);
 
 165                 // return the jquery selection (or if it was a method call that returned a value - the returned value)
 
 168         // object to store exposed functions and objects
 
 173                 _focused : function () { return instances[focused_instance] || null; },
 
 174                 _reference : function (needle) { 
 
 175                         // get by instance id
 
 176                         if(instances[needle]) { return instances[needle]; }
 
 177                         // get by DOM (if still no luck - return null
 
 179                         if(!o.length && typeof needle === "string") { o = $("#" + needle); }
 
 180                         if(!o.length) { return null; }
 
 181                         return instances[o.closest(".jstree").data("jstree_instance_id")] || null; 
 
 183                 _instance : function (index, container, settings) { 
 
 184                         // for plugins to store data in
 
 185                         this.data = { core : {} };
 
 186                         this.get_settings       = function () { return $.extend(true, {}, settings); };
 
 187                         this._get_settings      = function () { return settings; };
 
 188                         this.get_index          = function () { return index; };
 
 189                         this.get_container      = function () { return container; };
 
 190                         this.get_container_ul = function () { return container.children("ul:eq(0)"); };
 
 191                         this._set_settings      = function (s) { 
 
 192                                 settings = $.extend(true, {}, settings, s);
 
 196                 plugin : function (pname, pdata) {
 
 197                         pdata = $.extend({}, {
 
 203                         plugins[pname] = pdata;
 
 205                         $.jstree.defaults[pname] = pdata.defaults;
 
 206                         $.each(pdata._fn, function (i, val) {
 
 208                                 val.old                 = $.jstree._fn[i];
 
 209                                 $.jstree._fn[i] = function () {
 
 212                                                 args = Array.prototype.slice.call(arguments),
 
 213                                                 evnt = new $.Event("before.jstree"),
 
 216                                         if(this.data.core.locked === true && i !== "unlock" && i !== "is_locked") { return; }
 
 218                                         // Check if function belongs to the included plugins of this instance
 
 220                                                 if(func && func.plugin && $.inArray(func.plugin, this._get_settings().plugins) !== -1) { break; }
 
 223                                         if(!func) { return; }
 
 225                                         // context and function to trigger events, then finally call the function
 
 226                                         if(i.indexOf("_") === 0) {
 
 227                                                 rslt = func.apply(this, args);
 
 230                                                 rslt = this.get_container().triggerHandler(evnt, { "func" : i, "inst" : this, "args" : args, "plugin" : func.plugin });
 
 231                                                 if(rslt === false) { return; }
 
 232                                                 if(typeof rslt !== "undefined") { args = rslt; }
 
 236                                                                 __callback : function (data) { 
 
 237                                                                         this.get_container().triggerHandler( i + '.jstree', { "inst" : this, "args" : args, "rslt" : data, "rlbk" : rlbk });
 
 239                                                                 __rollback : function () { 
 
 240                                                                         rlbk = this.get_rollback();
 
 243                                                                 __call_old : function (replace_arguments) {
 
 244                                                                         return func.old.apply(this, (replace_arguments ? Array.prototype.slice.call(arguments, 1) : args ) );
 
 252                                 $.jstree._fn[i].old = val.old;
 
 253                                 $.jstree._fn[i].plugin = pname;
 
 256                 rollback : function (rb) {
 
 258                                 if(!$.isArray(rb)) { rb = [ rb ]; }
 
 259                                 $.each(rb, function (i, val) {
 
 260                                         instances[val.i].set_rollback(val.h, val.d);
 
 265         // set the prototype for all instances
 
 266         $.jstree._fn = $.jstree._instance.prototype = {};
 
 268         // load the css when DOM is ready
 
 270                 // code is copied from jQuery ($.browser is deprecated + there is a bug in IE)
 
 271                 var u = navigator.userAgent.toLowerCase(),
 
 272                         v = (u.match( /.+?(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
 
 274                                 '.jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } ' + 
 
 275                                 '.jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; min-width:18px; } ' + 
 
 276                                 '.jstree-rtl li { margin-left:0; margin-right:18px; } ' + 
 
 277                                 '.jstree > ul > li { margin-left:0px; } ' + 
 
 278                                 '.jstree-rtl > ul > li { margin-right:0px; } ' + 
 
 279                                 '.jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } ' + 
 
 280                                 '.jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } ' + 
 
 281                                 '.jstree a:focus { outline: none; } ' + 
 
 282                                 '.jstree a > ins { height:16px; width:16px; } ' + 
 
 283                                 '.jstree a > .jstree-icon { margin-right:3px; } ' + 
 
 284                                 '.jstree-rtl a > .jstree-icon { margin-left:3px; margin-right:0; } ' + 
 
 285                                 'li.jstree-open > ul { display:block; } ' + 
 
 286                                 'li.jstree-closed > ul { display:none; } ';
 
 287                 // Correct IE 6 (does not support the > CSS selector)
 
 288                 if(/msie/.test(u) && parseInt(v, 10) == 6) { 
 
 291                         // fix image flicker and lack of caching
 
 293                                 document.execCommand("BackgroundImageCache", false, true);
 
 297                                 '.jstree li { height:18px; margin-left:0; margin-right:0; } ' + 
 
 298                                 '.jstree li li { margin-left:18px; } ' + 
 
 299                                 '.jstree-rtl li li { margin-left:0px; margin-right:18px; } ' + 
 
 300                                 'li.jstree-open ul { display:block; } ' + 
 
 301                                 'li.jstree-closed ul { display:none !important; } ' + 
 
 302                                 '.jstree li a { display:inline; border-width:0 !important; padding:0px 2px !important; } ' + 
 
 303                                 '.jstree li a ins { height:16px; width:16px; margin-right:3px; } ' + 
 
 304                                 '.jstree-rtl li a ins { margin-right:0px; margin-left:3px; } ';
 
 306                 // Correct IE 7 (shifts anchor nodes onhover)
 
 307                 if(/msie/.test(u) && parseInt(v, 10) == 7) { 
 
 309                         css_string += '.jstree li a { border-width:0 !important; padding:0px 2px !important; } ';
 
 311                 // correct ff2 lack of display:inline-block
 
 312                 if(!/compatible/.test(u) && /mozilla/.test(u) && parseFloat(v, 10) < 1.9) {
 
 315                                 '.jstree ins { display:-moz-inline-box; } ' + 
 
 316                                 '.jstree li { line-height:12px; } ' + // WHY??
 
 317                                 '.jstree a { display:-moz-inline-box; } ' + 
 
 318                                 '.jstree .jstree-no-icons .jstree-checkbox { display:-moz-inline-stack !important; } ';
 
 319                                 /* this shouldn't be here as it is theme specific */
 
 321                 // the default stylesheet
 
 322                 $.vakata.css.add_sheet({ str : css_string, title : "jstree" });
 
 325         // core functions (open, close, create, update, delete)
 
 326         $.jstree.plugin("core", {
 
 327                 __init : function () {
 
 328                         this.data.core.locked = false;
 
 329                         this.data.core.to_open = this.get_settings().core.initially_open;
 
 330                         this.data.core.to_load = this.get_settings().core.initially_load;
 
 338                         notify_plugins : true,
 
 342                                 loading         : "Loading ...",
 
 343                                 new_node        : "New node",
 
 344                                 multiple_selection : "Multiple selection"
 
 350                                 if(this._get_settings().core.rtl) {
 
 351                                         this.get_container().addClass("jstree-rtl").css("direction", "rtl");
 
 353                                 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>");
 
 354                                 this.data.core.li_height = this.get_container_ul().find("li.jstree-closed, li.jstree-leaf").eq(0).height() || 18;
 
 357                                         .delegate("li > ins", "click.jstree", $.proxy(function (event) {
 
 358                                                         var trgt = $(event.target);
 
 359                                                         // if(trgt.is("ins") && event.pageY - trgt.offset().top < this.data.core.li_height) { this.toggle_node(trgt); }
 
 360                                                         this.toggle_node(trgt);
 
 362                                         .bind("mousedown.jstree", $.proxy(function () { 
 
 363                                                         this.set_focus(); // This used to be setTimeout(set_focus,0) - why?
 
 365                                         .bind("dblclick.jstree", function (event) { 
 
 367                                                 if(document.selection && document.selection.empty) { document.selection.empty(); }
 
 369                                                         if(window.getSelection) {
 
 370                                                                 sel = window.getSelection();
 
 372                                                                         sel.removeAllRanges();
 
 378                                 if(this._get_settings().core.notify_plugins) {
 
 380                                                 .bind("load_node.jstree", $.proxy(function (e, data) { 
 
 381                                                                 var o = this._get_node(data.rslt.obj),
 
 383                                                                 if(o === -1) { o = this.get_container_ul(); }
 
 384                                                                 if(!o.length) { return; }
 
 385                                                                 o.find("li").each(function () {
 
 387                                                                         if(th.data("jstree")) {
 
 388                                                                                 $.each(th.data("jstree"), function (plugin, values) {
 
 389                                                                                         if(t.data[plugin] && $.isFunction(t["_" + plugin + "_notify"])) {
 
 390                                                                                                 t["_" + plugin + "_notify"].call(t, th, values);
 
 397                                 if(this._get_settings().core.load_open) {
 
 399                                                 .bind("load_node.jstree", $.proxy(function (e, data) { 
 
 400                                                                 var o = this._get_node(data.rslt.obj),
 
 402                                                                 if(o === -1) { o = this.get_container_ul(); }
 
 403                                                                 if(!o.length) { return; }
 
 404                                                                 o.find("li.jstree-open:not(:has(ul))").each(function () {
 
 405                                                                         t.load_node(this, $.noop, $.noop);
 
 410                                 this.load_node(-1, function () { this.loaded(); this.reload_nodes(); });
 
 412                         destroy : function () { 
 
 414                                         n = this.get_index(),
 
 415                                         s = this._get_settings(),
 
 418                                 $.each(s.plugins, function (i, val) {
 
 419                                         try { plugins[val].__destroy.apply(_this); } catch(err) { }
 
 422                                 // set focus to another instance if this one is focused
 
 423                                 if(this.is_focused()) { 
 
 424                                         for(i in instances) { 
 
 425                                                 if(instances.hasOwnProperty(i) && i != n) { 
 
 426                                                         instances[i].set_focus(); 
 
 431                                 // if no other instance found
 
 432                                 if(n === focused_instance) { focused_instance = -1; }
 
 433                                 // remove all traces of jstree in the DOM (only the ones set using jstree*) and cleans all events
 
 436                                         .undelegate(".jstree")
 
 437                                         .removeData("jstree_instance_id")
 
 438                                         .find("[class^='jstree']")
 
 440                                                 .attr("class", function () { return this.className.replace(/jstree[^ ]*|$/ig,''); });
 
 442                                         .unbind(".jstree-" + n)
 
 443                                         .undelegate(".jstree-" + n);
 
 444                                 // remove the actual data
 
 449                         _core_notify : function (n, data) {
 
 451                                         this.open_node(n, false, true);
 
 456                                 this.data.core.locked = true;
 
 457                                 this.get_container().children("ul").addClass("jstree-locked").css("opacity","0.7");
 
 460                         unlock : function () {
 
 461                                 this.data.core.locked = false;
 
 462                                 this.get_container().children("ul").removeClass("jstree-locked").css("opacity","1");
 
 465                         is_locked : function () { return this.data.core.locked; },
 
 466                         save_opened : function () {
 
 468                                 this.data.core.to_open = [];
 
 469                                 this.get_container_ul().find("li.jstree-open").each(function () { 
 
 470                                         if(this.id) { _this.data.core.to_open.push("#" + this.id.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:")); }
 
 472                                 this.__callback(_this.data.core.to_open);
 
 474                         save_loaded : function () { },
 
 475                         reload_nodes : function (is_callback) {
 
 481                                         this.data.core.reopen = false; 
 
 482                                         this.data.core.refreshing = true; 
 
 483                                         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,"\\:"); });
 
 484                                         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,"\\:"); });
 
 485                                         if(this.data.core.to_open.length) {
 
 486                                                 this.data.core.to_load = this.data.core.to_load.concat(this.data.core.to_open);
 
 489                                 if(this.data.core.to_load.length) {
 
 490                                         $.each(this.data.core.to_load, function (i, val) {
 
 491                                                 if(val == "#") { return true; }
 
 492                                                 if($(val).length) { current.push(val); }
 
 493                                                 else { remaining.push(val); }
 
 496                                                 this.data.core.to_load = remaining;
 
 497                                                 $.each(current, function (i, val) { 
 
 498                                                         if(!_this._is_loaded(val)) {
 
 499                                                                 _this.load_node(val, function () { _this.reload_nodes(true); }, function () { _this.reload_nodes(true); });
 
 505                                 if(this.data.core.to_open.length) {
 
 506                                         $.each(this.data.core.to_open, function (i, val) {
 
 507                                                 _this.open_node(val, false, true); 
 
 511                                         // TODO: find a more elegant approach to syncronizing returning requests
 
 512                                         if(this.data.core.reopen) { clearTimeout(this.data.core.reopen); }
 
 513                                         this.data.core.reopen = setTimeout(function () { _this.__callback({}, _this); }, 50);
 
 514                                         this.data.core.refreshing = false;
 
 518                         reopen : function () {
 
 520                                 if(this.data.core.to_open.length) {
 
 521                                         $.each(this.data.core.to_open, function (i, val) {
 
 522                                                 _this.open_node(val, false, true); 
 
 527                         refresh : function (obj) {
 
 530                                 if(!obj) { obj = -1; }
 
 531                                 obj = this._get_node(obj);
 
 532                                 if(!obj) { obj = -1; }
 
 533                                 if(obj !== -1) { obj.children("UL").remove(); }
 
 534                                 else { this.get_container_ul().empty(); }
 
 535                                 this.load_node(obj, function () { _this.__callback({ "obj" : obj}); _this.reload_nodes(); });
 
 537                         // Dummy function to fire after the first load (so that there is a jstree.loaded event)
 
 538                         loaded  : function () { 
 
 542                         set_focus       : function () { 
 
 543                                 if(this.is_focused()) { return; }
 
 544                                 var f = $.jstree._focused();
 
 545                                 if(f) { f.unset_focus(); }
 
 547                                 this.get_container().addClass("jstree-focused"); 
 
 548                                 focused_instance = this.get_index(); 
 
 551                         is_focused      : function () { 
 
 552                                 return focused_instance == this.get_index(); 
 
 554                         unset_focus     : function () {
 
 555                                 if(this.is_focused()) {
 
 556                                         this.get_container().removeClass("jstree-focused"); 
 
 557                                         focused_instance = -1; 
 
 563                         _get_node               : function (obj) { 
 
 564                                 var $obj = $(obj, this.get_container()); 
 
 565                                 if($obj.is(".jstree") || obj == -1) { return -1; } 
 
 566                                 $obj = $obj.closest("li", this.get_container()); 
 
 567                                 return $obj.length ? $obj : false; 
 
 569                         _get_next               : function (obj, strict) {
 
 570                                 obj = this._get_node(obj);
 
 571                                 if(obj === -1) { return this.get_container().find("> ul > li:first-child"); }
 
 572                                 if(!obj.length) { return false; }
 
 573                                 if(strict) { return (obj.nextAll("li").size() > 0) ? obj.nextAll("li:eq(0)") : false; }
 
 575                                 if(obj.hasClass("jstree-open")) { return obj.find("li:eq(0)"); }
 
 576                                 else if(obj.nextAll("li").size() > 0) { return obj.nextAll("li:eq(0)"); }
 
 577                                 else { return obj.parentsUntil(".jstree","li").next("li").eq(0); }
 
 579                         _get_prev               : function (obj, strict) {
 
 580                                 obj = this._get_node(obj);
 
 581                                 if(obj === -1) { return this.get_container().find("> ul > li:last-child"); }
 
 582                                 if(!obj.length) { return false; }
 
 583                                 if(strict) { return (obj.prevAll("li").length > 0) ? obj.prevAll("li:eq(0)") : false; }
 
 585                                 if(obj.prev("li").length) {
 
 586                                         obj = obj.prev("li").eq(0);
 
 587                                         while(obj.hasClass("jstree-open")) { obj = obj.children("ul:eq(0)").children("li:last"); }
 
 590                                 else { var o = obj.parentsUntil(".jstree","li:eq(0)"); return o.length ? o : false; }
 
 592                         _get_parent             : function (obj) {
 
 593                                 obj = this._get_node(obj);
 
 594                                 if(obj == -1 || !obj.length) { return false; }
 
 595                                 var o = obj.parentsUntil(".jstree", "li:eq(0)");
 
 596                                 return o.length ? o : -1;
 
 598                         _get_children   : function (obj) {
 
 599                                 obj = this._get_node(obj);
 
 600                                 if(obj === -1) { return this.get_container().children("ul:eq(0)").children("li"); }
 
 601                                 if(!obj.length) { return false; }
 
 602                                 return obj.children("ul:eq(0)").children("li");
 
 604                         get_path                : function (obj, id_mode) {
 
 607                                 obj = this._get_node(obj);
 
 608                                 if(obj === -1 || !obj || !obj.length) { return false; }
 
 609                                 obj.parentsUntil(".jstree", "li").each(function () {
 
 610                                         p.push( id_mode ? this.id : _this.get_text(this) );
 
 613                                 p.push( id_mode ? obj.attr("id") : this.get_text(obj) );
 
 618                         _get_string : function (key) {
 
 619                                 return this._get_settings().core.strings[key] || key;
 
 622                         is_open         : function (obj) { obj = this._get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-open"); },
 
 623                         is_closed       : function (obj) { obj = this._get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-closed"); },
 
 624                         is_leaf         : function (obj) { obj = this._get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-leaf"); },
 
 625                         correct_state   : function (obj) {
 
 626                                 obj = this._get_node(obj);
 
 627                                 if(!obj || obj === -1) { return false; }
 
 628                                 obj.removeClass("jstree-closed jstree-open").addClass("jstree-leaf").children("ul").remove();
 
 629                                 this.__callback({ "obj" : obj });
 
 632                         open_node       : function (obj, callback, skip_animation) {
 
 633                                 obj = this._get_node(obj);
 
 634                                 if(!obj.length) { return false; }
 
 635                                 if(!obj.hasClass("jstree-closed")) { if(callback) { callback.call(); } return false; }
 
 636                                 var s = skip_animation || is_ie6 ? 0 : this._get_settings().core.animation,
 
 638                                 if(!this._is_loaded(obj)) {
 
 639                                         obj.children("a").addClass("jstree-loading");
 
 640                                         this.load_node(obj, function () { t.open_node(obj, callback, skip_animation); }, callback);
 
 643                                         if(this._get_settings().core.open_parents) {
 
 644                                                 obj.parentsUntil(".jstree",".jstree-closed").each(function () {
 
 645                                                         t.open_node(this, false, true);
 
 648                                         if(s) { obj.children("ul").css("display","none"); }
 
 649                                         obj.removeClass("jstree-closed").addClass("jstree-open").children("a").removeClass("jstree-loading");
 
 650                                         if(s) { obj.children("ul").stop(true, true).slideDown(s, function () { this.style.display = ""; t.after_open(obj); }); }
 
 651                                         else { t.after_open(obj); }
 
 652                                         this.__callback({ "obj" : obj });
 
 653                                         if(callback) { callback.call(); }
 
 656                         after_open      : function (obj) { this.__callback({ "obj" : obj }); },
 
 657                         close_node      : function (obj, skip_animation) {
 
 658                                 obj = this._get_node(obj);
 
 659                                 var s = skip_animation || is_ie6 ? 0 : this._get_settings().core.animation,
 
 661                                 if(!obj.length || !obj.hasClass("jstree-open")) { return false; }
 
 662                                 if(s) { obj.children("ul").attr("style","display:block !important"); }
 
 663                                 obj.removeClass("jstree-open").addClass("jstree-closed");
 
 664                                 if(s) { obj.children("ul").stop(true, true).slideUp(s, function () { this.style.display = ""; t.after_close(obj); }); }
 
 665                                 else { t.after_close(obj); }
 
 666                                 this.__callback({ "obj" : obj });
 
 668                         after_close     : function (obj) { this.__callback({ "obj" : obj }); },
 
 669                         toggle_node     : function (obj) {
 
 670                                 obj = this._get_node(obj);
 
 671                                 if(obj.hasClass("jstree-closed")) { return this.open_node(obj); }
 
 672                                 if(obj.hasClass("jstree-open")) { return this.close_node(obj); }
 
 674                         open_all        : function (obj, do_animation, original_obj) {
 
 675                                 obj = obj ? this._get_node(obj) : -1;
 
 676                                 if(!obj || obj === -1) { obj = this.get_container_ul(); }
 
 678                                         obj = obj.find("li.jstree-closed");
 
 682                                         if(obj.is(".jstree-closed")) { obj = obj.find("li.jstree-closed").addBack(); }
 
 683                                         else { obj = obj.find("li.jstree-closed"); }
 
 686                                 obj.each(function () { 
 
 688                                         if(!_this._is_loaded(this)) { _this.open_node(this, function() { _this.open_all(__this, do_animation, original_obj); }, !do_animation); }
 
 689                                         else { _this.open_node(this, false, !do_animation); }
 
 691                                 // so that callback is fired AFTER all nodes are open
 
 692                                 if(original_obj.find('li.jstree-closed').length === 0) { this.__callback({ "obj" : original_obj }); }
 
 694                         close_all       : function (obj, do_animation) {
 
 696                                 obj = obj ? this._get_node(obj) : this.get_container();
 
 697                                 if(!obj || obj === -1) { obj = this.get_container_ul(); }
 
 698                                 obj.find("li.jstree-open").addBack().each(function () { _this.close_node(this, !do_animation); });
 
 699                                 this.__callback({ "obj" : obj });
 
 701                         clean_node      : function (obj) {
 
 702                                 obj = obj && obj != -1 ? $(obj) : this.get_container_ul();
 
 703                                 obj = obj.is("li") ? obj.find("li").addBack() : obj.find("li");
 
 704                                 obj.removeClass("jstree-last")
 
 705                                         .filter("li:last-child").addClass("jstree-last").end()
 
 707                                                 .not(".jstree-open").removeClass("jstree-leaf").addClass("jstree-closed");
 
 708                                 obj.not(".jstree-open, .jstree-closed").addClass("jstree-leaf").children("ul").remove();
 
 709                                 this.__callback({ "obj" : obj });
 
 712                         get_rollback : function () { 
 
 714                                 return { i : this.get_index(), h : this.get_container().children("ul").clone(true), d : this.data }; 
 
 716                         set_rollback : function (html, data) {
 
 717                                 this.get_container().empty().append(html);
 
 721                         // Dummy functions to be overwritten by any datastore plugin included
 
 722                         load_node       : function (obj, s_call, e_call) { this.__callback({ "obj" : obj }); },
 
 723                         _is_loaded      : function (obj) { return true; },
 
 725                         // Basic operations: create
 
 726                         create_node     : function (obj, position, js, callback, is_loaded) {
 
 727                                 obj = this._get_node(obj);
 
 728                                 position = typeof position === "undefined" ? "last" : position;
 
 730                                         s = this._get_settings().core,
 
 733                                 if(obj !== -1 && !obj.length) { return false; }
 
 734                                 if(!is_loaded && !this._is_loaded(obj)) { this.load_node(obj, function () { this.create_node(obj, position, js, callback, true); }); return false; }
 
 738                                 if(typeof js === "string") { js = { "data" : js }; }
 
 740                                 if(js.attr) { d.attr(js.attr); }
 
 741                                 if(js.metadata) { d.data(js.metadata); }
 
 742                                 if(js.state) { d.addClass("jstree-" + js.state); }
 
 743                                 if(!js.data) { js.data = this._get_string("new_node"); }
 
 744                                 if(!$.isArray(js.data)) { tmp = js.data; js.data = []; js.data.push(tmp); }
 
 745                                 $.each(js.data, function (i, m) {
 
 747                                         if($.isFunction(m)) { m = m.call(this, js); }
 
 748                                         if(typeof m == "string") { tmp.attr('href','#')[ s.html_titles ? "html" : "text" ](m); }
 
 750                                                 if(!m.attr) { m.attr = {}; }
 
 751                                                 if(!m.attr.href) { m.attr.href = '#'; }
 
 752                                                 tmp.attr(m.attr)[ s.html_titles ? "html" : "text" ](m.title);
 
 753                                                 if(m.language) { tmp.addClass(m.language); }
 
 755                                         tmp.prepend("<ins class='jstree-icon'> </ins>");
 
 756                                         if(!m.icon && js.icon) { m.icon = js.icon; }
 
 758                                                 if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); }
 
 759                                                 else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat"); }
 
 763                                 d.prepend("<ins class='jstree-icon'> </ins>");
 
 765                                         obj = this.get_container();
 
 766                                         if(position === "before") { position = "first"; }
 
 767                                         if(position === "after") { position = "last"; }
 
 770                                         case "before": obj.before(d); tmp = this._get_parent(obj); break;
 
 771                                         case "after" : obj.after(d);  tmp = this._get_parent(obj); break;
 
 774                                                 if(!obj.children("ul").length) { obj.append("<ul />"); }
 
 775                                                 obj.children("ul").prepend(d);
 
 779                                                 if(!obj.children("ul").length) { obj.append("<ul />"); }
 
 780                                                 obj.children("ul").append(d);
 
 784                                                 if(!obj.children("ul").length) { obj.append("<ul />"); }
 
 785                                                 if(!position) { position = 0; }
 
 786                                                 tmp = obj.children("ul").children("li").eq(position);
 
 787                                                 if(tmp.length) { tmp.before(d); }
 
 788                                                 else { obj.children("ul").append(d); }
 
 792                                 if(tmp === -1 || tmp.get(0) === this.get_container().get(0)) { tmp = -1; }
 
 793                                 this.clean_node(tmp);
 
 794                                 this.__callback({ "obj" : d, "parent" : tmp });
 
 795                                 if(callback) { callback.call(this, d); }
 
 798                         // Basic operations: rename (deal with text)
 
 799                         get_text        : function (obj) {
 
 800                                 obj = this._get_node(obj);
 
 801                                 if(!obj.length) { return false; }
 
 802                                 var s = this._get_settings().core.html_titles;
 
 803                                 obj = obj.children("a:eq(0)");
 
 806                                         obj.children("INS").remove();
 
 810                                         obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
 
 811                                         return obj.nodeValue;
 
 814                         set_text        : function (obj, val) {
 
 815                                 obj = this._get_node(obj);
 
 816                                 if(!obj.length) { return false; }
 
 817                                 obj = obj.children("a:eq(0)");
 
 818                                 if(this._get_settings().core.html_titles) {
 
 819                                         var tmp = obj.children("INS").clone();
 
 820                                         obj.html(val).prepend(tmp);
 
 821                                         this.__callback({ "obj" : obj, "name" : val });
 
 825                                         obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
 
 826                                         this.__callback({ "obj" : obj, "name" : val });
 
 827                                         return (obj.nodeValue = val);
 
 830                         rename_node : function (obj, val) {
 
 831                                 obj = this._get_node(obj);
 
 833                                 if(obj && obj.length && this.set_text.apply(this, Array.prototype.slice.call(arguments))) { this.__callback({ "obj" : obj, "name" : val }); }
 
 835                         // Basic operations: deleting nodes
 
 836                         delete_node : function (obj) {
 
 837                                 obj = this._get_node(obj);
 
 838                                 if(!obj.length) { return false; }
 
 840                                 var p = this._get_parent(obj), prev = $([]), t = this;
 
 841                                 obj.each(function () {
 
 842                                         prev = prev.add(t._get_prev(this));
 
 845                                 if(p !== -1 && p.find("> ul > li").length === 0) {
 
 846                                         p.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");
 
 849                                 this.__callback({ "obj" : obj, "prev" : prev, "parent" : p });
 
 852                         prepare_move : function (o, r, pos, cb, is_cb) {
 
 855                                 p.ot = $.jstree._reference(o) || this;
 
 856                                 p.o = p.ot._get_node(o);
 
 857                                 p.r = r === - 1 ? -1 : this._get_node(r);
 
 858                                 p.p = (typeof pos === "undefined" || pos === false) ? "last" : pos; // TODO: move to a setting
 
 859                                 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) {
 
 860                                         this.__callback(prepared_move);
 
 861                                         if(cb) { cb.call(this, prepared_move); }
 
 864                                 p.ot = $.jstree._reference(p.o) || this;
 
 865                                 p.rt = $.jstree._reference(p.r) || this; // r === -1 ? p.ot : $.jstree._reference(p.r) || this
 
 866                                 if(p.r === -1 || !p.r) {
 
 876                                                         p.cp = p.rt.get_container().find(" > ul > li").length; 
 
 884                                         if(!/^(before|after)$/.test(p.p) && !this._is_loaded(p.r)) {
 
 885                                                 return this.load_node(p.r, function () { this.prepare_move(o, r, pos, cb, true); });
 
 890                                                         p.cr = p.rt._get_parent(p.r);
 
 893                                                         p.cp = p.r.index() + 1;
 
 894                                                         p.cr = p.rt._get_parent(p.r);
 
 902                                                         p.cp = p.r.find(" > ul > li").length; 
 
 911                                 p.np = p.cr == -1 ? p.rt.get_container() : p.cr;
 
 912                                 p.op = p.ot._get_parent(p.o);
 
 914                                 if(p.op === -1) { p.op = p.ot ? p.ot.get_container() : this.get_container(); }
 
 915                                 if(!/^(before|after)$/.test(p.p) && p.op && p.np && p.op[0] === p.np[0] && p.o.index() < p.cp) { p.cp++; }
 
 916                                 //if(p.p === "before" && p.op && p.np && p.op[0] === p.np[0] && p.o.index() < p.cp) { p.cp--; }
 
 917                                 p.or = p.np.find(" > ul > li:nth-child(" + (p.cp + 1) + ")");
 
 919                                 this.__callback(prepared_move);
 
 920                                 if(cb) { cb.call(this, prepared_move); }
 
 922                         check_move : function () {
 
 923                                 var obj = prepared_move, ret = true, r = obj.r === -1 ? this.get_container() : obj.r;
 
 924                                 if(!obj || !obj.o || obj.or[0] === obj.o[0]) { return false; }
 
 926                                         if(obj.op && obj.np && obj.op[0] === obj.np[0] && obj.cp - 1 === obj.o.index()) { return false; }
 
 927                                         obj.o.each(function () { 
 
 928                                                 if(r.parentsUntil(".jstree", "li").addBack().index(this) !== -1) { ret = false; return false; }
 
 933                         move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) {
 
 935                                         return this.prepare_move(obj, ref, position, function (p) {
 
 936                                                 this.move_node(p, false, false, is_copy, true, skip_check);
 
 940                                         prepared_move.cy = true;
 
 942                                 if(!skip_check && !this.check_move()) { return false; }
 
 947                                         o = obj.o.clone(true);
 
 948                                         o.find("*[id]").addBack().each(function () {
 
 949                                                 if(this.id) { this.id = "copy_" + this.id; }
 
 954                                 if(obj.or.length) { obj.or.before(o); }
 
 956                                         if(!obj.np.children("ul").length) { $("<ul />").appendTo(obj.np); }
 
 957                                         obj.np.children("ul:eq(0)").append(o); 
 
 961                                         obj.ot.clean_node(obj.op);
 
 962                                         obj.rt.clean_node(obj.np);
 
 963                                         if(!obj.op.find("> ul > li").length) {
 
 964                                                 obj.op.removeClass("jstree-open jstree-closed").addClass("jstree-leaf").children("ul").remove();
 
 969                                         prepared_move.cy = true;
 
 970                                         prepared_move.oc = o; 
 
 972                                 this.__callback(prepared_move);
 
 973                                 return prepared_move;
 
 975                         _get_move : function () { return prepared_move; }
 
 983  * This plugins handles selecting/deselecting/hovering/dehovering nodes
 
 986         var scrollbar_width, e1, e2;
 
 988                 if (/msie/.test(navigator.userAgent.toLowerCase())) {
 
 989                         e1 = $('<textarea cols="10" rows="2"></textarea>').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body');
 
 990                         e2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body');
 
 991                         scrollbar_width = e1.width() - e2.width();
 
 995                         e1 = $('<div />').css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: 0 })
 
 996                                         .prependTo('body').append('<div />').find('div').css({ width: '100%', height: 200 });
 
 997                         scrollbar_width = 100 - e1.width();
 
 998                         e1.parent().remove();
 
1001         $.jstree.plugin("ui", {
 
1002                 __init : function () { 
 
1003                         this.data.ui.selected = $(); 
 
1004                         this.data.ui.last_selected = false; 
 
1005                         this.data.ui.hovered = null;
 
1006                         this.data.ui.to_select = this.get_settings().ui.initially_select;
 
1008                         this.get_container()
 
1009                                 .delegate("a", "click.jstree", $.proxy(function (event) {
 
1010                                                 event.preventDefault();
 
1011                                                 event.currentTarget.blur();
 
1012                                                 if(!$(event.currentTarget).hasClass("jstree-loading")) {
 
1013                                                         this.select_node(event.currentTarget, true, event);
 
1016                                 .delegate("a", "mouseenter.jstree", $.proxy(function (event) {
 
1017                                                 if(!$(event.currentTarget).hasClass("jstree-loading")) {
 
1018                                                         this.hover_node(event.target);
 
1021                                 .delegate("a", "mouseleave.jstree", $.proxy(function (event) {
 
1022                                                 if(!$(event.currentTarget).hasClass("jstree-loading")) {
 
1023                                                         this.dehover_node(event.target);
 
1026                                 .bind("reopen.jstree", $.proxy(function () { 
 
1029                                 .bind("get_rollback.jstree", $.proxy(function () { 
 
1030                                                 this.dehover_node();
 
1031                                                 this.save_selected();
 
1033                                 .bind("set_rollback.jstree", $.proxy(function () { 
 
1036                                 .bind("close_node.jstree", $.proxy(function (event, data) { 
 
1037                                                 var s = this._get_settings().ui,
 
1038                                                         obj = this._get_node(data.rslt.obj),
 
1039                                                         clk = (obj && obj.length) ? obj.children("ul").find("a.jstree-clicked") : $(),
 
1041                                                 if(s.selected_parent_close === false || !clk.length) { return; }
 
1042                                                 clk.each(function () { 
 
1043                                                         _this.deselect_node(this);
 
1044                                                         if(s.selected_parent_close === "select_parent") { _this.select_node(obj); }
 
1047                                 .bind("delete_node.jstree", $.proxy(function (event, data) { 
 
1048                                                 var s = this._get_settings().ui.select_prev_on_delete,
 
1049                                                         obj = this._get_node(data.rslt.obj),
 
1050                                                         clk = (obj && obj.length) ? obj.find("a.jstree-clicked") : [],
 
1052                                                 clk.each(function () { _this.deselect_node(this); });
 
1053                                                 if(s && clk.length) { 
 
1054                                                         data.rslt.prev.each(function () { 
 
1055                                                                 if(this.parentNode) { _this.select_node(this); return false; /* if return false is removed all prev nodes will be selected */}
 
1059                                 .bind("move_node.jstree", $.proxy(function (event, data) { 
 
1061                                                         data.rslt.oc.find("a.jstree-clicked").removeClass("jstree-clicked");
 
1066                         select_limit : -1, // 0, 1, 2 ... or -1 for unlimited
 
1067                         select_multiple_modifier : "ctrl", // on, or ctrl, shift, alt
 
1068                         select_range_modifier : "shift",
 
1069                         selected_parent_close : "select_parent", // false, "deselect", "select_parent"
 
1070                         selected_parent_open : true,
 
1071                         select_prev_on_delete : true,
 
1072                         disable_selecting_children : false,
 
1073                         initially_select : []
 
1076                         _get_node : function (obj, allow_multiple) {
 
1077                                 if(typeof obj === "undefined" || obj === null) { return allow_multiple ? this.data.ui.selected : this.data.ui.last_selected; }
 
1078                                 var $obj = $(obj, this.get_container()); 
 
1079                                 if($obj.is(".jstree") || obj == -1) { return -1; } 
 
1080                                 $obj = $obj.closest("li", this.get_container()); 
 
1081                                 return $obj.length ? $obj : false; 
 
1083                         _ui_notify : function (n, data) {
 
1085                                         this.select_node(n, false);
 
1088                         save_selected : function () {
 
1090                                 this.data.ui.to_select = [];
 
1091                                 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,"\\:")); } });
 
1092                                 this.__callback(this.data.ui.to_select);
 
1094                         reselect : function () {
 
1096                                         s = this.data.ui.to_select;
 
1097                                 s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); });
 
1098                                 // this.deselect_all(); WHY deselect, breaks plugin state notifier?
 
1099                                 $.each(s, function (i, val) { if(val && val !== "#") { _this.select_node(val); } });
 
1100                                 this.data.ui.selected = this.data.ui.selected.filter(function () { return this.parentNode; });
 
1103                         refresh : function (obj) {
 
1104                                 this.save_selected();
 
1105                                 return this.__call_old();
 
1107                         hover_node : function (obj) {
 
1108                                 obj = this._get_node(obj);
 
1109                                 if(!obj.length) { return false; }
 
1110                                 //if(this.data.ui.hovered && obj.get(0) === this.data.ui.hovered.get(0)) { return; }
 
1111                                 if(!obj.hasClass("jstree-hovered")) { this.dehover_node(); }
 
1112                                 this.data.ui.hovered = obj.children("a").addClass("jstree-hovered").parent();
 
1113                                 this._fix_scroll(obj);
 
1114                                 this.__callback({ "obj" : obj });
 
1116                         dehover_node : function () {
 
1117                                 var obj = this.data.ui.hovered, p;
 
1118                                 if(!obj || !obj.length) { return false; }
 
1119                                 p = obj.children("a").removeClass("jstree-hovered").parent();
 
1120                                 if(this.data.ui.hovered[0] === p[0]) { this.data.ui.hovered = null; }
 
1121                                 this.__callback({ "obj" : obj });
 
1123                         select_node : function (obj, check, e) {
 
1124                                 obj = this._get_node(obj);
 
1125                                 if(obj == -1 || !obj || !obj.length) { return false; }
 
1126                                 var s = this._get_settings().ui,
 
1127                                         is_multiple = (s.select_multiple_modifier == "on" || (s.select_multiple_modifier !== false && e && e[s.select_multiple_modifier + "Key"])),
 
1128                                         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]),
 
1129                                         is_selected = this.is_selected(obj),
 
1133                                         if(s.disable_selecting_children && is_multiple && 
 
1135                                                         (obj.parentsUntil(".jstree","li").children("a.jstree-clicked").length) ||
 
1136                                                         (obj.children("ul").find("a.jstree-clicked:eq(0)").length)
 
1144                                                         this.data.ui.last_selected.addClass("jstree-last-selected");
 
1145                                                         obj = obj[ obj.index() < this.data.ui.last_selected.index() ? "nextUntil" : "prevUntil" ](".jstree-last-selected").addBack();
 
1146                                                         if(s.select_limit == -1 || obj.length < s.select_limit) {
 
1147                                                                 this.data.ui.last_selected.removeClass("jstree-last-selected");
 
1148                                                                 this.data.ui.selected.each(function () {
 
1149                                                                         if(this !== t.data.ui.last_selected[0]) { t.deselect_node(this); }
 
1151                                                                 is_selected = false;
 
1158                                                 case (is_selected && !is_multiple): 
 
1159                                                         this.deselect_all();
 
1160                                                         is_selected = false;
 
1163                                                 case (!is_selected && !is_multiple): 
 
1164                                                         if(s.select_limit == -1 || s.select_limit > 0) {
 
1165                                                                 this.deselect_all();
 
1169                                                 case (is_selected && is_multiple): 
 
1170                                                         this.deselect_node(obj);
 
1172                                                 case (!is_selected && is_multiple): 
 
1173                                                         if(s.select_limit == -1 || this.data.ui.selected.length + 1 <= s.select_limit) { 
 
1179                                 if(proceed && !is_selected) {
 
1180                                         if(!is_range) { this.data.ui.last_selected = obj; }
 
1181                                         obj.children("a").addClass("jstree-clicked");
 
1182                                         if(s.selected_parent_open) {
 
1183                                                 obj.parents(".jstree-closed").each(function () { t.open_node(this, false, true); });
 
1185                                         this.data.ui.selected = this.data.ui.selected.add(obj);
 
1186                                         this._fix_scroll(obj.eq(0));
 
1187                                         this.__callback({ "obj" : obj, "e" : e });
 
1190                         _fix_scroll : function (obj) {
 
1191                                 var c = this.get_container()[0], t;
 
1192                                 if(c.scrollHeight > c.offsetHeight) {
 
1193                                         obj = this._get_node(obj);
 
1194                                         if(!obj || obj === -1 || !obj.length || !obj.is(":visible")) { return; }
 
1195                                         t = obj.offset().top - this.get_container().offset().top;
 
1197                                                 c.scrollTop = c.scrollTop + t - 1; 
 
1199                                         if(t + this.data.core.li_height + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0) > c.offsetHeight) { 
 
1200                                                 c.scrollTop = c.scrollTop + (t - c.offsetHeight + this.data.core.li_height + 1 + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0)); 
 
1204                         deselect_node : function (obj) {
 
1205                                 obj = this._get_node(obj);
 
1206                                 if(!obj.length) { return false; }
 
1207                                 if(this.is_selected(obj)) {
 
1208                                         obj.children("a").removeClass("jstree-clicked");
 
1209                                         this.data.ui.selected = this.data.ui.selected.not(obj);
 
1210                                         if(this.data.ui.last_selected.get(0) === obj.get(0)) { this.data.ui.last_selected = this.data.ui.selected.eq(0); }
 
1211                                         this.__callback({ "obj" : obj });
 
1214                         toggle_select : function (obj) {
 
1215                                 obj = this._get_node(obj);
 
1216                                 if(!obj.length) { return false; }
 
1217                                 if(this.is_selected(obj)) { this.deselect_node(obj); }
 
1218                                 else { this.select_node(obj); }
 
1220                         is_selected : function (obj) { return this.data.ui.selected.index(this._get_node(obj)) >= 0; },
 
1221                         get_selected : function (context) { 
 
1222                                 return context ? $(context).find("a.jstree-clicked").parent() : this.data.ui.selected; 
 
1224                         deselect_all : function (context) {
 
1225                                 var ret = context ? $(context).find("a.jstree-clicked").parent() : this.get_container().find("a.jstree-clicked").parent();
 
1226                                 ret.children("a.jstree-clicked").removeClass("jstree-clicked");
 
1227                                 this.data.ui.selected = $([]);
 
1228                                 this.data.ui.last_selected = false;
 
1229                                 this.__callback({ "obj" : ret });
 
1233         // include the selection plugin by default
 
1234         $.jstree.defaults.plugins.push("ui");
 
1239  * jsTree CRRM plugin
 
1240  * Handles creating/renaming/removing/moving nodes by user interaction.
 
1243         $.jstree.plugin("crrm", { 
 
1244                 __init : function () {
 
1245                         this.get_container()
 
1246                                 .bind("move_node.jstree", $.proxy(function (e, data) {
 
1247                                         if(this._get_settings().crrm.move.open_onmove) {
 
1249                                                 data.rslt.np.parentsUntil(".jstree").addBack().filter(".jstree-closed").each(function () {
 
1250                                                         t.open_node(this, false, true);
 
1256                         input_width_limit : 200,
 
1258                                 always_copy                     : false, // false, true or "multitree"
 
1260                                 default_position        : "last",
 
1261                                 check_move                      : function (m) { return true; }
 
1265                         _show_input : function (obj, callback) {
 
1266                                 obj = this._get_node(obj);
 
1267                                 var rtl = this._get_settings().core.rtl,
 
1268                                         w = this._get_settings().crrm.input_width_limit,
 
1269                                         w1 = obj.children("ins").width(),
 
1270                                         w2 = obj.find("> a:visible > ins").width() * obj.find("> a:visible > ins").length,
 
1271                                         t = this.get_text(obj),
 
1272                                         h1 = $("<div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"),
 
1273                                         h2 = obj.css("position","relative").append(
 
1276                                                 "class" : "jstree-rename-input",
 
1277                                                 // "size" : t.length,
 
1280                                                         "border" : "1px solid silver",
 
1281                                                         "position" : "absolute",
 
1282                                                         "left"  : (rtl ? "auto" : (w1 + w2 + 4) + "px"),
 
1283                                                         "right" : (rtl ? (w1 + w2 + 4) + "px" : "auto"),
 
1285                                                         "height" : (this.data.core.li_height - 2) + "px",
 
1286                                                         "lineHeight" : (this.data.core.li_height - 2) + "px",
 
1287                                                         "width" : "150px" // will be set a bit further down
 
1289                                                 "blur" : $.proxy(function () {
 
1290                                                         var i = obj.children(".jstree-rename-input"),
 
1292                                                         if(v === "") { v = t; }
 
1294                                                         i.remove(); // rollback purposes
 
1295                                                         this.set_text(obj,t); // rollback purposes
 
1296                                                         this.rename_node(obj, v);
 
1297                                                         callback.call(this, obj, v, t);
 
1298                                                         obj.css("position","");
 
1300                                                 "keyup" : function (event) {
 
1301                                                         var key = event.keyCode || event.which;
 
1302                                                         if(key == 27) { this.value = t; this.blur(); return; }
 
1303                                                         else if(key == 13) { this.blur(); return; }
 
1305                                                                 h2.width(Math.min(h1.text("pW" + this.value).width(),w));
 
1308                                                 "keypress" : function(event) {
 
1309                                                         var key = event.keyCode || event.which;
 
1310                                                         if(key == 13) { return false; }
 
1313                                 ).children(".jstree-rename-input"); 
 
1314                                 this.set_text(obj, "");
 
1316                                                 fontFamily              : h2.css('fontFamily')          || '',
 
1317                                                 fontSize                : h2.css('fontSize')            || '',
 
1318                                                 fontWeight              : h2.css('fontWeight')          || '',
 
1319                                                 fontStyle               : h2.css('fontStyle')           || '',
 
1320                                                 fontStretch             : h2.css('fontStretch')         || '',
 
1321                                                 fontVariant             : h2.css('fontVariant')         || '',
 
1322                                                 letterSpacing   : h2.css('letterSpacing')       || '',
 
1323                                                 wordSpacing             : h2.css('wordSpacing')         || ''
 
1325                                 h2.width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select();
 
1327                         rename : function (obj) {
 
1328                                 obj = this._get_node(obj);
 
1330                                 var f = this.__callback;
 
1331                                 this._show_input(obj, function (obj, new_name, old_name) { 
 
1332                                         f.call(this, { "obj" : obj, "new_name" : new_name, "old_name" : old_name });
 
1335                         create : function (obj, position, js, callback, skip_rename) {
 
1336                                 var t, _this = this;
 
1337                                 obj = this._get_node(obj);
 
1338                                 if(!obj) { obj = -1; }
 
1340                                 t = this.create_node(obj, position, js, function (t) {
 
1341                                         var p = this._get_parent(t),
 
1343                                         if(callback) { callback.call(this, t); }
 
1344                                         if(p.length && p.hasClass("jstree-closed")) { this.open_node(p, false, true); }
 
1346                                                 this._show_input(t, function (obj, new_name, old_name) { 
 
1347                                                         _this.__callback({ "obj" : obj, "name" : new_name, "parent" : p, "position" : pos });
 
1350                                         else { _this.__callback({ "obj" : t, "name" : this.get_text(t), "parent" : p, "position" : pos }); }
 
1354                         remove : function (obj) {
 
1355                                 obj = this._get_node(obj, true);
 
1356                                 var p = this._get_parent(obj), prev = this._get_prev(obj);
 
1358                                 obj = this.delete_node(obj);
 
1359                                 if(obj !== false) { this.__callback({ "obj" : obj, "prev" : prev, "parent" : p }); }
 
1361                         check_move : function () {
 
1362                                 if(!this.__call_old()) { return false; }
 
1363                                 var s = this._get_settings().crrm.move;
 
1364                                 if(!s.check_move.call(this, this._get_move())) { return false; }
 
1367                         move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) {
 
1368                                 var s = this._get_settings().crrm.move;
 
1370                                         if(typeof position === "undefined") { position = s.default_position; }
 
1371                                         if(position === "inside" && !s.default_position.match(/^(before|after)$/)) { position = s.default_position; }
 
1372                                         return this.__call_old(true, obj, ref, position, is_copy, false, skip_check);
 
1374                                 // if the move is already prepared
 
1375                                 if(s.always_copy === true || (s.always_copy === "multitree" && obj.rt.get_index() !== obj.ot.get_index() )) {
 
1378                                 this.__call_old(true, obj, ref, position, is_copy, true, skip_check);
 
1381                         cut : function (obj) {
 
1382                                 obj = this._get_node(obj, true);
 
1383                                 if(!obj || !obj.length) { return false; }
 
1384                                 this.data.crrm.cp_nodes = false;
 
1385                                 this.data.crrm.ct_nodes = obj;
 
1386                                 this.__callback({ "obj" : obj });
 
1388                         copy : function (obj) {
 
1389                                 obj = this._get_node(obj, true);
 
1390                                 if(!obj || !obj.length) { return false; }
 
1391                                 this.data.crrm.ct_nodes = false;
 
1392                                 this.data.crrm.cp_nodes = obj;
 
1393                                 this.__callback({ "obj" : obj });
 
1395                         paste : function (obj) { 
 
1396                                 obj = this._get_node(obj);
 
1397                                 if(!obj || !obj.length) { return false; }
 
1398                                 var nodes = this.data.crrm.ct_nodes ? this.data.crrm.ct_nodes : this.data.crrm.cp_nodes;
 
1399                                 if(!this.data.crrm.ct_nodes && !this.data.crrm.cp_nodes) { return false; }
 
1400                                 if(this.data.crrm.ct_nodes) { this.move_node(this.data.crrm.ct_nodes, obj); this.data.crrm.ct_nodes = false; }
 
1401                                 if(this.data.crrm.cp_nodes) { this.move_node(this.data.crrm.cp_nodes, obj, false, true); }
 
1402                                 this.__callback({ "obj" : obj, "nodes" : nodes });
 
1406         // include the crr plugin by default
 
1407         // $.jstree.defaults.plugins.push("crrm");
 
1412  * jsTree themes plugin
 
1413  * Handles loading and setting themes, as well as detecting path to themes, etc.
 
1416         var themes_loaded = [];
 
1417         // this variable stores the path to the themes folder - if left as false - it will be autodetected
 
1418         $.jstree._themes = false;
 
1419         $.jstree.plugin("themes", {
 
1420                 __init : function () { 
 
1421                         this.get_container()
 
1422                                 .bind("init.jstree", $.proxy(function () {
 
1423                                                 var s = this._get_settings().themes;
 
1424                                                 this.data.themes.dots = s.dots; 
 
1425                                                 this.data.themes.icons = s.icons; 
 
1426                                                 this.set_theme(s.theme, s.url);
 
1428                                 .bind("loaded.jstree", $.proxy(function () {
 
1429                                                 // bound here too, as simple HTML tree's won't honor dots & icons otherwise
 
1430                                                 if(!this.data.themes.dots) { this.hide_dots(); }
 
1431                                                 else { this.show_dots(); }
 
1432                                                 if(!this.data.themes.icons) { this.hide_icons(); }
 
1433                                                 else { this.show_icons(); }
 
1443                         set_theme : function (theme_name, theme_url) {
 
1444                                 if(!theme_name) { return false; }
 
1445                                 if(!theme_url) { theme_url = $.jstree._themes + theme_name + '/style.css'; }
 
1446                                 if($.inArray(theme_url, themes_loaded) == -1) {
 
1447                                         $.vakata.css.add_sheet({ "url" : theme_url });
 
1448                                         themes_loaded.push(theme_url);
 
1450                                 if(this.data.themes.theme != theme_name) {
 
1451                                         this.get_container().removeClass('jstree-' + this.data.themes.theme);
 
1452                                         this.data.themes.theme = theme_name;
 
1454                                 this.get_container().addClass('jstree-' + theme_name);
 
1455                                 if(!this.data.themes.dots) { this.hide_dots(); }
 
1456                                 else { this.show_dots(); }
 
1457                                 if(!this.data.themes.icons) { this.hide_icons(); }
 
1458                                 else { this.show_icons(); }
 
1461                         get_theme       : function () { return this.data.themes.theme; },
 
1463                         show_dots       : function () { this.data.themes.dots = true; this.get_container().children("ul").removeClass("jstree-no-dots"); },
 
1464                         hide_dots       : function () { this.data.themes.dots = false; this.get_container().children("ul").addClass("jstree-no-dots"); },
 
1465                         toggle_dots     : function () { if(this.data.themes.dots) { this.hide_dots(); } else { this.show_dots(); } },
 
1467                         show_icons      : function () { this.data.themes.icons = true; this.get_container().children("ul").removeClass("jstree-no-icons"); },
 
1468                         hide_icons      : function () { this.data.themes.icons = false; this.get_container().children("ul").addClass("jstree-no-icons"); },
 
1469                         toggle_icons: function () { if(this.data.themes.icons) { this.hide_icons(); } else { this.show_icons(); } }
 
1472         // autodetect themes path
 
1474                 if($.jstree._themes === false) {
 
1475                         $("script").each(function () { 
 
1476                                 if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)) { 
 
1477                                         $.jstree._themes = this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/, "") + 'themes/'; 
 
1482                 if($.jstree._themes === false) { $.jstree._themes = "themes/"; }
 
1484         // include the themes plugin by default
 
1485         $.jstree.defaults.plugins.push("themes");
 
1490  * jsTree hotkeys plugin
 
1491  * Enables keyboard navigation for all tree instances
 
1492  * Depends on the jstree ui & jquery hotkeys plugins
 
1496         function exec(i, event) {
 
1497                 var f = $.jstree._focused(), tmp;
 
1498                 if(f && f.data && f.data.hotkeys && f.data.hotkeys.enabled) { 
 
1499                         tmp = f._get_settings().hotkeys[i];
 
1500                         if(tmp) { return tmp.call(f, event); }
 
1503         $.jstree.plugin("hotkeys", {
 
1504                 __init : function () {
 
1505                         if(typeof $.hotkeys === "undefined") { throw "jsTree hotkeys: jQuery hotkeys plugin not included."; }
 
1506                         if(!this.data.ui) { throw "jsTree hotkeys: jsTree UI plugin not included."; }
 
1507                         $.each(this._get_settings().hotkeys, function (i, v) {
 
1508                                 if(v !== false && $.inArray(i, bound) == -1) {
 
1509                                         $(document).bind("keydown", i, function (event) { return exec(i, event); });
 
1513                         this.get_container()
 
1514                                 .bind("lock.jstree", $.proxy(function () {
 
1515                                                 if(this.data.hotkeys.enabled) { this.data.hotkeys.enabled = false; this.data.hotkeys.revert = true; }
 
1517                                 .bind("unlock.jstree", $.proxy(function () {
 
1518                                                 if(this.data.hotkeys.revert) { this.data.hotkeys.enabled = true; }
 
1520                         this.enable_hotkeys();
 
1523                         "up" : function () { 
 
1524                                 var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
 
1525                                 this.hover_node(this._get_prev(o));
 
1528                         "ctrl+up" : function () { 
 
1529                                 var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
 
1530                                 this.hover_node(this._get_prev(o));
 
1533                         "shift+up" : function () { 
 
1534                                 var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
 
1535                                 this.hover_node(this._get_prev(o));
 
1538                         "down" : function () { 
 
1539                                 var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
 
1540                                 this.hover_node(this._get_next(o));
 
1543                         "ctrl+down" : function () { 
 
1544                                 var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
 
1545                                 this.hover_node(this._get_next(o));
 
1548                         "shift+down" : function () { 
 
1549                                 var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
 
1550                                 this.hover_node(this._get_next(o));
 
1553                         "left" : function () { 
 
1554                                 var o = this.data.ui.hovered || this.data.ui.last_selected;
 
1556                                         if(o.hasClass("jstree-open")) { this.close_node(o); }
 
1557                                         else { this.hover_node(this._get_prev(o)); }
 
1561                         "ctrl+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                         "shift+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                         "right" : function () { 
 
1578                                 var o = this.data.ui.hovered || this.data.ui.last_selected;
 
1580                                         if(o.hasClass("jstree-closed")) { this.open_node(o); }
 
1581                                         else { this.hover_node(this._get_next(o)); }
 
1585                         "ctrl+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                         "shift+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                         "space" : function () { 
 
1602                                 if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").click(); } 
 
1605                         "ctrl+space" : function (event) { 
 
1606                                 event.type = "click";
 
1607                                 if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } 
 
1610                         "shift+space" : function (event) { 
 
1611                                 event.type = "click";
 
1612                                 if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } 
 
1615                         "f2" : function () { this.rename(this.data.ui.hovered || this.data.ui.last_selected); },
 
1616                         "del" : function () { this.remove(this.data.ui.hovered || this._get_node(null)); }
 
1619                         enable_hotkeys : function () {
 
1620                                 this.data.hotkeys.enabled = true;
 
1622                         disable_hotkeys : function () {
 
1623                                 this.data.hotkeys.enabled = false;
 
1631  * jsTree JSON plugin
 
1632  * The JSON data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions.
 
1635         $.jstree.plugin("json_data", {
 
1636                 __init : function() {
 
1637                         var s = this._get_settings().json_data;
 
1638                         if(s.progressive_unload) {
 
1639                                 this.get_container().bind("after_close.jstree", function (e, data) {
 
1640                                         data.rslt.obj.children("ul").remove();
 
1645                         // `data` can be a function:
 
1646                         //  * accepts two arguments - node being loaded and a callback to pass the result to
 
1647                         //  * will be executed in the current tree's scope & ajax won't be supported
 
1650                         correct_state : true,
 
1651                         progressive_render : false,
 
1652                         progressive_unload : false
 
1655                         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); },
 
1656                         _is_loaded : function (obj) { 
 
1657                                 var s = this._get_settings().json_data;
 
1658                                 obj = this._get_node(obj); 
 
1659                                 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;
 
1661                         refresh : function (obj) {
 
1662                                 obj = this._get_node(obj);
 
1663                                 var s = this._get_settings().json_data;
 
1664                                 if(obj && obj !== -1 && s.progressive_unload && ($.isFunction(s.data) || !!s.ajax)) {
 
1665                                         obj.removeData("jstree_children");
 
1667                                 return this.__call_old();
 
1669                         load_node_json : function (obj, s_call, e_call) {
 
1670                                 var s = this.get_settings().json_data, d,
 
1671                                         error_func = function () {},
 
1672                                         success_func = function () {};
 
1673                                 obj = this._get_node(obj);
 
1675                                 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")) {
 
1676                                         d = this._parse_json(obj.data("jstree_children"), obj);
 
1679                                                 if(!s.progressive_unload) { obj.removeData("jstree_children"); }
 
1681                                         this.clean_node(obj);
 
1682                                         if(s_call) { s_call.call(this); }
 
1686                                 if(obj && obj !== -1) {
 
1687                                         if(obj.data("jstree_is_loading")) { return; }
 
1688                                         else { obj.data("jstree_is_loading",true); }
 
1691                                         case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied.";
 
1692                                         // function option added here for easier model integration (also supporting async - see callback)
 
1693                                         case ($.isFunction(s.data)):
 
1694                                                 s.data.call(this, obj, $.proxy(function (d) {
 
1695                                                         d = this._parse_json(d, obj);
 
1697                                                                 if(obj === -1 || !obj) {
 
1698                                                                         if(s.correct_state) { this.get_container().children("ul").empty(); }
 
1701                                                                         obj.children("a.jstree-loading").removeClass("jstree-loading");
 
1702                                                                         obj.removeData("jstree_is_loading");
 
1703                                                                         if(s.correct_state) { this.correct_state(obj); }
 
1705                                                                 if(e_call) { e_call.call(this); }
 
1708                                                                 if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); }
 
1709                                                                 else { obj.append(d).children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree_is_loading"); }
 
1710                                                                 this.clean_node(obj);
 
1711                                                                 if(s_call) { s_call.call(this); }
 
1715                                         case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
 
1716                                                 if(!obj || obj == -1) {
 
1717                                                         d = this._parse_json(s.data, obj);
 
1719                                                                 this.get_container().children("ul").empty().append(d.children());
 
1723                                                                 if(s.correct_state) { this.get_container().children("ul").empty(); }
 
1726                                                 if(s_call) { s_call.call(this); }
 
1728                                         case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
 
1729                                                 error_func = function (x, t, e) {
 
1730                                                         var ef = this.get_settings().json_data.ajax.error; 
 
1731                                                         if(ef) { ef.call(this, x, t, e); }
 
1732                                                         if(obj != -1 && obj.length) {
 
1733                                                                 obj.children("a.jstree-loading").removeClass("jstree-loading");
 
1734                                                                 obj.removeData("jstree_is_loading");
 
1735                                                                 if(t === "success" && s.correct_state) { this.correct_state(obj); }
 
1738                                                                 if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); }
 
1740                                                         if(e_call) { e_call.call(this); }
 
1742                                                 success_func = function (d, t, x) {
 
1743                                                         var sf = this.get_settings().json_data.ajax.success; 
 
1744                                                         if(sf) { d = sf.call(this,d,t,x) || d; }
 
1745                                                         if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "") || (!$.isArray(d) && !$.isPlainObject(d))) {
 
1746                                                                 return error_func.call(this, x, t, "");
 
1748                                                         d = this._parse_json(d, obj);
 
1750                                                                 if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); }
 
1751                                                                 else { obj.append(d).children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree_is_loading"); }
 
1752                                                                 this.clean_node(obj);
 
1753                                                                 if(s_call) { s_call.call(this); }
 
1756                                                                 if(obj === -1 || !obj) {
 
1757                                                                         if(s.correct_state) { 
 
1758                                                                                 this.get_container().children("ul").empty(); 
 
1759                                                                                 if(s_call) { s_call.call(this); }
 
1763                                                                         obj.children("a.jstree-loading").removeClass("jstree-loading");
 
1764                                                                         obj.removeData("jstree_is_loading");
 
1765                                                                         if(s.correct_state) { 
 
1766                                                                                 this.correct_state(obj);
 
1767                                                                                 if(s_call) { s_call.call(this); } 
 
1772                                                 s.ajax.context = this;
 
1773                                                 s.ajax.error = error_func;
 
1774                                                 s.ajax.success = success_func;
 
1775                                                 if(!s.ajax.dataType) { s.ajax.dataType = "json"; }
 
1776                                                 if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); }
 
1777                                                 if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
 
1782                         _parse_json : function (js, obj, is_callback) {
 
1784                                         p = this._get_settings(),
 
1786                                         t = p.core.html_titles,
 
1787                                         tmp, i, j, ul1, ul2;
 
1789                                 if(!js) { return d; }
 
1790                                 if(s.progressive_unload && obj && obj !== -1) { 
 
1791                                         obj.data("jstree_children", d);
 
1795                                         if(!js.length) { return false; }
 
1796                                         for(i = 0, j = js.length; i < j; i++) {
 
1797                                                 tmp = this._parse_json(js[i], obj, true);
 
1805                                         if(typeof js == "string") { js = { data : js }; }
 
1806                                         if(!js.data && js.data !== "") { return d; }
 
1808                                         if(js.attr) { d.attr(js.attr); }
 
1809                                         if(js.metadata) { d.data(js.metadata); }
 
1810                                         if(js.state) { d.addClass("jstree-" + js.state); }
 
1811                                         if(!$.isArray(js.data)) { tmp = js.data; js.data = []; js.data.push(tmp); }
 
1812                                         $.each(js.data, function (i, m) {
 
1814                                                 if($.isFunction(m)) { m = m.call(this, js); }
 
1815                                                 if(typeof m == "string") { tmp.attr('href','#')[ t ? "html" : "text" ](m); }
 
1817                                                         if(!m.attr) { m.attr = {}; }
 
1818                                                         if(!m.attr.href) { m.attr.href = '#'; }
 
1819                                                         tmp.attr(m.attr)[ t ? "html" : "text" ](m.title);
 
1820                                                         if(m.language) { tmp.addClass(m.language); }
 
1822                                                 tmp.prepend("<ins class='jstree-icon'> </ins>");
 
1823                                                 if(!m.icon && js.icon) { m.icon = js.icon; }
 
1825                                                         if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); }
 
1826                                                         else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat"); }
 
1830                                         d.prepend("<ins class='jstree-icon'> </ins>");
 
1832                                                 if(s.progressive_render && js.state !== "open") {
 
1833                                                         d.addClass("jstree-closed").data("jstree_children", js.children);
 
1836                                                         if(s.progressive_unload) { d.data("jstree_children", js.children); }
 
1837                                                         if($.isArray(js.children) && js.children.length) {
 
1838                                                                 tmp = this._parse_json(js.children, obj, true);
 
1855                         get_json : function (obj, li_attr, a_attr, is_callback) {
 
1857                                         s = this._get_settings(), 
 
1859                                         tmp1, tmp2, li, a, t, lang;
 
1860                                 obj = this._get_node(obj);
 
1861                                 if(!obj || obj === -1) { obj = this.get_container().find("> ul > li"); }
 
1862                                 li_attr = $.isArray(li_attr) ? li_attr : [ "id", "class" ];
 
1863                                 if(!is_callback && this.data.types) { li_attr.push(s.types.type_attr); }
 
1864                                 a_attr = $.isArray(a_attr) ? a_attr : [ ];
 
1866                                 obj.each(function () {
 
1868                                         tmp1 = { data : [] };
 
1869                                         if(li_attr.length) { tmp1.attr = { }; }
 
1870                                         $.each(li_attr, function (i, v) { 
 
1872                                                 if(tmp2 && tmp2.length && tmp2.replace(/jstree[^ ]*/ig,'').length) {
 
1873                                                         tmp1.attr[v] = (" " + tmp2).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,""); 
 
1876                                         if(li.hasClass("jstree-open")) { tmp1.state = "open"; }
 
1877                                         if(li.hasClass("jstree-closed")) { tmp1.state = "closed"; }
 
1878                                         if(li.data()) { tmp1.metadata = li.data(); }
 
1879                                         a = li.children("a");
 
1880                                         a.each(function () {
 
1884                                                         $.inArray("languages", s.plugins) !== -1 || 
 
1885                                                         t.children("ins").get(0).style.backgroundImage.length || 
 
1886                                                         (t.children("ins").get(0).className && t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').length)
 
1889                                                         if($.inArray("languages", s.plugins) !== -1 && $.isArray(s.languages) && s.languages.length) {
 
1890                                                                 $.each(s.languages, function (l, lv) {
 
1891                                                                         if(t.hasClass(lv)) {
 
1897                                                         tmp2 = { attr : { }, title : _this.get_text(t, lang) }; 
 
1898                                                         $.each(a_attr, function (k, z) {
 
1899                                                                 tmp2.attr[z] = (" " + (t.attr(z) || "")).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"");
 
1901                                                         if($.inArray("languages", s.plugins) !== -1 && $.isArray(s.languages) && s.languages.length) {
 
1902                                                                 $.each(s.languages, function (k, z) {
 
1903                                                                         if(t.hasClass(z)) { tmp2.language = z; return true; }
 
1906                                                         if(t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length) {
 
1907                                                                 tmp2.icon = t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"");
 
1909                                                         if(t.children("ins").get(0).style.backgroundImage.length) {
 
1910                                                                 tmp2.icon = t.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","");
 
1914                                                         tmp2 = _this.get_text(t);
 
1916                                                 if(a.length > 1) { tmp1.data.push(tmp2); }
 
1917                                                 else { tmp1.data = tmp2; }
 
1919                                         li = li.find("> ul > li");
 
1920                                         if(li.length) { tmp1.children = _this.get_json(li, li_attr, a_attr, true); }
 
1931  * jsTree languages plugin
 
1932  * Adds support for multiple language versions in one tree
 
1933  * This basically allows for many titles coexisting in one node, but only one of them being visible at any given time
 
1934  * This is useful for maintaining the same structure in many languages (hence the name of the plugin)
 
1938         $.jstree.plugin("languages", {
 
1939                 __init : function () { this._load_css();  },
 
1942                         set_lang : function (i) { 
 
1943                                 var langs = this._get_settings().languages,
 
1945                                         selector = ".jstree-" + this.get_index() + ' a';
 
1946                                 if(!$.isArray(langs) || langs.length === 0) { return false; }
 
1947                                 if($.inArray(i,langs) == -1) {
 
1948                                         if(!!langs[i]) { i = langs[i]; }
 
1949                                         else { return false; }
 
1951                                 if(i == this.data.languages.current_language) { return true; }
 
1952                                 st = $.vakata.css.get_css(selector + "." + this.data.languages.current_language, false, sh);
 
1953                                 if(st !== false) { st.style.display = "none"; }
 
1954                                 st = $.vakata.css.get_css(selector + "." + i, false, sh);
 
1955                                 if(st !== false) { st.style.display = ""; }
 
1956                                 this.data.languages.current_language = i;
 
1960                         get_lang : function () {
 
1961                                 return this.data.languages.current_language;
 
1963                         _get_string : function (key, lang) {
 
1964                                 var langs = this._get_settings().languages,
 
1965                                         s = this._get_settings().core.strings;
 
1966                                 if($.isArray(langs) && langs.length) {
 
1967                                         lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language;
 
1969                                 if(s[lang] && s[lang][key]) { return s[lang][key]; }
 
1970                                 if(s[key]) { return s[key]; }
 
1973                         get_text : function (obj, lang) {
 
1974                                 obj = this._get_node(obj) || this.data.ui.last_selected;
 
1975                                 if(!obj.size()) { return false; }
 
1976                                 var langs = this._get_settings().languages,
 
1977                                         s = this._get_settings().core.html_titles;
 
1978                                 if($.isArray(langs) && langs.length) {
 
1979                                         lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language;
 
1980                                         obj = obj.children("a." + lang);
 
1982                                 else { obj = obj.children("a:eq(0)"); }
 
1985                                         obj.children("INS").remove();
 
1989                                         obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
 
1990                                         return obj.nodeValue;
 
1993                         set_text : function (obj, val, lang) {
 
1994                                 obj = this._get_node(obj) || this.data.ui.last_selected;
 
1995                                 if(!obj.size()) { return false; }
 
1996                                 var langs = this._get_settings().languages,
 
1997                                         s = this._get_settings().core.html_titles,
 
1999                                 if($.isArray(langs) && langs.length) {
 
2000                                         lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language;
 
2001                                         obj = obj.children("a." + lang);
 
2003                                 else { obj = obj.children("a:eq(0)"); }
 
2005                                         tmp = obj.children("INS").clone();
 
2006                                         obj.html(val).prepend(tmp);
 
2007                                         this.__callback({ "obj" : obj, "name" : val, "lang" : lang });
 
2011                                         obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
 
2012                                         this.__callback({ "obj" : obj, "name" : val, "lang" : lang });
 
2013                                         return (obj.nodeValue = val);
 
2016                         _load_css : function () {
 
2017                                 var langs = this._get_settings().languages,
 
2018                                         str = "/* languages css */",
 
2019                                         selector = ".jstree-" + this.get_index() + ' a',
 
2021                                 if($.isArray(langs) && langs.length) {
 
2022                                         this.data.languages.current_language = langs[0];
 
2023                                         for(ln = 0; ln < langs.length; ln++) {
 
2024                                                 str += selector + "." + langs[ln] + " {";
 
2025                                                 if(langs[ln] != this.data.languages.current_language) { str += " display:none; "; }
 
2028                                         sh = $.vakata.css.add_sheet({ 'str' : str, 'title' : "jstree-languages" });
 
2031                         create_node : function (obj, position, js, callback) {
 
2032                                 var t = this.__call_old(true, obj, position, js, function (t) {
 
2033                                         var langs = this._get_settings().languages,
 
2034                                                 a = t.children("a"),
 
2036                                         if($.isArray(langs) && langs.length) {
 
2037                                                 for(ln = 0; ln < langs.length; ln++) {
 
2038                                                         if(!a.is("." + langs[ln])) {
 
2039                                                                 t.append(a.eq(0).clone().removeClass(langs.join(" ")).addClass(langs[ln]));
 
2042                                                 a.not("." + langs.join(", .")).remove();
 
2044                                         if(callback) { callback.call(this, t); }
 
2054  * jsTree cookies plugin
 
2055  * Stores the currently opened/selected nodes in a cookie and then restores them
 
2056  * Depends on the jquery.cookie plugin
 
2059         $.jstree.plugin("cookies", {
 
2060                 __init : function () {
 
2061                         if(typeof $.cookie === "undefined") { throw "jsTree cookie: jQuery cookie plugin not included."; }
 
2063                         var s = this._get_settings().cookies,
 
2065                         if(!!s.save_loaded) {
 
2066                                 tmp = $.cookie(s.save_loaded);
 
2067                                 if(tmp && tmp.length) { this.data.core.to_load = tmp.split(","); }
 
2069                         if(!!s.save_opened) {
 
2070                                 tmp = $.cookie(s.save_opened);
 
2071                                 if(tmp && tmp.length) { this.data.core.to_open = tmp.split(","); }
 
2073                         if(!!s.save_selected) {
 
2074                                 tmp = $.cookie(s.save_selected);
 
2075                                 if(tmp && tmp.length && this.data.ui) { this.data.ui.to_select = tmp.split(","); }
 
2077                         this.get_container()
 
2078                                 .one( ( this.data.ui ? "reselect" : "reopen" ) + ".jstree", $.proxy(function () {
 
2079                                         this.get_container()
 
2080                                                 .bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree", $.proxy(function (e) { 
 
2081                                                                 if(this._get_settings().cookies.auto_save) { this.save_cookie((e.handleObj.namespace + e.handleObj.type).replace("jstree","")); }
 
2086                         save_loaded             : "jstree_load",
 
2087                         save_opened             : "jstree_open",
 
2088                         save_selected   : "jstree_select",
 
2093                         save_cookie : function (c) {
 
2094                                 if(this.data.core.refreshing) { return; }
 
2095                                 var s = this._get_settings().cookies;
 
2096                                 if(!c) { // if called manually and not by event
 
2099                                                 $.cookie(s.save_loaded, this.data.core.to_load.join(","), s.cookie_options);
 
2103                                                 $.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options);
 
2105                                         if(s.save_selected && this.data.ui) {
 
2106                                                 this.save_selected();
 
2107                                                 $.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options);
 
2114                                                 if(!!s.save_opened) { 
 
2116                                                         $.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options); 
 
2118                                                 if(!!s.save_loaded) { 
 
2120                                                         $.cookie(s.save_loaded, this.data.core.to_load.join(","), s.cookie_options); 
 
2124                                         case "deselect_node":
 
2125                                                 if(!!s.save_selected && this.data.ui) { 
 
2126                                                         this.save_selected(); 
 
2127                                                         $.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options); 
 
2134         // include cookies by default
 
2135         // $.jstree.defaults.plugins.push("cookies");
 
2140  * jsTree sort plugin
 
2141  * Sorts items alphabetically (or using any other function)
 
2144         $.jstree.plugin("sort", {
 
2145                 __init : function () {
 
2146                         this.get_container()
 
2147                                 .bind("load_node.jstree", $.proxy(function (e, data) {
 
2148                                                 var obj = this._get_node(data.rslt.obj);
 
2149                                                 obj = obj === -1 ? this.get_container().children("ul") : obj.children("ul");
 
2152                                 .bind("rename_node.jstree create_node.jstree create.jstree", $.proxy(function (e, data) {
 
2153                                                 this.sort(data.rslt.obj.parent());
 
2155                                 .bind("move_node.jstree", $.proxy(function (e, data) {
 
2156                                                 var m = data.rslt.np == -1 ? this.get_container() : data.rslt.np;
 
2157                                                 this.sort(m.children("ul"));
 
2160                 defaults : function (a, b) { return this.get_text(a) > this.get_text(b) ? 1 : -1; },
 
2162                         sort : function (obj) {
 
2163                                 var s = this._get_settings().sort,
 
2165                                 obj.append($.makeArray(obj.children("li")).sort($.proxy(s, t)));
 
2166                                 obj.find("> li > ul").each(function() { t.sort($(this)); });
 
2167                                 this.clean_node(obj);
 
2176  * Drag and drop plugin for moving/copying nodes
 
2200                 drag_start : function (e, data, html) { 
 
2201                         if($.vakata.dnd.is_drag) { $.vakata.drag_stop({}); }
 
2203                                 e.currentTarget.unselectable = "on";
 
2204                                 e.currentTarget.onselectstart = function() { return false; };
 
2205                                 if(e.currentTarget.style) { e.currentTarget.style.MozUserSelect = "none"; }
 
2207                         $.vakata.dnd.init_x = e.pageX;
 
2208                         $.vakata.dnd.init_y = e.pageY;
 
2209                         $.vakata.dnd.user_data = data;
 
2210                         $.vakata.dnd.is_down = true;
 
2211                         $.vakata.dnd.helper = $("<div id='vakata-dragged' />").html(html); //.fadeTo(10,0.25);
 
2212                         $(document).bind("mousemove", $.vakata.dnd.drag);
 
2213                         $(document).bind("mouseup", $.vakata.dnd.drag_stop);
 
2216                 drag : function (e) { 
 
2217                         if(!$.vakata.dnd.is_down) { return; }
 
2218                         if(!$.vakata.dnd.is_drag) {
 
2219                                 if(Math.abs(e.pageX - $.vakata.dnd.init_x) > 5 || Math.abs(e.pageY - $.vakata.dnd.init_y) > 5) { 
 
2220                                         $.vakata.dnd.helper.appendTo("body");
 
2221                                         $.vakata.dnd.is_drag = true;
 
2222                                         $(document).triggerHandler("drag_start.vakata", { "event" : e, "data" : $.vakata.dnd.user_data });
 
2227                         // maybe use a scrolling parent element instead of document?
 
2228                         if(e.type === "mousemove") { // thought of adding scroll in order to move the helper, but mouse poisition is n/a
 
2229                                 var d = $(document), t = d.scrollTop(), l = d.scrollLeft();
 
2230                                 if(e.pageY - t < 20) { 
 
2231                                         if(sti && dir1 === "down") { clearInterval(sti); sti = false; }
 
2232                                         if(!sti) { dir1 = "up"; sti = setInterval(function () { $(document).scrollTop($(document).scrollTop() - $.vakata.dnd.scroll_spd); }, 150); }
 
2235                                         if(sti && dir1 === "up") { clearInterval(sti); sti = false; }
 
2237                                 if($(window).height() - (e.pageY - t) < 20) {
 
2238                                         if(sti && dir1 === "up") { clearInterval(sti); sti = false; }
 
2239                                         if(!sti) { dir1 = "down"; sti = setInterval(function () { $(document).scrollTop($(document).scrollTop() + $.vakata.dnd.scroll_spd); }, 150); }
 
2242                                         if(sti && dir1 === "down") { clearInterval(sti); sti = false; }
 
2245                                 if(e.pageX - l < 20) {
 
2246                                         if(sli && dir2 === "right") { clearInterval(sli); sli = false; }
 
2247                                         if(!sli) { dir2 = "left"; sli = setInterval(function () { $(document).scrollLeft($(document).scrollLeft() - $.vakata.dnd.scroll_spd); }, 150); }
 
2250                                         if(sli && dir2 === "left") { clearInterval(sli); sli = false; }
 
2252                                 if($(window).width() - (e.pageX - l) < 20) {
 
2253                                         if(sli && dir2 === "left") { clearInterval(sli); sli = false; }
 
2254                                         if(!sli) { dir2 = "right"; sli = setInterval(function () { $(document).scrollLeft($(document).scrollLeft() + $.vakata.dnd.scroll_spd); }, 150); }
 
2257                                         if(sli && dir2 === "right") { clearInterval(sli); sli = false; }
 
2261                         $.vakata.dnd.helper.css({ left : (e.pageX + $.vakata.dnd.helper_left) + "px", top : (e.pageY + $.vakata.dnd.helper_top) + "px" });
 
2262                         $(document).triggerHandler("drag.vakata", { "event" : e, "data" : $.vakata.dnd.user_data });
 
2264                 drag_stop : function (e) {
 
2265                         if(sli) { clearInterval(sli); }
 
2266                         if(sti) { clearInterval(sti); }
 
2267                         $(document).unbind("mousemove", $.vakata.dnd.drag);
 
2268                         $(document).unbind("mouseup", $.vakata.dnd.drag_stop);
 
2269                         $(document).triggerHandler("drag_stop.vakata", { "event" : e, "data" : $.vakata.dnd.user_data });
 
2270                         $.vakata.dnd.helper.remove();
 
2271                         $.vakata.dnd.init_x = 0;
 
2272                         $.vakata.dnd.init_y = 0;
 
2273                         $.vakata.dnd.user_data = {};
 
2274                         $.vakata.dnd.is_down = false;
 
2275                         $.vakata.dnd.is_drag = false;
 
2279                 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; } ';
 
2280                 $.vakata.css.add_sheet({ str : css_string, title : "vakata" });
 
2283         $.jstree.plugin("dnd", {
 
2284                 __init : function () {
 
2302                         this.get_container()
 
2303                                 .bind("mouseenter.jstree", $.proxy(function (e) {
 
2304                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
 
2305                                                         if(this.data.themes) {
 
2306                                                                 m.attr("class", "jstree-" + this.data.themes.theme); 
 
2307                                                                 if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); }
 
2308                                                                 $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme);
 
2310                                                         //if($(e.currentTarget).find("> ul > li").length === 0) {
 
2311                                                         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
 
2312                                                                 var tr = $.jstree._reference(e.target), dc;
 
2313                                                                 if(tr.data.dnd.foreign) {
 
2314                                                                         dc = tr._get_settings().dnd.drag_check.call(this, { "o" : o, "r" : tr.get_container(), is_root : true });
 
2315                                                                         if(dc === true || dc.inside === true || dc.before === true || dc.after === true) {
 
2316                                                                                 $.vakata.dnd.helper.children("ins").attr("class","jstree-ok");
 
2320                                                                         tr.prepare_move(o, tr.get_container(), "last");
 
2321                                                                         if(tr.check_move()) {
 
2322                                                                                 $.vakata.dnd.helper.children("ins").attr("class","jstree-ok");
 
2328                                 .bind("mouseup.jstree", $.proxy(function (e) {
 
2329                                                 //if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && $(e.currentTarget).find("> ul > li").length === 0) {
 
2330                                                 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
 
2331                                                         var tr = $.jstree._reference(e.currentTarget), dc;
 
2332                                                         if(tr.data.dnd.foreign) {
 
2333                                                                 dc = tr._get_settings().dnd.drag_check.call(this, { "o" : o, "r" : tr.get_container(), is_root : true });
 
2334                                                                 if(dc === true || dc.inside === true || dc.before === true || dc.after === true) {
 
2335                                                                         tr._get_settings().dnd.drag_finish.call(this, { "o" : o, "r" : tr.get_container(), is_root : true });
 
2339                                                                 tr.move_node(o, tr.get_container(), "last", e[tr._get_settings().dnd.copy_modifier + "Key"]);
 
2343                                 .bind("mouseleave.jstree", $.proxy(function (e) {
 
2344                                                 if(e.relatedTarget && e.relatedTarget.id && e.relatedTarget.id === "jstree-marker-line") {
 
2347                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
 
2348                                                         if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
 
2349                                                         if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
 
2350                                                         if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); }
 
2351                                                         if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); }
 
2352                                                         if($.vakata.dnd.helper.children("ins").hasClass("jstree-ok")) {
 
2353                                                                 $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
 
2357                                 .bind("mousemove.jstree", $.proxy(function (e) {
 
2358                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
 
2359                                                         var cnt = this.get_container()[0];
 
2361                                                         // Horizontal scroll
 
2362                                                         if(e.pageX + 24 > this.data.dnd.cof.left + this.data.dnd.cw) {
 
2363                                                                 if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
 
2364                                                                 this.data.dnd.i1 = setInterval($.proxy(function () { this.scrollLeft += $.vakata.dnd.scroll_spd; }, cnt), 100);
 
2366                                                         else if(e.pageX - 24 < this.data.dnd.cof.left) {
 
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);
 
2371                                                                 if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
 
2375                                                         if(e.pageY + 24 > this.data.dnd.cof.top + this.data.dnd.ch) {
 
2376                                                                 if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
 
2377                                                                 this.data.dnd.i2 = setInterval($.proxy(function () { this.scrollTop += $.vakata.dnd.scroll_spd; }, cnt), 100);
 
2379                                                         else if(e.pageY - 24 < this.data.dnd.cof.top) {
 
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);
 
2384                                                                 if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
 
2389                                 .bind("scroll.jstree", $.proxy(function (e) { 
 
2390                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && m && ml) {
 
2395                                 .delegate("a", "mousedown.jstree", $.proxy(function (e) { 
 
2397                                                         this.start_drag(e.currentTarget, e);
 
2401                                 .delegate("a", "mouseenter.jstree", $.proxy(function (e) { 
 
2402                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
 
2403                                                         this.dnd_enter(e.currentTarget);
 
2406                                 .delegate("a", "mousemove.jstree", $.proxy(function (e) { 
 
2407                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
 
2408                                                         if(!r || !r.length || r.children("a")[0] !== e.currentTarget) {
 
2409                                                                 this.dnd_enter(e.currentTarget);
 
2411                                                         if(typeof this.data.dnd.off.top === "undefined") { this.data.dnd.off = $(e.target).offset(); }
 
2412                                                         this.data.dnd.w = (e.pageY - (this.data.dnd.off.top || 0)) % this.data.core.li_height;
 
2413                                                         if(this.data.dnd.w < 0) { this.data.dnd.w += this.data.core.li_height; }
 
2417                                 .delegate("a", "mouseleave.jstree", $.proxy(function (e) { 
 
2418                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
 
2419                                                         if(e.relatedTarget && e.relatedTarget.id && e.relatedTarget.id === "jstree-marker-line") {
 
2423                                                                 if(ml) { ml.hide(); }
 
2425                                                         var ec = $(e.currentTarget).closest("li"), 
 
2426                                                                 er = $(e.relatedTarget).closest("li");
 
2427                                                         if(er[0] !== ec.prev()[0] && er[0] !== ec.next()[0]) {
 
2429                                                                 if(ml) { ml.hide(); }
 
2432                                                         this.data.dnd.mto = setTimeout( 
 
2433                                                                 (function (t) { return function () { t.dnd_leave(e); }; })(this),
 
2437                                 .delegate("a", "mouseup.jstree", $.proxy(function (e) { 
 
2438                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
 
2444                                 .bind("drag_stop.vakata", $.proxy(function () {
 
2445                                                 if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); }
 
2446                                                 if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); }
 
2447                                                 if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
 
2448                                                 if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
 
2449                                                 this.data.dnd.after             = false;
 
2450                                                 this.data.dnd.before    = false;
 
2451                                                 this.data.dnd.inside    = false;
 
2452                                                 this.data.dnd.off               = false;
 
2453                                                 this.data.dnd.prepared  = false;
 
2454                                                 this.data.dnd.w                 = false;
 
2455                                                 this.data.dnd.to1               = false;
 
2456                                                 this.data.dnd.to2               = false;
 
2457                                                 this.data.dnd.i1                = false;
 
2458                                                 this.data.dnd.i2                = false;
 
2459                                                 this.data.dnd.active    = false;
 
2460                                                 this.data.dnd.foreign   = false;
 
2461                                                 if(m) { m.css({ "top" : "-2000px" }); }
 
2462                                                 if(ml) { ml.css({ "top" : "-2000px" }); }
 
2464                                 .bind("drag_start.vakata", $.proxy(function (e, data) {
 
2465                                                 if(data.data.jstree) { 
 
2466                                                         var et = $(data.event.target);
 
2467                                                         if(et.closest(".jstree").hasClass("jstree-" + this.get_index())) {
 
2473                                 .bind("keydown.jstree-" + this.get_index() + " keyup.jstree-" + this.get_index(), $.proxy(function(e) {
 
2474                                                 if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && !this.data.dnd.foreign) {
 
2475                                                         var h = $.vakata.dnd.helper.children("ins");
 
2476                                                         if(e[this._get_settings().dnd.copy_modifier + "Key"] && h.hasClass("jstree-ok")) {
 
2477                                                                 h.parent().html(h.parent().html().replace(/ \(Copy\)$/, "") + " (Copy)");
 
2480                                                                 h.parent().html(h.parent().html().replace(/ \(Copy\)$/, ""));
 
2487                         var s = this._get_settings().dnd;
 
2490                                         .delegate(s.drag_target, "mousedown.jstree-" + this.get_index(), $.proxy(function (e) {
 
2492                                                 $.vakata.dnd.drag_start(e, { jstree : true, obj : e.target }, "<ins class='jstree-icon'></ins>" + $(e.target).text() );
 
2493                                                 if(this.data.themes) { 
 
2494                                                         if(m) { m.attr("class", "jstree-" + this.data.themes.theme); }
 
2495                                                         if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); }
 
2496                                                         $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); 
 
2498                                                 $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
 
2499                                                 var cnt = this.get_container();
 
2500                                                 this.data.dnd.cof = cnt.offset();
 
2501                                                 this.data.dnd.cw = parseInt(cnt.width(),10);
 
2502                                                 this.data.dnd.ch = parseInt(cnt.height(),10);
 
2503                                                 this.data.dnd.foreign = true;
 
2509                                         .delegate(s.drop_target, "mouseenter.jstree-" + this.get_index(), $.proxy(function (e) {
 
2510                                                         if(this.data.dnd.active && this._get_settings().dnd.drop_check.call(this, { "o" : o, "r" : $(e.target), "e" : e })) {
 
2511                                                                 $.vakata.dnd.helper.children("ins").attr("class","jstree-ok");
 
2514                                         .delegate(s.drop_target, "mouseleave.jstree-" + this.get_index(), $.proxy(function (e) {
 
2515                                                         if(this.data.dnd.active) {
 
2516                                                                 $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
 
2519                                         .delegate(s.drop_target, "mouseup.jstree-" + this.get_index(), $.proxy(function (e) {
 
2520                                                         if(this.data.dnd.active && $.vakata.dnd.helper.children("ins").hasClass("jstree-ok")) {
 
2521                                                                 this._get_settings().dnd.drop_finish.call(this, { "o" : o, "r" : $(e.target), "e" : e });
 
2527                         copy_modifier   : "ctrl",
 
2528                         check_timeout   : 100,
 
2530                         drop_target             : ".jstree-drop",
 
2531                         drop_check              : function (data) { return true; },
 
2532                         drop_finish             : $.noop,
 
2533                         drag_target             : ".jstree-draggable",
 
2534                         drag_finish             : $.noop,
 
2535                         drag_check              : function (data) { return { after : false, before : false, inside : true }; }
 
2538                         dnd_prepare : function () {
 
2539                                 if(!r || !r.length) { return; }
 
2540                                 this.data.dnd.off = r.offset();
 
2541                                 if(this._get_settings().core.rtl) {
 
2542                                         this.data.dnd.off.right = this.data.dnd.off.left + r.width();
 
2544                                 if(this.data.dnd.foreign) {
 
2545                                         var a = this._get_settings().dnd.drag_check.call(this, { "o" : o, "r" : r });
 
2546                                         this.data.dnd.after = a.after;
 
2547                                         this.data.dnd.before = a.before;
 
2548                                         this.data.dnd.inside = a.inside;
 
2549                                         this.data.dnd.prepared = true;
 
2550                                         return this.dnd_show();
 
2552                                 this.prepare_move(o, r, "before");
 
2553                                 this.data.dnd.before = this.check_move();
 
2554                                 this.prepare_move(o, r, "after");
 
2555                                 this.data.dnd.after = this.check_move();
 
2556                                 if(this._is_loaded(r)) {
 
2557                                         this.prepare_move(o, r, "inside");
 
2558                                         this.data.dnd.inside = this.check_move();
 
2561                                         this.data.dnd.inside = false;
 
2563                                 this.data.dnd.prepared = true;
 
2564                                 return this.dnd_show();
 
2566                         dnd_show : function () {
 
2567                                 if(!this.data.dnd.prepared) { return; }
 
2568                                 var o = ["before","inside","after"],
 
2570                                         rtl = this._get_settings().core.rtl,
 
2572                                 if(this.data.dnd.w < this.data.core.li_height/3) { o = ["before","inside","after"]; }
 
2573                                 else if(this.data.dnd.w <= this.data.core.li_height*2/3) {
 
2574                                         o = this.data.dnd.w < this.data.core.li_height/2 ? ["inside","before","after"] : ["inside","after","before"];
 
2576                                 else { o = ["after","inside","before"]; }
 
2577                                 $.each(o, $.proxy(function (i, val) { 
 
2578                                         if(this.data.dnd[val]) {
 
2579                                                 $.vakata.dnd.helper.children("ins").attr("class","jstree-ok");
 
2584                                 if(r === false) { $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); }
 
2586                                 pos = rtl ? (this.data.dnd.off.right - 18) : (this.data.dnd.off.left + 10);
 
2589                                                 m.css({ "left" : pos + "px", "top" : (this.data.dnd.off.top - 6) + "px" }).show();
 
2590                                                 if(ml) { ml.css({ "left" : (pos + 8) + "px", "top" : (this.data.dnd.off.top - 1) + "px" }).show(); }
 
2593                                                 m.css({ "left" : pos + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height - 6) + "px" }).show();
 
2594                                                 if(ml) { ml.css({ "left" : (pos + 8) + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height - 1) + "px" }).show(); }
 
2597                                                 m.css({ "left" : pos + ( rtl ? -4 : 4) + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height/2 - 5) + "px" }).show();
 
2598                                                 if(ml) { ml.hide(); }
 
2602                                                 if(ml) { ml.hide(); }
 
2608                         dnd_open : function () {
 
2609                                 this.data.dnd.to2 = false;
 
2610                                 this.open_node(r, $.proxy(this.dnd_prepare,this), true);
 
2612                         dnd_finish : function (e) {
 
2613                                 if(this.data.dnd.foreign) {
 
2614                                         if(this.data.dnd.after || this.data.dnd.before || this.data.dnd.inside) {
 
2615                                                 this._get_settings().dnd.drag_finish.call(this, { "o" : o, "r" : r, "p" : last_pos });
 
2620                                         this.move_node(o, r, last_pos, e[this._get_settings().dnd.copy_modifier + "Key"]);
 
2625                                 if(ml) { ml.hide(); }
 
2627                         dnd_enter : function (obj) {
 
2628                                 if(this.data.dnd.mto) { 
 
2629                                         clearTimeout(this.data.dnd.mto);
 
2630                                         this.data.dnd.mto = false;
 
2632                                 var s = this._get_settings().dnd;
 
2633                                 this.data.dnd.prepared = false;
 
2634                                 r = this._get_node(obj);
 
2635                                 if(s.check_timeout) { 
 
2636                                         // do the calculations after a minimal timeout (users tend to drag quickly to the desired location)
 
2637                                         if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); }
 
2638                                         this.data.dnd.to1 = setTimeout($.proxy(this.dnd_prepare, this), s.check_timeout); 
 
2643                                 if(s.open_timeout) { 
 
2644                                         if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); }
 
2645                                         if(r && r.length && r.hasClass("jstree-closed")) { 
 
2646                                                 // if the node is closed - open it, then recalculate
 
2647                                                 this.data.dnd.to2 = setTimeout($.proxy(this.dnd_open, this), s.open_timeout);
 
2651                                         if(r && r.length && r.hasClass("jstree-closed")) { 
 
2656                         dnd_leave : function (e) {
 
2657                                 this.data.dnd.after             = false;
 
2658                                 this.data.dnd.before    = false;
 
2659                                 this.data.dnd.inside    = false;
 
2660                                 $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
 
2662                                 if(ml) { ml.hide(); }
 
2663                                 if(r && r[0] === e.target.parentNode) {
 
2664                                         if(this.data.dnd.to1) {
 
2665                                                 clearTimeout(this.data.dnd.to1);
 
2666                                                 this.data.dnd.to1 = false;
 
2668                                         if(this.data.dnd.to2) {
 
2669                                                 clearTimeout(this.data.dnd.to2);
 
2670                                                 this.data.dnd.to2 = false;
 
2674                         start_drag : function (obj, e) {
 
2675                                 o = this._get_node(obj);
 
2676                                 if(this.data.ui && this.is_selected(o)) { o = this._get_node(null, true); }
 
2677                                 var dt = o.length > 1 ? this._get_string("multiple_selection") : this.get_text(o),
 
2678                                         cnt = this.get_container();
 
2679                                 if(!this._get_settings().core.html_titles) { dt = dt.replace(/</ig,"<").replace(/>/ig,">"); }
 
2680                                 $.vakata.dnd.drag_start(e, { jstree : true, obj : o }, "<ins class='jstree-icon'></ins>" + dt );
 
2681                                 if(this.data.themes) { 
 
2682                                         if(m) { m.attr("class", "jstree-" + this.data.themes.theme); }
 
2683                                         if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); }
 
2684                                         $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); 
 
2686                                 this.data.dnd.cof = cnt.offset();
 
2687                                 this.data.dnd.cw = parseInt(cnt.width(),10);
 
2688                                 this.data.dnd.ch = parseInt(cnt.height(),10);
 
2689                                 this.data.dnd.active = true;
 
2694                 var css_string = '' + 
 
2695                         '#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; ' + 
 
2696                         ' -moz-border-radius:4px; border-radius:4px; -webkit-border-radius:4px; ' +
 
2698                         '#vakata-dragged .jstree-ok { background:green; } ' + 
 
2699                         '#vakata-dragged .jstree-invalid { background:red; } ' + 
 
2700                         '#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; } ' + 
 
2701                         '#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; ' + 
 
2702                         ' 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; ' + 
 
2703                         ' -moz-border-radius:1px; border-radius:1px; -webkit-border-radius:1px; ' +
 
2706                 $.vakata.css.add_sheet({ str : css_string, title : "jstree" });
 
2707                 m = $("<div />").attr({ id : "jstree-marker" }).hide().html("»")
 
2708                         .bind("mouseleave mouseenter", function (e) { 
 
2712                                 e.stopImmediatePropagation(); 
 
2716                 ml = $("<div />").attr({ id : "jstree-marker-line" }).hide()
 
2717                         .bind("mouseup", function (e) { 
 
2719                                         r.children("a").trigger(e); 
 
2721                                         e.stopImmediatePropagation(); 
 
2725                         .bind("mouseleave", function (e) { 
 
2726                                 var rt = $(e.relatedTarget);
 
2727                                 if(rt.is(".jstree") || rt.closest(".jstree").length === 0) {
 
2729                                                 r.children("a").trigger(e); 
 
2733                                                 e.stopImmediatePropagation(); 
 
2739                 $(document).bind("drag_start.vakata", function (e, data) {
 
2740                         if(data.data.jstree) { m.show(); if(ml) { ml.show(); } }
 
2742                 $(document).bind("drag_stop.vakata", function (e, data) {
 
2743                         if(data.data.jstree) { m.hide(); if(ml) { ml.hide(); } }
 
2750  * jsTree checkbox plugin
 
2751  * Inserts checkboxes in front of every node
 
2752  * Depends on the ui plugin
 
2753  * DOES NOT WORK NICELY WITH MULTITREE DRAG'N'DROP
 
2756         $.jstree.plugin("checkbox", {
 
2757                 __init : function () {
 
2758                         this.data.checkbox.noui = this._get_settings().checkbox.override_ui;
 
2759                         if(this.data.ui && this.data.checkbox.noui) {
 
2760                                 this.select_node = this.deselect_node = this.deselect_all = $.noop;
 
2761                                 this.get_selected = this.get_checked;
 
2764                         this.get_container()
 
2765                                 .bind("open_node.jstree create_node.jstree clean_node.jstree refresh.jstree", $.proxy(function (e, data) { 
 
2766                                                 this._prepare_checkboxes(data.rslt.obj);
 
2768                                 .bind("loaded.jstree", $.proxy(function (e) {
 
2769                                                 this._prepare_checkboxes();
 
2771                                 .delegate( (this.data.ui && this.data.checkbox.noui ? "a" : "ins.jstree-checkbox") , "click.jstree", $.proxy(function (e) {
 
2773                                                 if(this._get_node(e.target).hasClass("jstree-checked")) { this.uncheck_node(e.target); }
 
2774                                                 else { this.check_node(e.target); }
 
2775                                                 if(this.data.ui && this.data.checkbox.noui) {
 
2776                                                         this.save_selected();
 
2777                                                         if(this.data.cookies) { this.save_cookie("select_node"); }
 
2780                                                         e.stopImmediatePropagation();
 
2786                         override_ui : false,
 
2788                         real_checkboxes : false,
 
2789                         checked_parent_open : true,
 
2790                         real_checkboxes_names : function (n) { return [ ("check_" + (n[0].id || Math.ceil(Math.random() * 10000))) , 1]; }
 
2792                 __destroy : function () {
 
2793                         this.get_container()
 
2794                                 .find("input.jstree-real-checkbox").removeClass("jstree-real-checkbox").end()
 
2795                                 .find("ins.jstree-checkbox").remove();
 
2798                         _checkbox_notify : function (n, data) {
 
2800                                         this.check_node(n, false);
 
2803                         _prepare_checkboxes : function (obj) {
 
2804                                 obj = !obj || obj == -1 ? this.get_container().find("> ul > li") : this._get_node(obj);
 
2805                                 if(obj === false) { return; } // added for removing root nodes
 
2806                                 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;
 
2807                                 obj.each(function () {
 
2809                                         c = t.is("li") && (t.hasClass("jstree-checked") || (rc && t.children(":checked").length)) ? "jstree-checked" : "jstree-unchecked";
 
2810                                         t.find("li").addBack().each(function () {
 
2811                                                 var $t = $(this), nm;
 
2812                                                 $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 );
 
2814                                                         if(!$t.children(":checkbox").length) {
 
2815                                                                 nm = rcn.call(_this, $t);
 
2816                                                                 $t.prepend("<input type='checkbox' class='jstree-real-checkbox' id='" + nm[0] + "' name='" + nm[0] + "' value='" + nm[1] + "' />");
 
2819                                                                 $t.children(":checkbox").addClass("jstree-real-checkbox");
 
2823                                                         if(c === "jstree-checked" || $t.hasClass("jstree-checked") || $t.children(':checked').length) {
 
2824                                                                 $t.find("li").addBack().addClass("jstree-checked").children(":checkbox").prop("checked", true);
 
2828                                                         if($t.hasClass("jstree-checked") || $t.children(':checked').length) {
 
2829                                                                 $t.addClass("jstree-checked").children(":checkbox").prop("checked", true);
 
2835                                         obj.find(".jstree-checked").parent().parent().each(function () { _this._repair_state(this); }); 
 
2838                         change_state : function (obj, state) {
 
2839                                 obj = this._get_node(obj);
 
2840                                 var coll = false, rc = this._get_settings().checkbox.real_checkboxes;
 
2841                                 if(!obj || obj === -1) { return false; }
 
2842                                 state = (state === false || state === true) ? state : obj.hasClass("jstree-checked");
 
2843                                 if(this._get_settings().checkbox.two_state) {
 
2845                                                 obj.removeClass("jstree-checked").addClass("jstree-unchecked"); 
 
2846                                                 if(rc) { obj.children(":checkbox").prop("checked", false); }
 
2849                                                 obj.removeClass("jstree-unchecked").addClass("jstree-checked"); 
 
2850                                                 if(rc) { obj.children(":checkbox").prop("checked", true); }
 
2855                                                 coll = obj.find("li").addBack();
 
2856                                                 if(!coll.filter(".jstree-checked, .jstree-undetermined").length) { return false; }
 
2857                                                 coll.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked"); 
 
2858                                                 if(rc) { coll.children(":checkbox").prop("checked", false); }
 
2861                                                 coll = obj.find("li").addBack();
 
2862                                                 if(!coll.filter(".jstree-unchecked, .jstree-undetermined").length) { return false; }
 
2863                                                 coll.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked"); 
 
2864                                                 if(rc) { coll.children(":checkbox").prop("checked", true); }
 
2865                                                 if(this.data.ui) { this.data.ui.last_selected = obj; }
 
2866                                                 this.data.checkbox.last_selected = obj;
 
2868                                         obj.parentsUntil(".jstree", "li").each(function () {
 
2869                                                 var $this = $(this);
 
2871                                                         if($this.children("ul").children("li.jstree-checked, li.jstree-undetermined").length) {
 
2872                                                                 $this.parentsUntil(".jstree", "li").addBack().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
 
2873                                                                 if(rc) { $this.parentsUntil(".jstree", "li").addBack().children(":checkbox").prop("checked", false); }
 
2877                                                                 $this.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");
 
2878                                                                 if(rc) { $this.children(":checkbox").prop("checked", false); }
 
2882                                                         if($this.children("ul").children("li.jstree-unchecked, li.jstree-undetermined").length) {
 
2883                                                                 $this.parentsUntil(".jstree", "li").addBack().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
 
2884                                                                 if(rc) { $this.parentsUntil(".jstree", "li").addBack().children(":checkbox").prop("checked", false); }
 
2888                                                                 $this.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");
 
2889                                                                 if(rc) { $this.children(":checkbox").prop("checked", true); }
 
2894                                 if(this.data.ui && this.data.checkbox.noui) { this.data.ui.selected = this.get_checked(); }
 
2895                                 this.__callback(obj);
 
2898                         check_node : function (obj) {
 
2899                                 if(this.change_state(obj, false)) { 
 
2900                                         obj = this._get_node(obj);
 
2901                                         if(this._get_settings().checkbox.checked_parent_open) {
 
2903                                                 obj.parents(".jstree-closed").each(function () { t.open_node(this, false, true); });
 
2905                                         this.__callback({ "obj" : obj }); 
 
2908                         uncheck_node : function (obj) {
 
2909                                 if(this.change_state(obj, true)) { this.__callback({ "obj" : this._get_node(obj) }); }
 
2911                         check_all : function () {
 
2913                                         coll = this._get_settings().checkbox.two_state ? this.get_container_ul().find("li") : this.get_container_ul().children("li");
 
2914                                 coll.each(function () {
 
2915                                         _this.change_state(this, false);
 
2919                         uncheck_all : function () {
 
2921                                         coll = this._get_settings().checkbox.two_state ? this.get_container_ul().find("li") : this.get_container_ul().children("li");
 
2922                                 coll.each(function () {
 
2923                                         _this.change_state(this, true);
 
2928                         is_checked : function(obj) {
 
2929                                 obj = this._get_node(obj);
 
2930                                 return obj.length ? obj.is(".jstree-checked") : false;
 
2932                         get_checked : function (obj, get_all) {
 
2933                                 obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj);
 
2934                                 return get_all || this._get_settings().checkbox.two_state ? obj.find(".jstree-checked") : obj.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked");
 
2936                         get_unchecked : 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-unchecked") : obj.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked");
 
2941                         show_checkboxes : function () { this.get_container().children("ul").removeClass("jstree-no-checkboxes"); },
 
2942                         hide_checkboxes : function () { this.get_container().children("ul").addClass("jstree-no-checkboxes"); },
 
2944                         _repair_state : function (obj) {
 
2945                                 obj = this._get_node(obj);
 
2946                                 if(!obj.length) { return; }
 
2947                                 if(this._get_settings().checkbox.two_state) {
 
2948                                         obj.find('li').addBack().not('.jstree-checked').removeClass('jstree-undetermined').addClass('jstree-unchecked').children(':checkbox').prop('checked', true);
 
2951                                 var rc = this._get_settings().checkbox.real_checkboxes,
 
2952                                         a = obj.find("> ul > .jstree-checked").length,
 
2953                                         b = obj.find("> ul > .jstree-undetermined").length,
 
2954                                         c = obj.find("> ul > li").length;
 
2955                                 if(c === 0) { if(obj.hasClass("jstree-undetermined")) { this.change_state(obj, false); } }
 
2956                                 else if(a === 0 && b === 0) { this.change_state(obj, true); }
 
2957                                 else if(a === c) { this.change_state(obj, false); }
 
2959                                         obj.parentsUntil(".jstree","li").addBack().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
 
2960                                         if(rc) { obj.parentsUntil(".jstree", "li").addBack().children(":checkbox").prop("checked", false); }
 
2963                         reselect : function () {
 
2964                                 if(this.data.ui && this.data.checkbox.noui) { 
 
2966                                                 s = this.data.ui.to_select;
 
2967                                         s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); });
 
2968                                         this.deselect_all();
 
2969                                         $.each(s, function (i, val) { _this.check_node(val); });
 
2976                         save_loaded : function () {
 
2978                                 this.data.core.to_load = [];
 
2979                                 this.get_container_ul().find("li.jstree-closed.jstree-undetermined").each(function () {
 
2980                                         if(this.id) { _this.data.core.to_load.push("#" + this.id); }
 
2986                 var css_string = '.jstree .jstree-real-checkbox { display:none; } ';
 
2987                 $.vakata.css.add_sheet({ str : css_string, title : "jstree" });
 
2994  * The XML data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions.
 
2997         $.vakata.xslt = function (xml, xsl, callback) {
 
2998                 var r = false, p, q, s;
 
3000                 if(r === false && window.ActiveXObject) {
 
3002                                 r = new ActiveXObject("Msxml2.XSLTemplate");
 
3003                                 q = new ActiveXObject("Msxml2.DOMDocument");
 
3005                                 s = new ActiveXObject("Msxml2.FreeThreadedDOMDocument");
 
3008                                 p = r.createProcessor();
 
3015                 xml = $.parseXML(xml);
 
3016                 xsl = $.parseXML(xsl);
 
3018                 if(r === false && typeof (XSLTProcessor) !== "undefined") {
 
3019                         p = new XSLTProcessor();
 
3020                         p.importStylesheet(xsl);
 
3021                         r = p.transformToFragment(xml, document);
 
3022                         r = $('<div />').append(r).html();
 
3025                 if(r === false && typeof (xml.transformNode) !== "undefined") {
 
3026                         r = xml.transformNode(xsl);
 
3028                 callback.call(null, r);
 
3031                 'nest' : '<' + '?xml version="1.0" encoding="utf-8" ?>' + 
 
3032                         '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' + 
 
3033                         '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/html" />' + 
 
3034                         '<xsl:template match="/">' + 
 
3035                         '       <xsl:call-template name="nodes">' + 
 
3036                         '               <xsl:with-param name="node" select="/root" />' + 
 
3037                         '       </xsl:call-template>' + 
 
3039                         '<xsl:template name="nodes">' + 
 
3040                         '       <xsl:param name="node" />' + 
 
3042                         '       <xsl:for-each select="$node/item">' + 
 
3043                         '               <xsl:variable name="children" select="count(./item) > 0" />' + 
 
3045                         '                       <xsl:attribute name="class">' + 
 
3046                         '                               <xsl:if test="position() = last()">jstree-last </xsl:if>' + 
 
3048                         '                                       <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' + 
 
3049                         '                                       <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' + 
 
3050                         '                                       <xsl:otherwise>jstree-leaf </xsl:otherwise>' + 
 
3052                         '                               <xsl:value-of select="@class" />' + 
 
3053                         '                       </xsl:attribute>' + 
 
3054                         '                       <xsl:for-each select="@*">' + 
 
3055                         '                               <xsl:if test="name() != \'class\' and name() != \'state\' and name() != \'hasChildren\'">' + 
 
3056                         '                                       <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + 
 
3058                         '                       </xsl:for-each>' + 
 
3059                         '       <ins class="jstree-icon"><xsl:text> </xsl:text></ins>' + 
 
3060                         '                       <xsl:for-each select="content/name">' + 
 
3062                         '                               <xsl:attribute name="href">' + 
 
3064                         '                                       <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' + 
 
3065                         '                                       <xsl:otherwise>#</xsl:otherwise>' + 
 
3067                         '                               </xsl:attribute>' + 
 
3068                         '                               <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' + 
 
3069                         '                               <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' + 
 
3070                         '                               <xsl:for-each select="@*">' + 
 
3071                         '                                       <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' + 
 
3072                         '                                               <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + 
 
3074                         '                               </xsl:for-each>' + 
 
3076                         '                                               <xsl:attribute name="class">jstree-icon ' + 
 
3077                         '                                                       <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' + 
 
3078                         '                                               </xsl:attribute>' + 
 
3079                         '                                               <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>' + 
 
3080                         '                                               <xsl:text> </xsl:text>' + 
 
3082                         '                                       <xsl:copy-of select="./child::node()" />' + 
 
3084                         '                       </xsl:for-each>' + 
 
3085                         '                       <xsl:if test="$children or @hasChildren"><xsl:call-template name="nodes"><xsl:with-param name="node" select="current()" /></xsl:call-template></xsl:if>' + 
 
3087                         '       </xsl:for-each>' + 
 
3090                         '</xsl:stylesheet>',
 
3092                 'flat' : '<' + '?xml version="1.0" encoding="utf-8" ?>' + 
 
3093                         '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' + 
 
3094                         '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/xml" />' + 
 
3095                         '<xsl:template match="/">' + 
 
3097                         '       <xsl:for-each select="//item[not(@parent_id) or @parent_id=0 or not(@parent_id = //item/@id)]">' + /* the last `or` may be removed */
 
3098                         '               <xsl:call-template name="nodes">' + 
 
3099                         '                       <xsl:with-param name="node" select="." />' + 
 
3100                         '                       <xsl:with-param name="is_last" select="number(position() = last())" />' + 
 
3101                         '               </xsl:call-template>' + 
 
3102                         '       </xsl:for-each>' + 
 
3105                         '<xsl:template name="nodes">' + 
 
3106                         '       <xsl:param name="node" />' + 
 
3107                         '       <xsl:param name="is_last" />' + 
 
3108                         '       <xsl:variable name="children" select="count(//item[@parent_id=$node/attribute::id]) > 0" />' + 
 
3110                         '       <xsl:attribute name="class">' + 
 
3111                         '               <xsl:if test="$is_last = true()">jstree-last </xsl:if>' + 
 
3113                         '                       <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' + 
 
3114                         '                       <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' + 
 
3115                         '                       <xsl:otherwise>jstree-leaf </xsl:otherwise>' + 
 
3117                         '               <xsl:value-of select="@class" />' + 
 
3118                         '       </xsl:attribute>' + 
 
3119                         '       <xsl:for-each select="@*">' + 
 
3120                         '               <xsl:if test="name() != \'parent_id\' and name() != \'hasChildren\' and name() != \'class\' and name() != \'state\'">' + 
 
3121                         '               <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + 
 
3123                         '       </xsl:for-each>' + 
 
3124                         '       <ins class="jstree-icon"><xsl:text> </xsl:text></ins>' + 
 
3125                         '       <xsl:for-each select="content/name">' + 
 
3127                         '               <xsl:attribute name="href">' + 
 
3129                         '                       <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' + 
 
3130                         '                       <xsl:otherwise>#</xsl:otherwise>' + 
 
3132                         '               </xsl:attribute>' + 
 
3133                         '               <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' + 
 
3134                         '               <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' + 
 
3135                         '               <xsl:for-each select="@*">' + 
 
3136                         '                       <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' + 
 
3137                         '                               <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + 
 
3139                         '               </xsl:for-each>' + 
 
3141                         '                               <xsl:attribute name="class">jstree-icon ' + 
 
3142                         '                                       <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' + 
 
3143                         '                               </xsl:attribute>' + 
 
3144                         '                               <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>' + 
 
3145                         '                               <xsl:text> </xsl:text>' + 
 
3147                         '                       <xsl:copy-of select="./child::node()" />' + 
 
3149                         '       </xsl:for-each>' + 
 
3150                         '       <xsl:if test="$children">' + 
 
3152                         '               <xsl:for-each select="//item[@parent_id=$node/attribute::id]">' + 
 
3153                         '                       <xsl:call-template name="nodes">' + 
 
3154                         '                               <xsl:with-param name="node" select="." />' + 
 
3155                         '                               <xsl:with-param name="is_last" select="number(position() = last())" />' + 
 
3156                         '                       </xsl:call-template>' + 
 
3157                         '               </xsl:for-each>' + 
 
3164         escape_xml = function(string) {
 
3167                         .replace(/&/g, '&')
 
3168                         .replace(/</g, '<')
 
3169                         .replace(/>/g, '>')
 
3170                         .replace(/"/g, '"')
 
3171                         .replace(/'/g, ''');
 
3173         $.jstree.plugin("xml_data", {
 
3179                         correct_state : true,
 
3180                         get_skip_empty : false,
 
3181                         get_include_preamble : true
 
3184                         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); },
 
3185                         _is_loaded : function (obj) { 
 
3186                                 var s = this._get_settings().xml_data;
 
3187                                 obj = this._get_node(obj);
 
3188                                 return obj == -1 || !obj || (!s.ajax && !$.isFunction(s.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0;
 
3190                         load_node_xml : function (obj, s_call, e_call) {
 
3191                                 var s = this.get_settings().xml_data,
 
3192                                         error_func = function () {},
 
3193                                         success_func = function () {};
 
3195                                 obj = this._get_node(obj);
 
3196                                 if(obj && obj !== -1) {
 
3197                                         if(obj.data("jstree_is_loading")) { return; }
 
3198                                         else { obj.data("jstree_is_loading",true); }
 
3201                                         case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied.";
 
3202                                         case ($.isFunction(s.data)):
 
3203                                                 s.data.call(this, obj, $.proxy(function (d) {
 
3204                                                         this.parse_xml(d, $.proxy(function (d) {
 
3206                                                                         d = d.replace(/ ?xmlns="[^"]*"/ig, "");
 
3209                                                                                 if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); }
 
3210                                                                                 else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.append(d); obj.removeData("jstree_is_loading"); }
 
3211                                                                                 if(s.clean_node) { this.clean_node(obj); }
 
3212                                                                                 if(s_call) { s_call.call(this); }
 
3215                                                                                 if(obj && obj !== -1) { 
 
3216                                                                                         obj.children("a.jstree-loading").removeClass("jstree-loading");
 
3217                                                                                         obj.removeData("jstree_is_loading");
 
3218                                                                                         if(s.correct_state) { 
 
3219                                                                                                 this.correct_state(obj);
 
3220                                                                                                 if(s_call) { s_call.call(this); } 
 
3224                                                                                         if(s.correct_state) { 
 
3225                                                                                                 this.get_container().children("ul").empty();
 
3226                                                                                                 if(s_call) { s_call.call(this); } 
 
3234                                         case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
 
3235                                                 if(!obj || obj == -1) {
 
3236                                                         this.parse_xml(s.data, $.proxy(function (d) {
 
3238                                                                         d = d.replace(/ ?xmlns="[^"]*"/ig, "");
 
3241                                                                                 this.get_container().children("ul").empty().append(d.children());
 
3242                                                                                 if(s.clean_node) { this.clean_node(obj); }
 
3243                                                                                 if(s_call) { s_call.call(this); }
 
3247                                                                         if(s.correct_state) { 
 
3248                                                                                 this.get_container().children("ul").empty(); 
 
3249                                                                                 if(s_call) { s_call.call(this); }
 
3255                                         case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
 
3256                                                 error_func = function (x, t, e) {
 
3257                                                         var ef = this.get_settings().xml_data.ajax.error; 
 
3258                                                         if(ef) { ef.call(this, x, t, e); }
 
3259                                                         if(obj !== -1 && obj.length) {
 
3260                                                                 obj.children("a.jstree-loading").removeClass("jstree-loading");
 
3261                                                                 obj.removeData("jstree_is_loading");
 
3262                                                                 if(t === "success" && s.correct_state) { this.correct_state(obj); }
 
3265                                                                 if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); }
 
3267                                                         if(e_call) { e_call.call(this); }
 
3269                                                 success_func = function (d, t, x) {
 
3271                                                         var sf = this.get_settings().xml_data.ajax.success; 
 
3272                                                         if(sf) { d = sf.call(this,d,t,x) || d; }
 
3273                                                         if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "")) {
 
3274                                                                 return error_func.call(this, x, t, "");
 
3276                                                         this.parse_xml(d, $.proxy(function (d) {
 
3278                                                                         d = d.replace(/ ?xmlns="[^"]*"/ig, "");
 
3281                                                                                 if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); }
 
3282                                                                                 else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.append(d); obj.removeData("jstree_is_loading"); }
 
3283                                                                                 if(s.clean_node) { this.clean_node(obj); }
 
3284                                                                                 if(s_call) { s_call.call(this); }
 
3287                                                                                 if(obj && obj !== -1) { 
 
3288                                                                                         obj.children("a.jstree-loading").removeClass("jstree-loading");
 
3289                                                                                         obj.removeData("jstree_is_loading");
 
3290                                                                                         if(s.correct_state) { 
 
3291                                                                                                 this.correct_state(obj);
 
3292                                                                                                 if(s_call) { s_call.call(this); } 
 
3296                                                                                         if(s.correct_state) { 
 
3297                                                                                                 this.get_container().children("ul").empty();
 
3298                                                                                                 if(s_call) { s_call.call(this); } 
 
3305                                                 s.ajax.context = this;
 
3306                                                 s.ajax.error = error_func;
 
3307                                                 s.ajax.success = success_func;
 
3308                                                 if(!s.ajax.dataType) { s.ajax.dataType = "xml"; }
 
3309                                                 if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); }
 
3310                                                 if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
 
3315                         parse_xml : function (xml, callback) {
 
3316                                 var s = this._get_settings().xml_data;
 
3317                                 $.vakata.xslt(xml, xsl[s.xsl], callback);
 
3319                         get_xml : function (tp, obj, li_attr, a_attr, is_callback) {
 
3321                                         s = this._get_settings(), 
 
3323                                         tmp1, tmp2, li, a, lang;
 
3324                                 if(!tp) { tp = "flat"; }
 
3325                                 if(!is_callback) { is_callback = 0; }
 
3326                                 obj = this._get_node(obj);
 
3327                                 if(!obj || obj === -1) { obj = this.get_container().find("> ul > li"); }
 
3328                                 li_attr = $.isArray(li_attr) ? li_attr : [ "id", "class" ];
 
3329                                 if(!is_callback && this.data.types && $.inArray(s.types.type_attr, li_attr) === -1) { li_attr.push(s.types.type_attr); }
 
3331                                 a_attr = $.isArray(a_attr) ? a_attr : [ ];
 
3334                                         if(s.xml_data.get_include_preamble) { 
 
3335                                                 result += '<' + '?xml version="1.0" encoding="UTF-8"?' + '>'; 
 
3339                                 obj.each(function () {
 
3342                                         $.each(li_attr, function (i, v) { 
 
3344                                                 if(!s.xml_data.get_skip_empty || typeof t !== "undefined") {
 
3345                                                         result += " " + v + "=\"" + escape_xml((" " + (t || "")).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"")) + "\""; 
 
3348                                         if(li.hasClass("jstree-open")) { result += " state=\"open\""; }
 
3349                                         if(li.hasClass("jstree-closed")) { result += " state=\"closed\""; }
 
3350                                         if(tp === "flat") { result += " parent_id=\"" + escape_xml(is_callback) + "\""; }
 
3352                                         result += "<content>";
 
3353                                         a = li.children("a");
 
3354                                         a.each(function () {
 
3358                                                 if($.inArray("languages", s.plugins) !== -1) {
 
3359                                                         $.each(s.languages, function (k, z) {
 
3360                                                                 if(tmp1.hasClass(z)) { result += " lang=\"" + escape_xml(z) + "\""; lang = z; return false; }
 
3364                                                         $.each(a_attr, function (k, z) {
 
3365                                                                 var t = tmp1.attr(z);
 
3366                                                                 if(!s.xml_data.get_skip_empty || typeof t !== "undefined") {
 
3367                                                                         result += " " + z + "=\"" + escape_xml((" " + t || "").replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"")) + "\"";
 
3371                                                 if(tmp1.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length) {
 
3372                                                         result += ' icon="' + escape_xml(tmp1.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"")) + '"';
 
3374                                                 if(tmp1.children("ins").get(0).style.backgroundImage.length) {
 
3375                                                         result += ' icon="' + escape_xml(tmp1.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","").replace(/'/ig,"").replace(/"/ig,"")) + '"';
 
3378                                                 result += "<![CDATA[" + _this.get_text(tmp1, lang) + "]]>";
 
3379                                                 result += "</name>";
 
3381                                         result += "</content>";
 
3382                                         tmp2 = li[0].id || true;
 
3383                                         li = li.find("> ul > li");
 
3384                                         if(li.length) { tmp2 = _this.get_xml(tp, li, li_attr, a_attr, tmp2); }
 
3386                                         if(tp == "nest") { result += tmp2; }
 
3387                                         result += "</item>";
 
3388                                         if(tp == "flat") { result += tmp2; }
 
3390                                 if(!is_callback) { result += "</root>"; }
 
3399  * jsTree search plugin
 
3400  * Enables both sync and async search on the tree
 
3401  * DOES NOT WORK WITH JSON PROGRESSIVE RENDER
 
3404         if($().jquery.split('.')[1] >= 8) {
 
3405                 $.expr[':'].jstree_contains = $.expr.createPseudo(function(search) {
 
3406                         return function(a) {
 
3407                                 return (a.textContent || a.innerText || "").toLowerCase().indexOf(search.toLowerCase())>=0;
 
3410                 $.expr[':'].jstree_title_contains = $.expr.createPseudo(function(search) {
 
3411                         return function(a) {
 
3412                                 return (a.getAttribute("title") || "").toLowerCase().indexOf(search.toLowerCase())>=0;
 
3417                 $.expr[':'].jstree_contains = function(a,i,m){
 
3418                         return (a.textContent || a.innerText || "").toLowerCase().indexOf(m[3].toLowerCase())>=0;
 
3420                 $.expr[':'].jstree_title_contains = function(a,i,m) {
 
3421                         return (a.getAttribute("title") || "").toLowerCase().indexOf(m[3].toLowerCase())>=0;
 
3424         $.jstree.plugin("search", {
 
3425                 __init : function () {
 
3426                         this.data.search.str = "";
 
3427                         this.data.search.result = $();
 
3428                         if(this._get_settings().search.show_only_matches) {
 
3429                                 this.get_container()
 
3430                                         .bind("search.jstree", function (e, data) {
 
3431                                                 $(this).children("ul").find("li").hide().removeClass("jstree-last");
 
3432                                                 data.rslt.nodes.parentsUntil(".jstree").addBack().show()
 
3433                                                         .filter("ul").each(function () { $(this).children("li:visible").eq(-1).addClass("jstree-last"); });
 
3435                                         .bind("clear_search.jstree", function () {
 
3436                                                 $(this).children("ul").find("li").css("display","").end().end().jstree("clean_node", -1);
 
3442                         search_method : "jstree_contains", // for case insensitive - jstree_contains
 
3443                         show_only_matches : false
 
3446                         search : function (str, skip_async) {
 
3447                                 if($.trim(str) === "") { this.clear_search(); return; }
 
3448                                 var s = this.get_settings().search, 
 
3450                                         error_func = function () { },
 
3451                                         success_func = function () { };
 
3452                                 this.data.search.str = str;
 
3454                                 if(!skip_async && s.ajax !== false && this.get_container_ul().find("li.jstree-closed:not(:has(ul)):eq(0)").length > 0) {
 
3455                                         this.search.supress_callback = true;
 
3456                                         error_func = function () { };
 
3457                                         success_func = function (d, t, x) {
 
3458                                                 var sf = this.get_settings().search.ajax.success; 
 
3459                                                 if(sf) { d = sf.call(this,d,t,x) || d; }
 
3460                                                 this.data.search.to_open = d;
 
3461                                                 this._search_open();
 
3463                                         s.ajax.context = this;
 
3464                                         s.ajax.error = error_func;
 
3465                                         s.ajax.success = success_func;
 
3466                                         if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, str); }
 
3467                                         if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, str); }
 
3468                                         if(!s.ajax.data) { s.ajax.data = { "search_string" : str }; }
 
3469                                         if(!s.ajax.dataType || /^json/.exec(s.ajax.dataType)) { s.ajax.dataType = "json"; }
 
3473                                 if(this.data.search.result.length) { this.clear_search(); }
 
3474                                 this.data.search.result = this.get_container().find("a" + (this.data.languages ? "." + this.get_lang() : "" ) + ":" + (s.search_method) + "(" + this.data.search.str + ")");
 
3475                                 this.data.search.result.addClass("jstree-search").parent().parents(".jstree-closed").each(function () {
 
3476                                         t.open_node(this, false, true);
 
3478                                 this.__callback({ nodes : this.data.search.result, str : str });
 
3480                         clear_search : function (str) {
 
3481                                 this.data.search.result.removeClass("jstree-search");
 
3482                                 this.__callback(this.data.search.result);
 
3483                                 this.data.search.result = $();
 
3485                         _search_open : function (is_callback) {
 
3490                                 if(this.data.search.to_open.length) {
 
3491                                         $.each(this.data.search.to_open, function (i, val) {
 
3492                                                 if(val == "#") { return true; }
 
3493                                                 if($(val).length && $(val).is(".jstree-closed")) { current.push(val); }
 
3494                                                 else { remaining.push(val); }
 
3496                                         if(current.length) {
 
3497                                                 this.data.search.to_open = remaining;
 
3498                                                 $.each(current, function (i, val) { 
 
3499                                                         _this.open_node(val, function () { _this._search_open(true); }); 
 
3504                                 if(done) { this.search(this.data.search.str, true); }
 
3512  * jsTree contextmenu plugin
 
3515         $.vakata.context = {
 
3516                 hide_on_mouseleave : false,
 
3518                 cnt             : $("<div id='vakata-contextmenu' />"),
 
3525                 show    : function (s, t, x, y, d, p, rtl) {
 
3526                         $.vakata.context.rtl = !!rtl;
 
3527                         var html = $.vakata.context.parse(s), h, w;
 
3528                         if(!html) { return; }
 
3529                         $.vakata.context.vis = true;
 
3530                         $.vakata.context.tgt = t;
 
3531                         $.vakata.context.par = p || t || null;
 
3532                         $.vakata.context.data = d || null;
 
3533                         $.vakata.context.cnt
 
3535                                 .css({ "visibility" : "hidden", "display" : "block", "left" : 0, "top" : 0 });
 
3537                         if($.vakata.context.hide_on_mouseleave) {
 
3538                                 $.vakata.context.cnt
 
3539                                         .one("mouseleave", function(e) { $.vakata.context.hide(); });
 
3542                         h = $.vakata.context.cnt.height();
 
3543                         w = $.vakata.context.cnt.width();
 
3544                         if(x + w > $(document).width()) { 
 
3545                                 x = $(document).width() - (w + 5); 
 
3546                                 $.vakata.context.cnt.find("li > ul").addClass("right"); 
 
3548                         if(y + h > $(document).height()) { 
 
3549                                 y = y - (h + t[0].offsetHeight); 
 
3550                                 $.vakata.context.cnt.find("li > ul").addClass("bottom"); 
 
3553                         $.vakata.context.cnt
 
3554                                 .css({ "left" : x, "top" : y })
 
3556                                         .bind("mouseenter", function (e) { 
 
3557                                                 var w = $(document).width(),
 
3558                                                         h = $(document).height(),
 
3559                                                         ul = $(this).children("ul").show(); 
 
3560                                                 if(w !== $(document).width()) { ul.toggleClass("right"); }
 
3561                                                 if(h !== $(document).height()) { ul.toggleClass("bottom"); }
 
3563                                         .bind("mouseleave", function (e) { 
 
3564                                                 $(this).children("ul").hide(); 
 
3567                                 .css({ "visibility" : "visible" })
 
3569                         $(document).triggerHandler("context_show.vakata");
 
3571                 hide    : function () {
 
3572                         $.vakata.context.vis = false;
 
3573                         $.vakata.context.cnt.attr("class","").css({ "visibility" : "hidden" });
 
3574                         $(document).triggerHandler("context_hide.vakata");
 
3576                 parse   : function (s, is_callback) {
 
3577                         if(!s) { return false; }
 
3581                         if(!is_callback) { $.vakata.context.func = {}; }
 
3583                         $.each(s, function (i, val) {
 
3584                                 if(!val) { return true; }
 
3585                                 $.vakata.context.func[i] = val.action;
 
3586                                 if(!was_sep && val.separator_before) {
 
3587                                         str += "<li class='vakata-separator vakata-separator-before'></li>";
 
3590                                 str += "<li class='" + (val._class || "") + (val._disabled ? " jstree-contextmenu-disabled " : "") + "'><ins ";
 
3591                                 if(val.icon && val.icon.indexOf("/") === -1) { str += " class='" + val.icon + "' "; }
 
3592                                 if(val.icon && val.icon.indexOf("/") !== -1) { str += " style='background:url(" + val.icon + ") center center no-repeat;' "; }
 
3593                                 str += "> </ins><a href='#' rel='" + i + "'>";
 
3595                                         str += "<span style='float:" + ($.vakata.context.rtl ? "left" : "right") + ";'>»</span>";
 
3597                                 str += val.label + "</a>";
 
3599                                         tmp = $.vakata.context.parse(val.submenu, true);
 
3600                                         if(tmp) { str += tmp; }
 
3603                                 if(val.separator_after) {
 
3604                                         str += "<li class='vakata-separator vakata-separator-after'></li>";
 
3608                         str = str.replace(/<li class\='vakata-separator vakata-separator-after'\><\/li\>$/,"");
 
3610                         $(document).triggerHandler("context_parse.vakata");
 
3611                         return str.length > 10 ? str : false;
 
3613                 exec    : function (i) {
 
3614                         if($.isFunction($.vakata.context.func[i])) {
 
3615                                 // if is string - eval and call it!
 
3616                                 $.vakata.context.func[i].call($.vakata.context.data, $.vakata.context.par);
 
3619                         else { return false; }
 
3623                 var css_string = '' + 
 
3624                         '#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; } ' + 
 
3625                         '#vakata-contextmenu ul { min-width:180px; *width:180px; } ' + 
 
3626                         '#vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } ' + 
 
3627                         '#vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } ' + 
 
3628                         '#vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } ' + 
 
3629                         '#vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } ' + 
 
3630                         '#vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } ' + 
 
3631                         '#vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } ' + 
 
3632                         '#vakata-contextmenu .right { right:100%; left:auto; } ' + 
 
3633                         '#vakata-contextmenu .bottom { bottom:-1px; top:auto; } ' + 
 
3634                         '#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; } ';
 
3635                 $.vakata.css.add_sheet({ str : css_string, title : "vakata" });
 
3636                 $.vakata.context.cnt
 
3637                         .delegate("a","click", function (e) { e.preventDefault(); })
 
3638                         .delegate("a","mouseup", function (e) {
 
3639                                 if(!$(this).parent().hasClass("jstree-contextmenu-disabled") && $.vakata.context.exec($(this).attr("rel"))) {
 
3640                                         $.vakata.context.hide();
 
3642                                 else { $(this).blur(); }
 
3644                         .delegate("a","mouseover", function () {
 
3645                                 $.vakata.context.cnt.find(".vakata-hover").removeClass("vakata-hover");
 
3648                 $(document).bind("mousedown", function (e) { if($.vakata.context.vis && !$.contains($.vakata.context.cnt[0], e.target)) { $.vakata.context.hide(); } });
 
3649                 if(typeof $.hotkeys !== "undefined") {
 
3651                                 .bind("keydown", "up", function (e) { 
 
3652                                         if($.vakata.context.vis) { 
 
3653                                                 var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first();
 
3654                                                 if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last(); }
 
3655                                                 o.addClass("vakata-hover");
 
3656                                                 e.stopImmediatePropagation(); 
 
3660                                 .bind("keydown", "down", function (e) { 
 
3661                                         if($.vakata.context.vis) { 
 
3662                                                 var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first();
 
3663                                                 if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first(); }
 
3664                                                 o.addClass("vakata-hover");
 
3665                                                 e.stopImmediatePropagation(); 
 
3669                                 .bind("keydown", "right", function (e) { 
 
3670                                         if($.vakata.context.vis) { 
 
3671                                                 $.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover");
 
3672                                                 e.stopImmediatePropagation(); 
 
3676                                 .bind("keydown", "left", function (e) { 
 
3677                                         if($.vakata.context.vis) { 
 
3678                                                 $.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover");
 
3679                                                 e.stopImmediatePropagation(); 
 
3683                                 .bind("keydown", "esc", function (e) { 
 
3684                                         $.vakata.context.hide(); 
 
3687                                 .bind("keydown", "space", function (e) { 
 
3688                                         $.vakata.context.cnt.find(".vakata-hover").last().children("a").click();
 
3694         $.jstree.plugin("contextmenu", {
 
3695                 __init : function () {
 
3696                         this.get_container()
 
3697                                 .delegate("a", "contextmenu.jstree", $.proxy(function (e) {
 
3699                                                 if(!$(e.currentTarget).hasClass("jstree-loading")) {
 
3700                                                         this.show_contextmenu(e.currentTarget, e.pageX, e.pageY);
 
3703                                 .delegate("a", "click.jstree", $.proxy(function (e) {
 
3704                                                 if(this.data.contextmenu) {
 
3705                                                         $.vakata.context.hide();
 
3708                                 .bind("destroy.jstree", $.proxy(function () {
 
3709                                                 // TODO: move this to descruct method
 
3710                                                 if(this.data.contextmenu) {
 
3711                                                         $.vakata.context.hide();
 
3714                         $(document).bind("context_hide.vakata", $.proxy(function () { this.data.contextmenu = false; }, this));
 
3717                         select_node : false, // requires UI plugin
 
3718                         show_at_node : true,
 
3719                         items : { // Could be a function that should return an object like this one
 
3721                                         "separator_before"      : false,
 
3722                                         "separator_after"       : true,
 
3724                                         "action"                        : function (obj) { this.create(obj); }
 
3727                                         "separator_before"      : false,
 
3728                                         "separator_after"       : false,
 
3730                                         "action"                        : function (obj) { this.rename(obj); }
 
3733                                         "separator_before"      : false,
 
3735                                         "separator_after"       : false,
 
3737                                         "action"                        : function (obj) { if(this.is_selected(obj)) { this.remove(); } else { this.remove(obj); } }
 
3740                                         "separator_before"      : true,
 
3742                                         "separator_after"       : false,
 
3747                                                         "separator_before"      : false,
 
3748                                                         "separator_after"       : false,
 
3750                                                         "action"                        : function (obj) { this.cut(obj); }
 
3753                                                         "separator_before"      : false,
 
3755                                                         "separator_after"       : false,
 
3757                                                         "action"                        : function (obj) { this.copy(obj); }
 
3760                                                         "separator_before"      : false,
 
3762                                                         "separator_after"       : false,
 
3764                                                         "action"                        : function (obj) { this.paste(obj); }
 
3771                         show_contextmenu : function (obj, x, y) {
 
3772                                 obj = this._get_node(obj);
 
3773                                 var s = this.get_settings().contextmenu,
 
3774                                         a = obj.children("a:visible:eq(0)"),
 
3777                                 if(s.select_node && this.data.ui && !this.is_selected(obj)) {
 
3778                                         this.deselect_all();
 
3779                                         this.select_node(obj, true);
 
3781                                 if(s.show_at_node || typeof x === "undefined" || typeof y === "undefined") {
 
3784                                         y = o.top + this.data.core.li_height;
 
3786                                 i = obj.data("jstree") && obj.data("jstree").contextmenu ? obj.data("jstree").contextmenu : s.items;
 
3787                                 if($.isFunction(i)) { i = i.call(this, obj); }
 
3788                                 this.data.contextmenu = true;
 
3789                                 $.vakata.context.show(i, a, x, y, this, obj, this._get_settings().core.rtl);
 
3790                                 if(this.data.themes) { $.vakata.context.cnt.attr("class", "jstree-" + this.data.themes.theme + "-context"); }
 
3798  * jsTree types plugin
 
3799  * Adds support types of nodes
 
3800  * You can set an attribute on each li node, that represents its type.
 
3801  * According to the type setting the node may get custom icon/validation rules
 
3804         $.jstree.plugin("types", {
 
3805                 __init : function () {
 
3806                         var s = this._get_settings().types;
 
3807                         this.data.types.attach_to = [];
 
3808                         this.get_container()
 
3809                                 .bind("init.jstree", $.proxy(function () { 
 
3810                                                 var types = s.types, 
 
3815                                                 $.each(types, function (i, tp) {
 
3816                                                         $.each(tp, function (k, v) { 
 
3817                                                                 if(!/^(max_depth|max_children|icon|valid_children)$/.test(k)) { _this.data.types.attach_to.push(k); }
 
3819                                                         if(!tp.icon) { return true; }
 
3820                                                         if( tp.icon.image || tp.icon.position) {
 
3821                                                                 if(i == "default")      { icons_css += '.jstree-' + _this.get_index() + ' a > .jstree-icon { '; }
 
3822                                                                 else                            { icons_css += '.jstree-' + _this.get_index() + ' li[' + attr + '="' + i + '"] > a > .jstree-icon { '; }
 
3823                                                                 if(tp.icon.image)       { icons_css += ' background-image:url(' + tp.icon.image + '); '; }
 
3824                                                                 if(tp.icon.position){ icons_css += ' background-position:' + tp.icon.position + '; '; }
 
3825                                                                 else                            { icons_css += ' background-position:0 0; '; }
 
3829                                                 if(icons_css !== "") { $.vakata.css.add_sheet({ 'str' : icons_css, title : "jstree-types" }); }
 
3831                                 .bind("before.jstree", $.proxy(function (e, data) { 
 
3833                                                         o = this._get_settings().types.use_data ? this._get_node(data.args[0]) : false, 
 
3834                                                         d = o && o !== -1 && o.length ? o.data("jstree") : false;
 
3835                                                 if(d && d.types && d.types[data.func] === false) { e.stopImmediatePropagation(); return false; }
 
3836                                                 if($.inArray(data.func, this.data.types.attach_to) !== -1) {
 
3837                                                         if(!data.args[0] || (!data.args[0].tagName && !data.args[0].jquery)) { return; }
 
3838                                                         s = this._get_settings().types.types;
 
3839                                                         t = this._get_type(data.args[0]);
 
3842                                                                         (s[t] && typeof s[t][data.func] !== "undefined") || 
 
3843                                                                         (s["default"] && typeof s["default"][data.func] !== "undefined") 
 
3844                                                                 ) && this._check(data.func, data.args[0]) === false
 
3846                                                                 e.stopImmediatePropagation();
 
3852                                 this.get_container()
 
3853                                         .bind("load_node.jstree set_type.jstree", $.proxy(function (e, data) {
 
3854                                                         var r = data && data.rslt && data.rslt.obj && data.rslt.obj !== -1 ? this._get_node(data.rslt.obj).parent() : this.get_container_ul(),
 
3856                                                                 s = this._get_settings().types;
 
3857                                                         $.each(s.types, function (i, tp) {
 
3858                                                                 if(tp.icon && (tp.icon.image || tp.icon.position)) {
 
3859                                                                         c = i === "default" ? r.find("li > a > .jstree-icon") : r.find("li[" + s.type_attr + "='" + i + "'] > a > .jstree-icon");
 
3860                                                                         if(tp.icon.image) { c.css("backgroundImage","url(" + tp.icon.image + ")"); }
 
3861                                                                         c.css("backgroundPosition", tp.icon.position || "0 0");
 
3868                         // defines maximum number of root nodes (-1 means unlimited, -2 means disable max_children checking)
 
3870                         // defines the maximum depth of the tree (-1 means unlimited, -2 means disable max_depth checking)
 
3872                         // defines valid node types for the root nodes
 
3873                         valid_children          : "all",
 
3875                         // whether to use $.data
 
3877                         // where is the type stores (the rel attribute of the LI element)
 
3883                                         "max_children"  : -1,
 
3885                                         "valid_children": "all"
 
3887                                         // Bound functions - you can bind any other function here (using boolean or function)
 
3888                                         //"select_node" : true
 
3893                         _types_notify : function (n, data) {
 
3894                                 if(data.type && this._get_settings().types.use_data) {
 
3895                                         this.set_type(data.type, n);
 
3898                         _get_type : function (obj) {
 
3899                                 obj = this._get_node(obj);
 
3900                                 return (!obj || !obj.length) ? false : obj.attr(this._get_settings().types.type_attr) || "default";
 
3902                         set_type : function (str, obj) {
 
3903                                 obj = this._get_node(obj);
 
3904                                 var ret = (!obj.length || !str) ? false : obj.attr(this._get_settings().types.type_attr, str);
 
3905                                 if(ret) { this.__callback({ obj : obj, type : str}); }
 
3908                         _check : function (rule, obj, opts) {
 
3909                                 obj = this._get_node(obj);
 
3910                                 var v = false, t = this._get_type(obj), d = 0, _this = this, s = this._get_settings().types, data = false;
 
3912                                         if(!!s[rule]) { v = s[rule]; }
 
3916                                         if(t === false) { return; }
 
3917                                         data = s.use_data ? obj.data("jstree") : false;
 
3918                                         if(data && data.types && typeof data.types[rule] !== "undefined") { v = data.types[rule]; }
 
3919                                         else if(!!s.types[t] && typeof s.types[t][rule] !== "undefined") { v = s.types[t][rule]; }
 
3920                                         else if(!!s.types["default"] && typeof s.types["default"][rule] !== "undefined") { v = s.types["default"][rule]; }
 
3922                                 if($.isFunction(v)) { v = v.call(this, obj); }
 
3923                                 if(rule === "max_depth" && obj !== -1 && opts !== false && s.max_depth !== -2 && v !== 0) {
 
3924                                         // also include the node itself - otherwise if root node it is not checked
 
3925                                         obj.children("a:eq(0)").parentsUntil(".jstree","li").each(function (i) {
 
3926                                                 // check if current depth already exceeds global tree depth
 
3927                                                 if(s.max_depth !== -1 && s.max_depth - (i + 1) <= 0) { v = 0; return false; }
 
3928                                                 d = (i === 0) ? v : _this._check(rule, this, false);
 
3929                                                 // check if current node max depth is already matched or exceeded
 
3930                                                 if(d !== -1 && d - (i + 1) <= 0) { v = 0; return false; }
 
3931                                                 // otherwise - set the max depth to the current value minus current depth
 
3932                                                 if(d >= 0 && (d - (i + 1) < v || v < 0) ) { v = d - (i + 1); }
 
3933                                                 // if the global tree depth exists and it minus the nodes calculated so far is less than `v` or `v` is unlimited
 
3934                                                 if(s.max_depth >= 0 && (s.max_depth - (i + 1) < v || v < 0) ) { v = s.max_depth - (i + 1); }
 
3939                         check_move : function () {
 
3940                                 if(!this.__call_old()) { return false; }
 
3941                                 var m  = this._get_move(),
 
3942                                         s  = m.rt._get_settings().types,
 
3943                                         mc = m.rt._check("max_children", m.cr),
 
3944                                         md = m.rt._check("max_depth", m.cr),
 
3945                                         vc = m.rt._check("valid_children", m.cr),
 
3948                                 if(vc === "none") { return false; } 
 
3949                                 if($.isArray(vc) && m.ot && m.ot._get_type) {
 
3950                                         m.o.each(function () {
 
3951                                                 if($.inArray(m.ot._get_type(this), vc) === -1) { d = false; return false; }
 
3953                                         if(d === false) { return false; }
 
3955                                 if(s.max_children !== -2 && mc !== -1) {
 
3956                                         ch = m.cr === -1 ? this.get_container().find("> ul > li").not(m.o).length : m.cr.find("> ul > li").not(m.o).length;
 
3957                                         if(ch + m.o.length > mc) { return false; }
 
3959                                 if(s.max_depth !== -2 && md !== -1) {
 
3961                                         if(md === 0) { return false; }
 
3962                                         if(typeof m.o.d === "undefined") {
 
3963                                                 // TODO: deal with progressive rendering and async when checking max_depth (how to know the depth of the moved node)
 
3965                                                 while(t.length > 0) {
 
3966                                                         t = t.find("> ul > li");
 
3971                                         if(md - m.o.d < 0) { return false; }
 
3975                         create_node : function (obj, position, js, callback, is_loaded, skip_check) {
 
3976                                 if(!skip_check && (is_loaded || this._is_loaded(obj))) {
 
3977                                         var p  = (typeof position == "string" && position.match(/^before|after$/i) && obj !== -1) ? this._get_parent(obj) : this._get_node(obj),
 
3978                                                 s  = this._get_settings().types,
 
3979                                                 mc = this._check("max_children", p),
 
3980                                                 md = this._check("max_depth", p),
 
3981                                                 vc = this._check("valid_children", p),
 
3983                                         if(typeof js === "string") { js = { data : js }; }
 
3984                                         if(!js) { js = {}; }
 
3985                                         if(vc === "none") { return false; } 
 
3987                                                 if(!js.attr || !js.attr[s.type_attr]) { 
 
3988                                                         if(!js.attr) { js.attr = {}; }
 
3989                                                         js.attr[s.type_attr] = vc[0]; 
 
3992                                                         if($.inArray(js.attr[s.type_attr], vc) === -1) { return false; }
 
3995                                         if(s.max_children !== -2 && mc !== -1) {
 
3996                                                 ch = p === -1 ? this.get_container().find("> ul > li").length : p.find("> ul > li").length;
 
3997                                                 if(ch + 1 > mc) { return false; }
 
3999                                         if(s.max_depth !== -2 && md !== -1 && (md - 1) < 0) { return false; }
 
4001                                 return this.__call_old(true, obj, position, js, callback, is_loaded, skip_check);
 
4009  * jsTree HTML plugin
 
4010  * The HTML data store. Datastores are build by replacing the `load_node` and `_is_loaded` functions.
 
4013         $.jstree.plugin("html_data", {
 
4014                 __init : function () { 
 
4015                         // this used to use html() and clean the whitespace, but this way any attached data was lost
 
4016                         this.data.html_data.original_container_html = this.get_container().find(" > ul > li").clone(true);
 
4017                         // remove white space from LI node - otherwise nodes appear a bit to the right
 
4018                         this.data.html_data.original_container_html.find("li").addBack().contents().filter(function() { return this.nodeType == 3; }).remove();
 
4023                         correct_state : true
 
4026                         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); },
 
4027                         _is_loaded : function (obj) { 
 
4028                                 obj = this._get_node(obj); 
 
4029                                 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;
 
4031                         load_node_html : function (obj, s_call, e_call) {
 
4033                                         s = this.get_settings().html_data,
 
4034                                         error_func = function () {},
 
4035                                         success_func = function () {};
 
4036                                 obj = this._get_node(obj);
 
4037                                 if(obj && obj !== -1) {
 
4038                                         if(obj.data("jstree_is_loading")) { return; }
 
4039                                         else { obj.data("jstree_is_loading",true); }
 
4042                                         case ($.isFunction(s.data)):
 
4043                                                 s.data.call(this, obj, $.proxy(function (d) {
 
4044                                                         if(d && d !== "" && d.toString && d.toString().replace(/^[\s\n]+$/,"") !== "") {
 
4046                                                                 if(!d.is("ul")) { d = $("<ul />").append(d); }
 
4047                                                                 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"); }
 
4048                                                                 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"); }
 
4049                                                                 this.clean_node(obj);
 
4050                                                                 if(s_call) { s_call.call(this); }
 
4053                                                                 if(obj && obj !== -1) {
 
4054                                                                         obj.children("a.jstree-loading").removeClass("jstree-loading");
 
4055                                                                         obj.removeData("jstree_is_loading");
 
4056                                                                         if(s.correct_state) { 
 
4057                                                                                 this.correct_state(obj);
 
4058                                                                                 if(s_call) { s_call.call(this); } 
 
4062                                                                         if(s.correct_state) { 
 
4063                                                                                 this.get_container().children("ul").empty();
 
4064                                                                                 if(s_call) { s_call.call(this); } 
 
4070                                         case (!s.data && !s.ajax):
 
4071                                                 if(!obj || obj == -1) {
 
4072                                                         this.get_container()
 
4073                                                                 .children("ul").empty()
 
4074                                                                 .append(this.data.html_data.original_container_html)
 
4075                                                                 .find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'> </ins>").end()
 
4076                                                                 .filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");
 
4079                                                 if(s_call) { s_call.call(this); }
 
4081                                         case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
 
4082                                                 if(!obj || obj == -1) {
 
4084                                                         if(!d.is("ul")) { d = $("<ul />").append(d); }
 
4085                                                         this.get_container()
 
4086                                                                 .children("ul").empty().append(d.children())
 
4087                                                                 .find("li, a").filter(function () { return !this.firstChild || !this.firstChild.tagName || this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'> </ins>").end()
 
4088                                                                 .filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");
 
4091                                                 if(s_call) { s_call.call(this); }
 
4093                                         case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
 
4094                                                 obj = this._get_node(obj);
 
4095                                                 error_func = function (x, t, e) {
 
4096                                                         var ef = this.get_settings().html_data.ajax.error; 
 
4097                                                         if(ef) { ef.call(this, x, t, e); }
 
4098                                                         if(obj != -1 && obj.length) {
 
4099                                                                 obj.children("a.jstree-loading").removeClass("jstree-loading");
 
4100                                                                 obj.removeData("jstree_is_loading");
 
4101                                                                 if(t === "success" && s.correct_state) { this.correct_state(obj); }
 
4104                                                                 if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); }
 
4106                                                         if(e_call) { e_call.call(this); }
 
4108                                                 success_func = function (d, t, x) {
 
4109                                                         var sf = this.get_settings().html_data.ajax.success; 
 
4110                                                         if(sf) { d = sf.call(this,d,t,x) || d; }
 
4111                                                         if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "")) {
 
4112                                                                 return error_func.call(this, x, t, "");
 
4116                                                                 if(!d.is("ul")) { d = $("<ul />").append(d); }
 
4117                                                                 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"); }
 
4118                                                                 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"); }
 
4119                                                                 this.clean_node(obj);
 
4120                                                                 if(s_call) { s_call.call(this); }
 
4123                                                                 if(obj && obj !== -1) {
 
4124                                                                         obj.children("a.jstree-loading").removeClass("jstree-loading");
 
4125                                                                         obj.removeData("jstree_is_loading");
 
4126                                                                         if(s.correct_state) { 
 
4127                                                                                 this.correct_state(obj);
 
4128                                                                                 if(s_call) { s_call.call(this); } 
 
4132                                                                         if(s.correct_state) { 
 
4133                                                                                 this.get_container().children("ul").empty();
 
4134                                                                                 if(s_call) { s_call.call(this); } 
 
4139                                                 s.ajax.context = this;
 
4140                                                 s.ajax.error = error_func;
 
4141                                                 s.ajax.success = success_func;
 
4142                                                 if(!s.ajax.dataType) { s.ajax.dataType = "html"; }
 
4143                                                 if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); }
 
4144                                                 if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
 
4151         // include the HTML data plugin by default
 
4152         $.jstree.defaults.plugins.push("html_data");
 
4157  * jsTree themeroller plugin
 
4158  * Adds support for jQuery UI themes. Include this at the end of your plugins list, also make sure "themes" is not included.
 
4161         $.jstree.plugin("themeroller", {
 
4162                 __init : function () {
 
4163                         var s = this._get_settings().themeroller;
 
4164                         this.get_container()
 
4165                                 .addClass("ui-widget-content")
 
4166                                 .addClass("jstree-themeroller")
 
4167                                 .delegate("a","mouseenter.jstree", function (e) {
 
4168                                         if(!$(e.currentTarget).hasClass("jstree-loading")) {
 
4169                                                 $(this).addClass(s.item_h);
 
4172                                 .delegate("a","mouseleave.jstree", function () {
 
4173                                         $(this).removeClass(s.item_h);
 
4175                                 .bind("init.jstree", $.proxy(function (e, data) { 
 
4176                                                 data.inst.get_container().find("> ul > li > .jstree-loading > ins").addClass("ui-icon-refresh");
 
4177                                                 this._themeroller(data.inst.get_container().find("> ul > li"));
 
4179                                 .bind("open_node.jstree create_node.jstree", $.proxy(function (e, data) { 
 
4180                                                 this._themeroller(data.rslt.obj);
 
4182                                 .bind("loaded.jstree refresh.jstree", $.proxy(function (e) {
 
4183                                                 this._themeroller();
 
4185                                 .bind("close_node.jstree", $.proxy(function (e, data) {
 
4186                                                 this._themeroller(data.rslt.obj);
 
4188                                 .bind("delete_node.jstree", $.proxy(function (e, data) {
 
4189                                                 this._themeroller(data.rslt.parent);
 
4191                                 .bind("correct_state.jstree", $.proxy(function (e, data) {
 
4193                                                         .children("ins.jstree-icon").removeClass(s.opened + " " + s.closed + " ui-icon").end()
 
4194                                                         .find("> a > ins.ui-icon")
 
4195                                                                 .filter(function() { 
 
4196                                                                         return this.className.toString()
 
4197                                                                                 .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"")
 
4198                                                                                 .indexOf("ui-icon-") === -1; 
 
4199                                                                 }).removeClass(s.item_open + " " + s.item_clsd).addClass(s.item_leaf || "jstree-no-icon");
 
4201                                 .bind("select_node.jstree", $.proxy(function (e, data) {
 
4202                                                 data.rslt.obj.children("a").addClass(s.item_a);
 
4204                                 .bind("deselect_node.jstree deselect_all.jstree", $.proxy(function (e, data) {
 
4205                                                 this.get_container()
 
4206                                                         .find("a." + s.item_a).removeClass(s.item_a).end()
 
4207                                                         .find("a.jstree-clicked").addClass(s.item_a);
 
4209                                 .bind("dehover_node.jstree", $.proxy(function (e, data) {
 
4210                                                 data.rslt.obj.children("a").removeClass(s.item_h);
 
4212                                 .bind("hover_node.jstree", $.proxy(function (e, data) {
 
4213                                                 this.get_container()
 
4214                                                         .find("a." + s.item_h).not(data.rslt.obj).removeClass(s.item_h);
 
4215                                                 data.rslt.obj.children("a").addClass(s.item_h);
 
4217                                 .bind("move_node.jstree", $.proxy(function (e, data) {
 
4218                                                 this._themeroller(data.rslt.o);
 
4219                                                 this._themeroller(data.rslt.op);
 
4222                 __destroy : function () {
 
4223                         var s = this._get_settings().themeroller,
 
4225                         $.each(s, function (i, v) {
 
4227                                 if(v.length) { c = c.concat(v); }
 
4229                         this.get_container()
 
4230                                 .removeClass("ui-widget-content")
 
4231                                 .find("." + c.join(", .")).removeClass(c.join(" "));
 
4234                         _themeroller : function (obj) {
 
4235                                 var s = this._get_settings().themeroller;
 
4236                                 obj = (!obj || obj == -1) ? this.get_container_ul() : this._get_node(obj);
 
4237                                 obj = (!obj || obj == -1) ? this.get_container_ul() : obj.parent();
 
4239                                         .find("li.jstree-closed")
 
4240                                                 .children("ins.jstree-icon").removeClass(s.opened).addClass("ui-icon " + s.closed).end()
 
4241                                                 .children("a").addClass(s.item)
 
4242                                                         .children("ins.jstree-icon").addClass("ui-icon")
 
4243                                                                 .filter(function() { 
 
4244                                                                         return this.className.toString()
 
4245                                                                                 .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"")
 
4246                                                                                 .indexOf("ui-icon-") === -1; 
 
4247                                                                 }).removeClass(s.item_leaf + " " + s.item_open).addClass(s.item_clsd || "jstree-no-icon")
 
4252                                         .find("li.jstree-open")
 
4253                                                 .children("ins.jstree-icon").removeClass(s.closed).addClass("ui-icon " + s.opened).end()
 
4254                                                 .children("a").addClass(s.item)
 
4255                                                         .children("ins.jstree-icon").addClass("ui-icon")
 
4256                                                                 .filter(function() { 
 
4257                                                                         return this.className.toString()
 
4258                                                                                 .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"")
 
4259                                                                                 .indexOf("ui-icon-") === -1; 
 
4260                                                                 }).removeClass(s.item_leaf + " " + s.item_clsd).addClass(s.item_open || "jstree-no-icon")
 
4265                                         .find("li.jstree-leaf")
 
4266                                                 .children("ins.jstree-icon").removeClass(s.closed + " ui-icon " + s.opened).end()
 
4267                                                 .children("a").addClass(s.item)
 
4268                                                         .children("ins.jstree-icon").addClass("ui-icon")
 
4269                                                                 .filter(function() { 
 
4270                                                                         return this.className.toString()
 
4271                                                                                 .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"")
 
4272                                                                                 .indexOf("ui-icon-") === -1; 
 
4273                                                                 }).removeClass(s.item_clsd + " " + s.item_open).addClass(s.item_leaf || "jstree-no-icon");
 
4277                         "opened"        : "ui-icon-triangle-1-se",
 
4278                         "closed"        : "ui-icon-triangle-1-e",
 
4279                         "item"          : "ui-state-default",
 
4280                         "item_h"        : "ui-state-hover",
 
4281                         "item_a"        : "ui-state-active",
 
4282                         "item_open"     : "ui-icon-folder-open",
 
4283                         "item_clsd"     : "ui-icon-folder-collapsed",
 
4284                         "item_leaf"     : "ui-icon-document"
 
4288                 var css_string = '' + 
 
4289                         '.jstree-themeroller .ui-icon { overflow:visible; } ' + 
 
4290                         '.jstree-themeroller a { padding:0 2px; } ' + 
 
4291                         '.jstree-themeroller .jstree-no-icon { display:none; }';
 
4292                 $.vakata.css.add_sheet({ str : css_string, title : "jstree" });
 
4298  * jsTree unique plugin
 
4299  * Forces different names amongst siblings (still a bit experimental)
 
4300  * NOTE: does not check language versions (it will not be possible to have nodes with the same title, even in different languages)
 
4303         $.jstree.plugin("unique", {
 
4304                 __init : function () {
 
4305                         this.get_container()
 
4306                                 .bind("before.jstree", $.proxy(function (e, data) { 
 
4307                                                 var nms = [], res = true, p, t;
 
4308                                                 if(data.func == "move_node") {
 
4309                                                         // obj, ref, position, is_copy, is_prepared, skip_check
 
4310                                                         if(data.args[4] === true) {
 
4311                                                                 if(data.args[0].o && data.args[0].o.length) {
 
4312                                                                         data.args[0].o.children("a").each(function () { nms.push($(this).text().replace(/^\s+/g,"")); });
 
4313                                                                         res = this._check_unique(nms, data.args[0].np.find("> ul > li").not(data.args[0].o), "move_node");
 
4317                                                 if(data.func == "create_node") {
 
4318                                                         // obj, position, js, callback, is_loaded
 
4319                                                         if(data.args[4] || this._is_loaded(data.args[0])) {
 
4320                                                                 p = this._get_node(data.args[0]);
 
4321                                                                 if(data.args[1] && (data.args[1] === "before" || data.args[1] === "after")) {
 
4322                                                                         p = this._get_parent(data.args[0]);
 
4323                                                                         if(!p || p === -1) { p = this.get_container(); }
 
4325                                                                 if(typeof data.args[2] === "string") { nms.push(data.args[2]); }
 
4326                                                                 else if(!data.args[2] || !data.args[2].data) { nms.push(this._get_string("new_node")); }
 
4327                                                                 else { nms.push(data.args[2].data); }
 
4328                                                                 res = this._check_unique(nms, p.find("> ul > li"), "create_node");
 
4331                                                 if(data.func == "rename_node") {
 
4333                                                         nms.push(data.args[1]);
 
4334                                                         t = this._get_node(data.args[0]);
 
4335                                                         p = this._get_parent(t);
 
4336                                                         if(!p || p === -1) { p = this.get_container(); }
 
4337                                                         res = this._check_unique(nms, p.find("> ul > li").not(t), "rename_node");
 
4340                                                         e.stopPropagation();
 
4346                         error_callback : $.noop
 
4349                         _check_unique : function (nms, p, func) {
 
4350                                 var cnms = [], ok = true;
 
4351                                 p.children("a").each(function () { cnms.push($(this).text().replace(/^\s+/g,"")); });
 
4352                                 if(!cnms.length || !nms.length) { return true; }
 
4353                                 $.each(nms, function (i, v) {
 
4354                                         if($.inArray(v, cnms) !== -1) {
 
4360                                         this._get_settings().unique.error_callback.call(null, nms, p, func);
 
4364                         check_move : function () {
 
4365                                 if(!this.__call_old()) { return false; }
 
4366                                 var p = this._get_move(), nms = [];
 
4367                                 if(p.o && p.o.length) {
 
4368                                         p.o.children("a").each(function () { nms.push($(this).text().replace(/^\s+/g,"")); });
 
4369                                         return this._check_unique(nms, p.np.find("> ul > li").not(p.o), "check_move");
 
4379  * jsTree wholerow plugin
 
4380  * Makes select and hover work on the entire width of the node
 
4381  * MAY BE HEAVY IN LARGE DOM
 
4384         $.jstree.plugin("wholerow", {
 
4385                 __init : function () {
 
4386                         if(!this.data.ui) { throw "jsTree wholerow: jsTree UI plugin not included."; }
 
4387                         this.data.wholerow.html = false;
 
4388                         this.data.wholerow.to = false;
 
4389                         this.get_container()
 
4390                                 .bind("init.jstree", $.proxy(function (e, data) { 
 
4391                                                 this._get_settings().core.animation = 0;
 
4393                                 .bind("open_node.jstree create_node.jstree clean_node.jstree loaded.jstree", $.proxy(function (e, data) { 
 
4394                                                 this._prepare_wholerow_span( data && data.rslt && data.rslt.obj ? data.rslt.obj : -1 );
 
4396                                 .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) { 
 
4397                                                 if(this.data.to) { clearTimeout(this.data.to); }
 
4398                                                 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);
 
4400                                 .bind("deselect_all.jstree", $.proxy(function (e, data) { 
 
4401                                                 this.get_container().find(" > .jstree-wholerow .jstree-clicked").removeClass("jstree-clicked " + (this.data.themeroller ? this._get_settings().themeroller.item_a : "" ));
 
4403                                 .bind("select_node.jstree deselect_node.jstree ", $.proxy(function (e, data) { 
 
4404                                                 data.rslt.obj.each(function () { 
 
4405                                                         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)) + ")");
 
4406                                                         // ref.children("a")[e.type === "select_node" ? "addClass" : "removeClass"]("jstree-clicked");
 
4407                                                         ref.children("a").attr("class",data.rslt.obj.children("a").attr("class"));
 
4410                                 .bind("hover_node.jstree dehover_node.jstree", $.proxy(function (e, data) { 
 
4411                                                 this.get_container().find(" > .jstree-wholerow .jstree-hovered").removeClass("jstree-hovered " + (this.data.themeroller ? this._get_settings().themeroller.item_h : "" ));
 
4412                                                 if(e.type === "hover_node") {
 
4413                                                         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)) + ")");
 
4414                                                         // ref.children("a").addClass("jstree-hovered");
 
4415                                                         ref.children("a").attr("class",data.rslt.obj.children(".jstree-hovered").attr("class"));
 
4418                                 .delegate(".jstree-wholerow-span, ins.jstree-icon, li", "click.jstree", function (e) {
 
4419                                                 var n = $(e.currentTarget);
 
4420                                                 if(e.target.tagName === "A" || (e.target.tagName === "INS" && n.closest("li").is(".jstree-open, .jstree-closed"))) { return; }
 
4421                                                 n.closest("li").children("a:visible:eq(0)").click();
 
4422                                                 e.stopImmediatePropagation();
 
4424                                 .delegate("li", "mouseover.jstree", $.proxy(function (e) {
 
4425                                                 e.stopImmediatePropagation();
 
4426                                                 if($(e.currentTarget).children(".jstree-hovered, .jstree-clicked").length) { return false; }
 
4427                                                 this.hover_node(e.currentTarget);
 
4430                                 .delegate("li", "mouseleave.jstree", $.proxy(function (e) {
 
4431                                                 if($(e.currentTarget).children("a").hasClass("jstree-hovered").length) { return; }
 
4432                                                 this.dehover_node(e.currentTarget);
 
4434                         if(is_ie7 || is_ie6) {
 
4435                                 $.vakata.css.add_sheet({ str : ".jstree-" + this.get_index() + " { position:relative; } ", title : "jstree" });
 
4440                 __destroy : function () {
 
4441                         this.get_container().children(".jstree-wholerow").remove();
 
4442                         this.get_container().find(".jstree-wholerow-span").remove();
 
4445                         _prepare_wholerow_span : function (obj) {
 
4446                                 obj = !obj || obj == -1 ? this.get_container().find("> ul > li") : this._get_node(obj);
 
4447                                 if(obj === false) { return; } // added for removing root nodes
 
4448                                 obj.each(function () {
 
4449                                         $(this).find("li").addBack().each(function () {
 
4451                                                 if($t.children(".jstree-wholerow-span").length) { return true; }
 
4452                                                 $t.prepend("<span class='jstree-wholerow-span' style='width:" + ($t.parentsUntil(".jstree","li").length * 18) + "px;'> </span>");
 
4456                         _prepare_wholerow_ul : function () {
 
4457                                 var o = this.get_container().children("ul").eq(0), h = o.html();
 
4458                                 o.addClass("jstree-wholerow-real");
 
4459                                 if(this.data.wholerow.last_html !== h) {
 
4460                                         this.data.wholerow.last_html = h;
 
4461                                         this.get_container().children(".jstree-wholerow").remove();
 
4462                                         this.get_container().append(
 
4463                                                 o.clone().removeClass("jstree-wholerow-real")
 
4464                                                         .wrapAll("<div class='jstree-wholerow' />").parent()
 
4465                                                         .width(o.parent()[0].scrollWidth)
 
4466                                                         .css("top", (o.height() + ( is_ie7 ? 5 : 0)) * -1 )
 
4467                                                         .find("li[id]").each(function () { this.removeAttribute("id"); }).end()
 
4474                 var css_string = '' + 
 
4475                         '.jstree .jstree-wholerow-real { position:relative; z-index:1; } ' + 
 
4476                         '.jstree .jstree-wholerow-real li { cursor:pointer; } ' + 
 
4477                         '.jstree .jstree-wholerow-real a { border-left-color:transparent !important; border-right-color:transparent !important; } ' + 
 
4478                         '.jstree .jstree-wholerow { position:relative; z-index:0; height:0; } ' + 
 
4479                         '.jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { width:100%; } ' + 
 
4480                         '.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li, .jstree .jstree-wholerow a { margin:0 !important; padding:0 !important; } ' + 
 
4481                         '.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { background:transparent !important; }' + 
 
4482                         '.jstree .jstree-wholerow ins, .jstree .jstree-wholerow span, .jstree .jstree-wholerow input { display:none !important; }' + 
 
4483                         '.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; } ' + 
 
4484                         '.jstree .jstree-wholerow-span { position:absolute; left:0; margin:0px; padding:0; height:18px; border-width:0; padding:0; z-index:0; }';
 
4487                                 '.jstree .jstree-wholerow a { display:block; height:18px; margin:0; padding:0; border:0; } ' + 
 
4488                                 '.jstree .jstree-wholerow-real a { border-color:transparent !important; } ';
 
4490                 if(is_ie7 || is_ie6) {
 
4492                                 '.jstree .jstree-wholerow, .jstree .jstree-wholerow li, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow a { margin:0; padding:0; line-height:18px; } ' + 
 
4493                                 '.jstree .jstree-wholerow a { display:block; height:18px; line-height:18px; overflow:hidden; } ';
 
4495                 $.vakata.css.add_sheet({ str : css_string, title : "jstree" });
 
4501 * jsTree model plugin
 
4502 * This plugin gets jstree to use a class model to retrieve data, creating great dynamism
 
4505         var nodeInterface = ["getChildren","getChildrenCount","getAttr","getName","getProps"],
 
4506                 validateInterface = function(obj, inter) {
 
4509                         inter = [].concat(inter);
 
4510                         $.each(inter, function (i, v) {
 
4511                                 if(!$.isFunction(obj[v])) { valid = false; return false; }
 
4515         $.jstree.plugin("model", {
 
4516                 __init : function () {
 
4517                         if(!this.data.json_data) { throw "jsTree model: jsTree json_data plugin not included."; }
 
4518                         this._get_settings().json_data.data = function (n, b) {
 
4519                                 var obj = (n == -1) ? this._get_settings().model.object : n.data("jstree_model");
 
4520                                 if(!validateInterface(obj, nodeInterface)) { return b.call(null, false); }
 
4521                                 if(this._get_settings().model.async) {
 
4522                                         obj.getChildren($.proxy(function (data) {
 
4523                                                 this.model_done(data, b);
 
4527                                         this.model_done(obj.getChildren(), b);
 
4537                         model_done : function (data, callback) {
 
4539                                         s = this._get_settings(),
 
4542                                 if(!$.isArray(data)) { data = [data]; }
 
4543                                 $.each(data, function (i, nd) {
 
4544                                         var r = nd.getProps() || {};
 
4545                                         r.attr = nd.getAttr() || {};
 
4546                                         if(nd.getChildrenCount()) { r.state = "closed"; }
 
4547                                         r.data = nd.getName();
 
4548                                         if(!$.isArray(r.data)) { r.data = [r.data]; }
 
4549                                         if(_this.data.types && $.isFunction(nd.getType)) {
 
4550                                                 r.attr[s.types.type_attr] = nd.getType();
 
4552                                         if(r.attr.id && s.model.id_prefix) { r.attr.id = s.model.id_prefix + r.attr.id; }
 
4553                                         if(!r.metadata) { r.metadata = { }; }
 
4554                                         r.metadata.jstree_model = nd;
 
4557                                 callback.call(null, ret);