fmsystem-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Fmsystem-commits] [14436] update treeview from upstream


From: Sigurd Nes
Subject: [Fmsystem-commits] [14436] update treeview from upstream
Date: Fri, 20 Nov 2015 15:05:42 +0000

Revision: 14436
          http://svn.sv.gnu.org/viewvc/?view=rev&root=fmsystem&revision=14436
Author:   sigurdne
Date:     2015-11-20 15:05:42 +0000 (Fri, 20 Nov 2015)
Log Message:
-----------
update treeview from upstream

Modified Paths:
--------------
    branches/dev-syncromind/phpgwapi/js/jquery/treeview/jstree.js
    branches/dev-syncromind/phpgwapi/js/jquery/treeview/jstree.min.js
    branches/dev-syncromind/phpgwapi/js/jquery/treeview/themes/default/style.css
    
branches/dev-syncromind/phpgwapi/js/jquery/treeview/themes/default/style.min.css
    
branches/dev-syncromind/phpgwapi/js/jquery/treeview/themes/default-dark/style.css
    
branches/dev-syncromind/phpgwapi/js/jquery/treeview/themes/default-dark/style.min.css

Modified: branches/dev-syncromind/phpgwapi/js/jquery/treeview/jstree.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/jquery/treeview/jstree.js       
2015-11-20 15:01:27 UTC (rev 14435)
+++ branches/dev-syncromind/phpgwapi/js/jquery/treeview/jstree.js       
2015-11-20 15:05:42 UTC (rev 14436)
@@ -1,11 +1,11 @@
-/*globals jQuery, define, exports, require, window, document, postMessage */
+/*globals jQuery, define, module, exports, require, window, document, 
postMessage */
 (function (factory) {
        "use strict";
        if (typeof define === 'function' && define.amd) {
                define(['jquery'], factory);
        }
-       else if(typeof exports === 'object') {
-               factory(require('jquery'));
+       else if(typeof module !== 'undefined' && module.exports) {
+               module.exports = factory(require('jquery'));
        }
        else {
                factory(jQuery);
@@ -13,7 +13,7 @@
 }(function ($, undefined) {
        "use strict";
 /*!
- * jsTree 3.0.8
+ * jsTree 3.2.1
  * http://jstree.com/
  *
  * Copyright (c) 2014 Ivan Bozhanov (http://vakata.com)
@@ -22,7 +22,7 @@
  *   http://www.opensource.org/licenses/mit-license.php
  */
 /*!
- * if using jslint please allow for the jQuery global and use following 
options: 
+ * if using jslint please allow for the jQuery global and use following 
options:
  * jslint: browser: true, ass: true, bitwise: true, continue: true, nomen: 
true, plusplus: true, regexp: true, unparam: true, todo: true, white: true
  */
 
@@ -42,18 +42,19 @@
                ccp_inst = false,
                themes_loaded = [],
                src = $('script:last').attr('src'),
-               _d = document, _node = _d.createElement('LI'), _temp1, _temp2;
+               document = window.document, // local variable is always faster 
to access then a global
+               _node = document.createElement('LI'), _temp1, _temp2;
 
        _node.setAttribute('role', 'treeitem');
-       _temp1 = _d.createElement('I');
+       _temp1 = document.createElement('I');
        _temp1.className = 'jstree-icon jstree-ocl';
        _temp1.setAttribute('role', 'presentation');
        _node.appendChild(_temp1);
-       _temp1 = _d.createElement('A');
+       _temp1 = document.createElement('A');
        _temp1.className = 'jstree-anchor';
        _temp1.setAttribute('href','#');
        _temp1.setAttribute('tabindex','-1');
-       _temp2 = _d.createElement('I');
+       _temp2 = document.createElement('I');
        _temp2.className = 'jstree-icon jstree-themeicon';
        _temp2.setAttribute('role', 'presentation');
        _temp1.appendChild(_temp2);
@@ -66,11 +67,11 @@
         * @name $.jstree
         */
        $.jstree = {
-               /** 
+               /**
                 * specifies the jstree version in use
                 * @name $.jstree.version
                 */
-               version : '3.0.8',
+               version : '3.2.1',
                /**
                 * holds all the default options used when creating new 
instances
                 * @name $.jstree.defaults
@@ -88,7 +89,8 @@
                 */
                plugins : {},
                path : src && src.indexOf('/') !== -1 ? 
src.replace(/\/[^\/]+$/,'') : '',
-               idregex : /[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%]/g
+               idregex : /[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g,
+               root : '#'
        };
        /**
         * creates a jstree instance
@@ -109,6 +111,7 @@
                                tmp = tmp.plugin(k, options[k]);
                        }
                });
+               $(el).data('jstree', tmp);
                tmp.init(el, options);
                return tmp;
        };
@@ -168,7 +171,7 @@
        $.jstree.reference = function (needle) {
                var tmp = null,
                        obj = null;
-               if(needle && needle.id) { needle = needle.id; }
+               if(needle && needle.id && (!needle.tagName || 
!needle.nodeType)) { needle = needle.id; }
 
                if(!obj || !obj.length) {
                        try { obj = $(needle); } catch (ignore) { }
@@ -191,14 +194,14 @@
                return tmp;
        };
        /**
-        * Create an instance, get an instance or invoke a command on a 
instance. 
-        * 
+        * Create an instance, get an instance or invoke a command on a 
instance.
+        *
         * If there is no instance associated with the current node a new one 
is created and `arg` is used to extend `$.jstree.defaults` for this new 
instance. There would be no return value (chaining is not broken).
-        * 
+        *
         * If there is an existing instance and `arg` is a string the command 
specified by `arg` is executed on the instance, with any additional arguments 
passed to the function. If the function returns a value it will be returned 
(chaining could break depending on function).
-        * 
+        *
         * If there is an existing instance and `arg` is not a string the 
instance itself is returned (similar to `$.jstree.reference`).
-        * 
+        *
         * In any other case - nothing is returned and chaining is not broken.
         *
         * __Examples__
@@ -230,7 +233,7 @@
                                null;
                        // if there is no instance and no method is being 
called - create one
                        if(!instance && !is_method && (arg === undefined || 
$.isPlainObject(arg))) {
-                               $(this).data('jstree', new 
$.jstree.create(this, arg));
+                               $.jstree.create(this, arg);
                        }
                        // if there is an instance and no method is called - 
return the instance
                        if( (instance && !is_method) || arg === true ) {
@@ -271,14 +274,14 @@
        $.jstree.defaults.core = {
                /**
                 * data configuration
-                * 
+                *
                 * If left as `false` the HTML inside the jstree container 
element is used to populate the tree (that should be an unordered list with 
list items).
                 *
                 * You can also pass in a HTML string or a JSON array here.
-                * 
-                * It is possible to pass in a standard jQuery-like AJAX config 
and jstree will automatically determine if the response is JSON or HTML and use 
that to populate the tree. 
+                *
+                * It is possible to pass in a standard jQuery-like AJAX config 
and jstree will automatically determine if the response is JSON or HTML and use 
that to populate the tree.
                 * In addition to the standard jQuery ajax options here you can 
suppy functions for `data` and `url`, the functions will be run in the current 
instance's scope and a param will be passed indicating which node is being 
loaded, the return value of those functions will be used.
-                * 
+                *
                 * The last option is to specify a function, that function will 
receive the node being loaded as argument and a second param which is a 
function which should be called with the result.
                 *
                 * __Examples__
@@ -307,7 +310,7 @@
                 *                              }
                 *                      ]
                 *              });
-                *      
+                *
                 *      // function
                 *      $('#tree').jstree({
                 *              'core' : {
@@ -315,7 +318,7 @@
                 *                              callback.call(this, ['Root 1', 
'Root 2']);
                 *                      }
                 *              });
-                * 
+                *
                 * @name $.jstree.defaults.core.data
                 */
                data                    : false,
@@ -355,7 +358,7 @@
                 *                      }
                 *              }
                 *      });
-                * 
+                *
                 * @name $.jstree.defaults.core.check_callback
                 */
                check_callback  : false,
@@ -434,7 +437,12 @@
                 * Force node text to plain text (and escape HTML). Defaults to 
`false`
                 * @name $.jstree.defaults.core.force_text
                 */
-               force_text : false
+               force_text : false,
+               /**
+                * Should the node should be toggled if the text is double 
clicked . Defaults to `true`
+                * @name $.jstree.defaults.core.dblclick_toggle
+                */
+               dblclick_toggle : true
        };
        $.jstree.core.prototype = {
                /**
@@ -455,7 +463,7 @@
                        return this;
                },
                /**
-                * used to decorate an instance with a plugin. Used internally.
+                * initialize the instance. Used internally.
                 * @private
                 * @name init(el, optons)
                 * @param {DOMElement|jQuery|String} el the element we are 
transforming
@@ -464,16 +472,7 @@
                 */
                init : function (el, options) {
                        this._model = {
-                               data : {
-                                       '#' : {
-                                               id : '#',
-                                               parent : null,
-                                               parents : [],
-                                               children : [],
-                                               children_d : [],
-                                               state : { loaded : false }
-                                       }
-                               },
+                               data : {},
                                changed : [],
                                force_full_redraw : false,
                                redraw_timeout : false,
@@ -484,10 +483,17 @@
                                        disabled : false
                                }
                        };
+                       this._model.data[$.jstree.root] = {
+                               id : $.jstree.root,
+                               parent : null,
+                               parents : [],
+                               children : [],
+                               children_d : [],
+                               state : { loaded : false }
+                       };
 
                        this.element = $(el).addClass('jstree jstree-' + 
this._id);
                        this.settings = options;
-                       this.element.bind("destroyed", $.proxy(this.teardown, 
this));
 
                        this._data.core.ready = false;
                        this._data.core.loaded = false;
@@ -525,7 +531,7 @@
                         * @name loading.jstree
                         */
                        this.trigger("loading");
-                       this.load_node('#');
+                       this.load_node($.jstree.root);
                },
                /**
                 * destroy an instance
@@ -541,7 +547,6 @@
                                catch (ignore) { }
                        }
                        if(!keep_html) { this.element.empty(); }
-                       this.element.unbind("destroyed", this.teardown);
                        this.teardown();
                },
                /**
@@ -566,9 +571,11 @@
                 */
                bind : function () {
                        var word = '',
-                               tout = null;
+                               tout = null,
+                               was_click = 0;
                        this.element
-                               .on("dblclick.jstree", function () {
+                               .on("dblclick.jstree", function (e) {
+                                               if(e.target.tagName && 
e.target.tagName.toLowerCase() === "input") { return true; }
                                                if(document.selection && 
document.selection.empty) {
                                                        
document.selection.empty();
                                                }
@@ -582,16 +589,32 @@
                                                        }
                                                }
                                        })
+                               .on("mousedown.jstree", $.proxy(function (e) {
+                                               if(e.target === 
this.element[0]) {
+                                                       e.preventDefault(); // 
prevent losing focus when clicking scroll arrows (FF, Chrome)
+                                                       was_click = +(new 
Date()); // ie does not allow to prevent losing focus
+                                               }
+                                       }, this))
+                               .on("mousedown.jstree", ".jstree-ocl", function 
(e) {
+                                               e.preventDefault(); // prevent 
any node inside from losing focus when clicking the open/close icon
+                                       })
                                .on("click.jstree", ".jstree-ocl", 
$.proxy(function (e) {
                                                this.toggle_node(e.target);
                                        }, this))
+                               .on("dblclick.jstree", ".jstree-anchor", 
$.proxy(function (e) {
+                                               if(e.target.tagName && 
e.target.tagName.toLowerCase() === "input") { return true; }
+                                               
if(this.settings.core.dblclick_toggle) {
+                                                       
this.toggle_node(e.target);
+                                               }
+                                       }, this))
                                .on("click.jstree", ".jstree-anchor", 
$.proxy(function (e) {
                                                e.preventDefault();
                                                if(e.currentTarget !== 
document.activeElement) { $(e.currentTarget).focus(); }
                                                
this.activate_node(e.currentTarget, e);
                                        }, this))
                                .on('keydown.jstree', '.jstree-anchor', 
$.proxy(function (e) {
-                                               if(e.target.tagName === 
"INPUT") { return true; }
+                                               if(e.target.tagName && 
e.target.tagName.toLowerCase() === "input") { return true; }
+                                               if(e.which !== 32 && e.which 
!== 13 && (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey)) { return true; }
                                                var o = null;
                                                if(this._data.core.rtl) {
                                                        if(e.which === 37) { 
e.which = 39; }
@@ -615,7 +638,7 @@
                                                                }
                                                                else {
                                                                        o = 
this.get_parent(e.currentTarget);
-                                                                       if(o && 
o.id !== '#') { this.get_node(o, true).children('.jstree-anchor').focus(); }
+                                                                       if(o && 
o.id !== $.jstree.root) { this.get_node(o, 
true).children('.jstree-anchor').focus(); }
                                                                }
                                                                break;
                                                        case 38: // up
@@ -650,12 +673,12 @@
                                                                
e.preventDefault();
                                                                
this.element.find('.jstree-anchor').filter(':visible').last().focus();
                                                                break;
-                                                       /*
+                                                       /*!
                                                        // delete
                                                        case 46:
                                                                
e.preventDefault();
                                                                o = 
this.get_node(e.currentTarget);
-                                                               if(o && o.id && 
o.id !== '#') {
+                                                               if(o && o.id && 
o.id !== $.jstree.root) {
                                                                        o = 
this.is_selected(o) ? this.get_selected() : o;
                                                                        
this.delete_node(o);
                                                                }
@@ -664,7 +687,7 @@
                                                        case 113:
                                                                
e.preventDefault();
                                                                o = 
this.get_node(e.currentTarget);
-                                                               if(o && o.id && 
o.id !== '#') {
+                                                               if(o && o.id && 
o.id !== $.jstree.root) {
                                                                        // 
this.edit(o);
                                                                }
                                                                break;
@@ -676,7 +699,7 @@
                                        }, this))
                                .on("load_node.jstree", $.proxy(function (e, 
data) {
                                                if(data.status) {
-                                                       if(data.node.id === '#' 
&& !this._data.core.loaded) {
+                                                       if(data.node.id === 
$.jstree.root && !this._data.core.loaded) {
                                                                
this._data.core.loaded = true;
                                                                
if(this._firstChild(this.get_container_ul()[0])) {
                                                                        
this.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id);
@@ -688,33 +711,37 @@
                                                                 */
                                                                
this.trigger("loaded");
                                                        }
-                                                       
if(!this._data.core.ready && 
!this.get_container_ul().find('.jstree-loading').length) {
-                                                               
this._data.core.ready = true;
-                                                               
if(this._data.core.selected.length) {
-                                                                       
if(this.settings.core.expand_selected_onload) {
-                                                                               
var tmp = [], i, j;
-                                                                               
for(i = 0, j = this._data.core.selected.length; i < j; i++) {
-                                                                               
        tmp = tmp.concat(this._model.data[this._data.core.selected[i]].parents);
+                                                       
if(!this._data.core.ready) {
+                                                               
setTimeout($.proxy(function() {
+                                                                       
if(this.element && !this.get_container_ul().find('.jstree-loading').length) {
+                                                                               
this._data.core.ready = true;
+                                                                               
if(this._data.core.selected.length) {
+                                                                               
        if(this.settings.core.expand_selected_onload) {
+                                                                               
                var tmp = [], i, j;
+                                                                               
                for(i = 0, j = this._data.core.selected.length; i < j; i++) {
+                                                                               
                        tmp = 
tmp.concat(this._model.data[this._data.core.selected[i]].parents);
+                                                                               
                }
+                                                                               
                tmp = $.vakata.array_unique(tmp);
+                                                                               
                for(i = 0, j = tmp.length; i < j; i++) {
+                                                                               
                        this.open_node(tmp[i], false, 0);
+                                                                               
                }
+                                                                               
        }
+                                                                               
        this.trigger('changed', { 'action' : 'ready', 'selected' : 
this._data.core.selected });
                                                                                
}
-                                                                               
tmp = $.vakata.array_unique(tmp);
-                                                                               
for(i = 0, j = tmp.length; i < j; i++) {
-                                                                               
        this.open_node(tmp[i], false, 0);
-                                                                               
}
+                                                                               
/**
+                                                                               
 * triggered after all nodes are finished loading
+                                                                               
 * @event
+                                                                               
 * @name ready.jstree
+                                                                               
 */
+                                                                               
this.trigger("ready");
                                                                        }
-                                                                       
this.trigger('changed', { 'action' : 'ready', 'selected' : 
this._data.core.selected });
-                                                               }
-                                                               /**
-                                                                * triggered 
after all nodes are finished loading
-                                                                * @event
-                                                                * @name 
ready.jstree
-                                                                */
-                                                               
setTimeout($.proxy(function () { this.trigger("ready"); }, this), 0);
+                                                               }, this), 0);
                                                        }
                                                }
                                        }, this))
                                // quick searching when the tree is focused
                                .on('keypress.jstree', $.proxy(function (e) {
-                                               if(e.target.tagName === 
"INPUT") { return true; }
+                                               if(e.target.tagName && 
e.target.tagName.toLowerCase() === "input") { return true; }
                                                if(tout) { clearTimeout(tout); }
                                                tout = setTimeout(function () {
                                                        word = '';
@@ -748,7 +775,7 @@
                                                        if(end) { return; }
                                                }
                                                // list nodes that start with 
that letter (only if word consists of a single char)
-                                               if(new RegExp('^' + chr + 
'+$').test(word)) {
+                                               if(new RegExp('^' + 
chr.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '+$').test(word)) {
                                                        // search for the next 
node starting with that letter
                                                        col.slice(ind + 
1).each($.proxy(function (i, v) {
                                                                
if($(v).text().toLowerCase().charAt(0) === chr) {
@@ -787,6 +814,7 @@
                                .on('blur.jstree', '.jstree-anchor', 
$.proxy(function (e) {
                                                this._data.core.focused = null;
                                                
$(e.currentTarget).filter('.jstree-hovered').mouseleave();
+                                               this.element.attr('tabindex', 
'0');
                                        }, this))
                                .on('focus.jstree', '.jstree-anchor', 
$.proxy(function (e) {
                                                var tmp = 
this.get_node(e.currentTarget);
@@ -795,10 +823,15 @@
                                                }
                                                
this.element.find('.jstree-hovered').not(e.currentTarget).mouseleave();
                                                $(e.currentTarget).mouseenter();
+                                               this.element.attr('tabindex', 
'-1');
                                        }, this))
                                .on('focus.jstree', $.proxy(function () {
-                                               if(!this._data.core.focused) {
-                                                       
this.get_node(this.element.attr('aria-activedescendant'), true).find('> 
.jstree-anchor').focus();
+                                               if(+(new Date()) - was_click > 
500 && !this._data.core.focused) {
+                                                       was_click = 0;
+                                                       var act = 
this.get_node(this.element.attr('aria-activedescendant'), true);
+                                                       if(act) {
+                                                               act.find('> 
.jstree-anchor').focus();
+                                                       }
                                                }
                                        }, this))
                                .on('mouseenter.jstree', '.jstree-anchor', 
$.proxy(function (e) {
@@ -929,14 +962,14 @@
                                        obj = 
this._model.data[dom.closest('.jstree-node').attr('id')];
                                }
                                else if((dom = $(obj, this.element)).length && 
dom.hasClass('jstree')) {
-                                       obj = this._model.data['#'];
+                                       obj = this._model.data[$.jstree.root];
                                }
                                else {
                                        return false;
                                }
 
                                if(as_dom) {
-                                       obj = obj.id === '#' ? this.element : 
$('#' + obj.id.replace($.jstree.idregex,'\\$&'), this.element);
+                                       obj = obj.id === $.jstree.root ? 
this.element : $('#' + obj.id.replace($.jstree.idregex,'\\$&'), this.element);
                                }
                                return obj;
                        } catch (ex) { return false; }
@@ -951,7 +984,7 @@
                 */
                get_path : function (obj, glue, ids) {
                        obj = obj.parents ? obj : this.get_node(obj);
-                       if(!obj || obj.id === '#' || !obj.parents) {
+                       if(!obj || obj.id === $.jstree.root || !obj.parents) {
                                return false;
                        }
                        var i, j, p = [];
@@ -1005,7 +1038,7 @@
                        if(tmp !== null) {
                                return $(tmp);
                        }
-                       return 
obj.parentsUntil(".jstree",".jstree-node").next(".jstree-node:visible").first();
+                       return 
obj.parentsUntil(".jstree",".jstree-node").nextAll(".jstree-node:visible").first();
                },
                /**
                 * get the previous visible node that is above the `obj` node. 
If `strict` is set to `true` only sibling nodes are returned.
@@ -1056,7 +1089,7 @@
                 */
                get_parent : function (obj) {
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        return obj.parent;
@@ -1174,14 +1207,22 @@
                                        this.trigger('changed', { 'action' : 
'load_node', 'node' : obj, 'selected' : this._data.core.selected });
                                }
                        }
+                       obj.state.failed = false;
                        obj.state.loading = true;
                        this.get_node(obj, 
true).addClass("jstree-loading").attr('aria-busy',true);
                        this._load_node(obj, $.proxy(function (status) {
                                obj = this._model.data[obj.id];
                                obj.state.loading = false;
                                obj.state.loaded = status;
-                               var dom = this.get_node(obj, true);
-                               if(obj.state.loaded && !obj.children.length && 
dom && dom.length && !dom.hasClass('jstree-leaf')) {
+                               obj.state.failed = !obj.state.loaded;
+                               var dom = this.get_node(obj, true), i = 0, j = 
0, m = this._model.data, has_children = false;
+                               for(i = 0, j = obj.children.length; i < j; i++) 
{
+                                       if(m[obj.children[i]] && 
!m[obj.children[i]].state.hidden) {
+                                               has_children = true;
+                                               break;
+                                       }
+                               }
+                               if(obj.state.loaded && !has_children && dom && 
dom.length && !dom.hasClass('jstree-leaf')) {
                                        dom.removeClass('jstree-closed 
jstree-open').addClass('jstree-leaf');
                                }
                                
dom.removeClass("jstree-loading").attr('aria-busy',false);
@@ -1209,9 +1250,9 @@
                _load_nodes : function (nodes, callback, is_callback) {
                        var r = true,
                                c = function () { this._load_nodes(nodes, 
callback, true); },
-                               m = this._model.data, i, j;
+                               m = this._model.data, i, j, tmp = [];
                        for(i = 0, j = nodes.length; i < j; i++) {
-                               if(m[nodes[i]] && (!m[nodes[i]].state.loaded || 
!is_callback)) {
+                               if(m[nodes[i]] && ( (!m[nodes[i]].state.loaded 
&& !m[nodes[i]].state.failed) || !is_callback)) {
                                        if(!this.is_loading(nodes[i])) {
                                                this.load_node(nodes[i], c);
                                        }
@@ -1219,8 +1260,13 @@
                                }
                        }
                        if(r) {
+                               for(i = 0, j = nodes.length; i < j; i++) {
+                                       if(m[nodes[i]] && 
m[nodes[i]].state.loaded) {
+                                               tmp.push(nodes[i]);
+                                       }
+                               }
                                if(callback && !callback.done) {
-                                       callback.call(this, nodes);
+                                       callback.call(this, tmp);
                                        callback.done = true;
                                }
                        }
@@ -1233,7 +1279,7 @@
                 * @trigger load_all.jstree
                 */
                load_all : function (obj, callback) {
-                       if(!obj) { obj = '#'; }
+                       if(!obj) { obj = $.jstree.root; }
                        obj = this.get_node(obj);
                        if(!obj) { return false; }
                        var to_load = [],
@@ -1276,7 +1322,7 @@
                        var s = this.settings.core.data, t;
                        // use original HTML
                        if(!s) {
-                               if(obj.id === '#') {
+                               if(obj.id === $.jstree.root) {
                                        return this._append_html_data(obj, 
this._data.core.original_container_html.clone(true), function (status) {
                                                callback.call(this, status);
                                        });
@@ -1284,14 +1330,14 @@
                                else {
                                        return callback.call(this, false);
                                }
-                               // return callback.call(this, obj.id === '#' ? 
this._append_html_data(obj, 
this._data.core.original_container_html.clone(true)) : false);
+                               // return callback.call(this, obj.id === 
$.jstree.root ? this._append_html_data(obj, 
this._data.core.original_container_html.clone(true)) : false);
                        }
                        if($.isFunction(s)) {
                                return s.call(this, obj, $.proxy(function (d) {
                                        if(d === false) {
                                                callback.call(this, false);
                                        }
-                                       this[typeof d === 'string' ? 
'_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $(d) : 
d, function (status) {
+                                       this[typeof d === 'string' ? 
'_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? 
$($.parseHTML(d)).filter(function () { return this.nodeType !== 3; }) : d, 
function (status) {
                                                callback.call(this, status);
                                        });
                                        // return d === false ? 
callback.call(this, false) : callback.call(this, this[typeof d === 'string' ? 
'_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $(d) : 
d));
@@ -1309,12 +1355,12 @@
                                        return $.ajax(s)
                                                .done($.proxy(function (d,t,x) {
                                                                var type = 
x.getResponseHeader('Content-Type');
-                                                               
if(type.indexOf('json') !== -1 || typeof d === "object") {
+                                                               if((type && 
type.indexOf('json') !== -1) || typeof d === "object") {
                                                                        return 
this._append_json_data(obj, d, function (status) { callback.call(this, status); 
});
                                                                        
//return callback.call(this, this._append_json_data(obj, d));
                                                                }
-                                                               
if(type.indexOf('html') !== -1 || typeof d === "string") {
-                                                                       return 
this._append_html_data(obj, $(d), function (status) { callback.call(this, 
status); });
+                                                               if((type && 
type.indexOf('html') !== -1) || typeof d === "string") {
+                                                                       return 
this._append_html_data(obj, $($.parseHTML(d)).filter(function () { return 
this.nodeType !== 3; }), function (status) { callback.call(this, status); });
                                                                        // 
return callback.call(this, this._append_html_data(obj, $(d)));
                                                                }
                                                                
this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'core', 'id' : 
'core_04', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : 
obj.id, 'xhr' : x }) };
@@ -1328,7 +1374,7 @@
                                                        }, this));
                                }
                                t = ($.isArray(s) || $.isPlainObject(s)) ? 
JSON.parse(JSON.stringify(s)) : s;
-                               if(obj.id === '#') {
+                               if(obj.id === $.jstree.root) {
                                        return this._append_json_data(obj, t, 
function (status) {
                                                callback.call(this, status);
                                        });
@@ -1338,11 +1384,11 @@
                                        this.settings.core.error.call(this, 
this._data.core.last_error);
                                        return callback.call(this, false);
                                }
-                               //return callback.call(this, (obj.id === "#" ? 
this._append_json_data(obj, t) : false) );
+                               //return callback.call(this, (obj.id === 
$.jstree.root ? this._append_json_data(obj, t) : false) );
                        }
                        if(typeof s === 'string') {
-                               if(obj.id === '#') {
-                                       return this._append_html_data(obj, 
$(s), function (status) {
+                               if(obj.id === $.jstree.root) {
+                                       return this._append_html_data(obj, 
$($.parseHTML(s)).filter(function () { return this.nodeType !== 3; }), function 
(status) {
                                                callback.call(this, status);
                                        });
                                }
@@ -1351,7 +1397,7 @@
                                        this.settings.core.error.call(this, 
this._data.core.last_error);
                                        return callback.call(this, false);
                                }
-                               //return callback.call(this, (obj.id === "#" ? 
this._append_html_data(obj, $(s)) : false) );
+                               //return callback.call(this, (obj.id === 
$.jstree.root ? this._append_html_data(obj, $(s)) : false) );
                        }
                        return callback.call(this, false);
                },
@@ -1410,7 +1456,7 @@
                         * @param {String} parent the parent ID of the nodes
                         */
                        this.trigger('model', { "nodes" : dpc, 'parent' : par 
});
-                       if(par !== '#') {
+                       if(par !== $.jstree.root) {
                                this._node_changed(par);
                                this.redraw();
                        }
@@ -1433,6 +1479,7 @@
                 * @trigger model.jstree, changed.jstree
                 */
                _append_json_data : function (dom, data, cb, force_processing) {
+                       if(this.element === null) { return; }
                        dom = this.get_node(dom);
                        dom.children = [];
                        dom.children_d = [];
@@ -1496,6 +1543,9 @@
                                                        if(d && d.data && 
d.data.jstree && d.data.jstree.icon) {
                                                                tmp.icon = 
d.data.jstree.icon;
                                                        }
+                                                       if(tmp.icon === 
undefined || tmp.icon === null || tmp.icon === "") {
+                                                               tmp.icon = true;
+                                                       }
                                                        if(d && d.data) {
                                                                tmp.data = 
d.data;
                                                                
if(d.data.jstree) {
@@ -1585,6 +1635,9 @@
                                                        if(d && d.data && 
d.data.jstree && d.data.jstree.icon) {
                                                                tmp.icon = 
d.data.jstree.icon;
                                                        }
+                                                       if(tmp.icon === 
undefined || tmp.icon === null || tmp.icon === "") {
+                                                               tmp.icon = true;
+                                                       }
                                                        if(d && d.data) {
                                                                tmp.data = 
d.data;
                                                                
if(d.data.jstree) {
@@ -1720,6 +1773,7 @@
                                        }
                                },
                                rslt = function (rslt, worker) {
+                                       if(this.element === null) { return; }
                                        this._cnt = rslt.cnt;
                                        this._model.data = rslt.mod; // breaks 
the reference in load_node - careful
 
@@ -1747,7 +1801,7 @@
 
                                        this.trigger('model', { "nodes" : 
rslt.dpc, 'parent' : rslt.par });
 
-                                       if(rslt.par !== '#') {
+                                       if(rslt.par !== $.jstree.root) {
                                                this._node_changed(rslt.par);
                                                this.redraw();
                                        }
@@ -1886,9 +1940,12 @@
                        if(tmp.length) {
                                data.icon = 
tmp.hasClass('jstree-themeicon-hidden') ? false : tmp.attr('rel');
                        }
-                       if(data.state.icon) {
+                       if(data.state.icon !== undefined) {
                                data.icon = data.state.icon;
                        }
+                       if(data.icon === undefined || data.icon === null || 
data.icon === "") {
+                               data.icon = true;
+                       }
                        tmp = d.children("ul").children("li");
                        do {
                                tid = 'j' + this._id + '_' + (++this._cnt);
@@ -1961,6 +2018,9 @@
                        if(d && d.data && d.data.jstree && d.data.jstree.icon) {
                                tmp.icon = d.data.jstree.icon;
                        }
+                       if(tmp.icon === undefined || tmp.icon === null || 
tmp.icon === "") {
+                               tmp.icon = true;
+                       }
                        if(d && d.data) {
                                tmp.data = d.data;
                                if(d.data.jstree) {
@@ -2059,6 +2119,9 @@
                        if(d && d.data && d.data.jstree && d.data.jstree.icon) {
                                tmp.icon = d.data.jstree.icon;
                        }
+                       if(tmp.icon === undefined || tmp.icon === null || 
tmp.icon === "") {
+                               tmp.icon = true;
+                       }
                        if(d && d.data) {
                                tmp.data = d.data;
                                if(d.data.jstree) {
@@ -2131,7 +2194,7 @@
                 * @trigger redraw.jstree
                 */
                _redraw : function () {
-                       var nodes = this._model.force_full_redraw ? 
this._model.data['#'].children.concat([]) : this._model.changed.concat([]),
+                       var nodes = this._model.force_full_redraw ? 
this._model.data[$.jstree.root].children.concat([]) : 
this._model.changed.concat([]),
                                f = document.createElement('UL'), tmp, i, j, fe 
= this._data.core.focused;
                        for(i = 0, j = nodes.length; i < j; i++) {
                                tmp = this.redraw_node(nodes[i], true, 
this._model.force_full_redraw);
@@ -2180,6 +2243,35 @@
                        this._redraw();
                },
                /**
+                * redraws a single node's children. Used internally.
+                * @private
+                * @name draw_children(node)
+                * @param {mixed} node the node whose children will be redrawn
+                */
+               draw_children : function (node) {
+                       var obj = this.get_node(node),
+                               i = false,
+                               j = false,
+                               k = false,
+                               d = document;
+                       if(!obj) { return false; }
+                       if(obj.id === $.jstree.root) { return 
this.redraw(true); }
+                       node = this.get_node(node, true);
+                       if(!node || !node.length) { return false; } // TODO: 
quick toggle
+
+                       node.children('.jstree-children').remove();
+                       node = node[0];
+                       if(obj.children.length && obj.state.loaded) {
+                               k = d.createElement('UL');
+                               k.setAttribute('role', 'group');
+                               k.className = 'jstree-children';
+                               for(i = 0, j = obj.children.length; i < j; i++) 
{
+                                       
k.appendChild(this.redraw_node(obj.children[i], true, true));
+                               }
+                               node.appendChild(k);
+                       }
+               },
+               /**
                 * redraws a single node. Used internally.
                 * @private
                 * @name redraw_node(node, deep, is_callback, force_render)
@@ -2201,20 +2293,24 @@
                                m = this._model.data,
                                f = false,
                                s = false,
-                               tmp = null;
+                               tmp = null,
+                               t = 0,
+                               l = 0,
+                               has_children = false,
+                               last_sibling = false;
                        if(!obj) { return false; }
-                       if(obj.id === '#') {  return this.redraw(true); }
+                       if(obj.id === $.jstree.root) {  return 
this.redraw(true); }
                        deep = deep || obj.children.length === 0;
                        node = !document.querySelector ? 
document.getElementById(obj.id) : this.element[0].querySelector('#' + 
("0123456789".indexOf(obj.id[0]) !== -1 ? '\\3' + obj.id[0] + ' ' + 
obj.id.substr(1).replace($.jstree.idregex,'\\$&') : 
obj.id.replace($.jstree.idregex,'\\$&')) ); //, this.element);
                        if(!node) {
                                deep = true;
                                //node = d.createElement('LI');
                                if(!is_callback) {
-                                       par = obj.parent !== '#' ? $('#' + 
obj.parent.replace($.jstree.idregex,'\\$&'), this.element)[0] : null;
+                                       par = obj.parent !== $.jstree.root ? 
$('#' + obj.parent.replace($.jstree.idregex,'\\$&'), this.element)[0] : null;
                                        if(par !== null && (!par || 
!m[obj.parent].state.opened)) {
                                                return false;
                                        }
-                                       ind = $.inArray(obj.id, par === null ? 
m['#'].children : m[obj.parent].children);
+                                       ind = $.inArray(obj.id, par === null ? 
m[$.jstree.root].children : m[obj.parent].children);
                                }
                        }
                        else {
@@ -2263,14 +2359,39 @@
                                node.setAttribute('aria-disabled', true);
                        }
 
-                       if(obj.state.loaded && !obj.children.length) {
+                       for(i = 0, j = obj.children.length; i < j; i++) {
+                               if(!m[obj.children[i]].state.hidden) {
+                                       has_children = true;
+                                       break;
+                               }
+                       }
+                       if(obj.parent !== null && m[obj.parent] && 
!obj.state.hidden) {
+                               i = $.inArray(obj.id, m[obj.parent].children);
+                               last_sibling = obj.id;
+                               if(i !== -1) {
+                                       i++;
+                                       for(j = m[obj.parent].children.length; 
i < j; i++) {
+                                               
if(!m[m[obj.parent].children[i]].state.hidden) {
+                                                       last_sibling = 
m[obj.parent].children[i];
+                                               }
+                                               if(last_sibling !== obj.id) {
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+
+                       if(obj.state.hidden) {
+                               c += ' jstree-hidden';
+                       }
+                       if(obj.state.loaded && !has_children) {
                                c += ' jstree-leaf';
                        }
                        else {
                                c += obj.state.opened && obj.state.loaded ? ' 
jstree-open' : ' jstree-closed';
                                node.setAttribute('aria-expanded', 
(obj.state.opened && obj.state.loaded) );
                        }
-                       if(obj.parent !== null && 
m[obj.parent].children[m[obj.parent].children.length - 1] === obj.id) {
+                       if(last_sibling === obj.id) {
                                c += ' jstree-last';
                        }
                        node.id = obj.id;
@@ -2312,6 +2433,7 @@
                                node.childNodes[1].innerHTML += obj.text;
                        }
 
+
                        if(deep && obj.children.length && (obj.state.opened || 
force_render) && obj.state.loaded) {
                                k = d.createElement('UL');
                                k.setAttribute('role', 'group');
@@ -2350,7 +2472,11 @@
                                        par.appendChild(node);
                                }
                                if(f) {
+                                       t = this.element[0].scrollTop;
+                                       l = this.element[0].scrollLeft;
                                        node.childNodes[1].focus();
+                                       this.element[0].scrollTop = t;
+                                       this.element[0].scrollLeft = l;
                                }
                        }
                        if(obj.state.opened && !obj.state.loaded) {
@@ -2379,7 +2505,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        animation = animation === undefined ? 
this.settings.core.animation : animation;
@@ -2403,9 +2529,12 @@
                                d = this.get_node(obj, true);
                                t = this;
                                if(d.length) {
+                                       if(animation && 
d.children(".jstree-children").length) {
+                                               
d.children(".jstree-children").stop(true, true);
+                                       }
                                        if(obj.children.length && 
!this._firstChild(d.children('.jstree-children')[0])) {
-                                               this.redraw_node(obj, true, 
false, true);
-                                               d = this.get_node(obj, true);
+                                               this.draw_children(obj);
+                                               //d = this.get_node(obj, true);
                                        }
                                        if(!animation) {
                                                this.trigger('before_open', { 
"node" : obj });
@@ -2453,6 +2582,7 @@
                                         */
                                        this.trigger("after_open", { "node" : 
obj });
                                }
+                               return true;
                        }
                },
                /**
@@ -2463,12 +2593,12 @@
                 */
                _open_to : function (obj) {
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        var i, j, p = obj.parents;
                        for(i = 0, j = p.length; i < j; i+=1) {
-                               if(i !== '#') {
+                               if(i !== $.jstree.root) {
                                        this.open_node(p[i], false, 0);
                                }
                        }
@@ -2491,7 +2621,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        if(this.is_closed(obj)) {
@@ -2564,10 +2694,10 @@
                 * @trigger open_all.jstree
                 */
                open_all : function (obj, animation, original_obj) {
-                       if(!obj) { obj = '#'; }
+                       if(!obj) { obj = $.jstree.root; }
                        obj = this.get_node(obj);
                        if(!obj) { return false; }
-                       var dom = obj.id === '#' ? this.get_container_ul() : 
this.get_node(obj, true), i, j, _this;
+                       var dom = obj.id === $.jstree.root ? 
this.get_container_ul() : this.get_node(obj, true), i, j, _this;
                        if(!dom.length) {
                                for(i = 0, j = obj.children_d.length; i < j; 
i++) {
                                        
if(this.is_closed(this._model.data[obj.children_d[i]])) {
@@ -2604,19 +2734,18 @@
                 * @trigger close_all.jstree
                 */
                close_all : function (obj, animation) {
-                       if(!obj) { obj = '#'; }
+                       if(!obj) { obj = $.jstree.root; }
                        obj = this.get_node(obj);
                        if(!obj) { return false; }
-                       var dom = obj.id === '#' ? this.get_container_ul() : 
this.get_node(obj, true),
+                       var dom = obj.id === $.jstree.root ? 
this.get_container_ul() : this.get_node(obj, true),
                                _this = this, i, j;
-                       if(!dom.length) {
-                               for(i = 0, j = obj.children_d.length; i < j; 
i++) {
-                                       
this._model.data[obj.children_d[i]].state.opened = false;
-                               }
-                               return this.trigger('close_all', { "node" : obj 
});
+                       if(dom.length) {
+                               dom = this.is_open(obj) ? 
dom.find('.jstree-open').addBack() : dom.find('.jstree-open');
+                               $(dom.get().reverse()).each(function () { 
_this.close_node(this, animation || 0); });
                        }
-                       dom = this.is_open(obj) ? 
dom.find('.jstree-open').addBack() : dom.find('.jstree-open');
-                       $(dom.get().reverse()).each(function () { 
_this.close_node(this, animation || 0); });
+                       for(i = 0, j = obj.children_d.length; i < j; i++) {
+                               
this._model.data[obj.children_d[i]].state.opened = false;
+                       }
                        /**
                         * triggered when an `close_all` call completes
                         * @event
@@ -2651,7 +2780,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        obj.state.disabled = false;
@@ -2680,7 +2809,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        obj.state.disabled = true;
@@ -2694,6 +2823,130 @@
                        this.trigger('disable_node', { 'node' : obj });
                },
                /**
+                * hides a node - it is still in the structure but will not be 
visible
+                * @name hide_node(obj)
+                * @param {mixed} obj the node to hide
+                * @param {Boolean} redraw internal parameter controlling if 
redraw is called
+                * @trigger hide_node.jstree
+                */
+               hide_node : function (obj, skip_redraw) {
+                       var t1, t2;
+                       if($.isArray(obj)) {
+                               obj = obj.slice();
+                               for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+                                       this.hide_node(obj[t1], true);
+                               }
+                               this.redraw();
+                               return true;
+                       }
+                       obj = this.get_node(obj);
+                       if(!obj || obj.id === $.jstree.root) {
+                               return false;
+                       }
+                       if(!obj.state.hidden) {
+                               obj.state.hidden = true;
+                               this._node_changed(obj.parent);
+                               if(!skip_redraw) {
+                                       this.redraw();
+                               }
+                               /**
+                                * triggered when an node is hidden
+                                * @event
+                                * @name hide_node.jstree
+                                * @param {Object} node the hidden node
+                                */
+                               this.trigger('hide_node', { 'node' : obj });
+                       }
+               },
+               /**
+                * shows a node
+                * @name show_node(obj)
+                * @param {mixed} obj the node to show
+                * @param {Boolean} skip_redraw internal parameter controlling 
if redraw is called
+                * @trigger show_node.jstree
+                */
+               show_node : function (obj, skip_redraw) {
+                       var t1, t2;
+                       if($.isArray(obj)) {
+                               obj = obj.slice();
+                               for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+                                       this.show_node(obj[t1], true);
+                               }
+                               this.redraw();
+                               return true;
+                       }
+                       obj = this.get_node(obj);
+                       if(!obj || obj.id === $.jstree.root) {
+                               return false;
+                       }
+                       if(obj.state.hidden) {
+                               obj.state.hidden = false;
+                               this._node_changed(obj.parent);
+                               if(!skip_redraw) {
+                                       this.redraw();
+                               }
+                               /**
+                                * triggered when an node is shown
+                                * @event
+                                * @name show_node.jstree
+                                * @param {Object} node the shown node
+                                */
+                               this.trigger('show_node', { 'node' : obj });
+                       }
+               },
+               /**
+                * hides all nodes
+                * @name hide_all()
+                * @trigger hide_all.jstree
+                */
+               hide_all : function (skip_redraw) {
+                       var i, m = this._model.data, ids = [];
+                       for(i in m) {
+                               if(m.hasOwnProperty(i) && i !== $.jstree.root 
&& !m[i].state.hidden) {
+                                       m[i].state.hidden = true;
+                                       ids.push(i);
+                               }
+                       }
+                       this._model.force_full_redraw = true;
+                       if(!skip_redraw) {
+                               this.redraw();
+                       }
+                       /**
+                        * triggered when all nodes are hidden
+                        * @event
+                        * @name hide_all.jstree
+                        * @param {Array} nodes the IDs of all hidden nodes
+                        */
+                       this.trigger('hide_all', { 'nodes' : ids });
+                       return ids;
+               },
+               /**
+                * shows all nodes
+                * @name show_all()
+                * @trigger show_all.jstree
+                */
+               show_all : function (skip_redraw) {
+                       var i, m = this._model.data, ids = [];
+                       for(i in m) {
+                               if(m.hasOwnProperty(i) && i !== $.jstree.root 
&& m[i].state.hidden) {
+                                       m[i].state.hidden = false;
+                                       ids.push(i);
+                               }
+                       }
+                       this._model.force_full_redraw = true;
+                       if(!skip_redraw) {
+                               this.redraw();
+                       }
+                       /**
+                        * triggered when all nodes are shown
+                        * @event
+                        * @name show_all.jstree
+                        * @param {Array} nodes the IDs of all shown nodes
+                        */
+                       this.trigger('show_all', { 'nodes' : ids });
+                       return ids;
+               },
+               /**
                 * called when a node is selected by the user. Used internally.
                 * @private
                 * @name activate_node(obj, e)
@@ -2705,6 +2958,9 @@
                        if(this.is_disabled(obj)) {
                                return false;
                        }
+                       if(!e || typeof e !== 'object') {
+                               e = {};
+                       }
 
                        // ensure last_clicked is still in the DOM, make it 
fresh (maybe it was moved?) and make sure it is still selected, if not - make 
last_clicked the last selected node
                        this._data.core.last_clicked = 
this._data.core.last_clicked && this._data.core.last_clicked.id !== undefined ? 
this.get_node(this._data.core.last_clicked.id) : null;
@@ -2736,7 +2992,7 @@
                                                if(p[i] === l) {
                                                        c = !c;
                                                }
-                                               if(c || p[i] === o || p[i] === 
l) {
+                                               if(!this.is_disabled(p[i]) && 
(c || p[i] === o || p[i] === l)) {
                                                        this.select_node(p[i], 
true, false, e);
                                                }
                                                else {
@@ -2759,8 +3015,9 @@
                         * @event
                         * @name activate_node.jstree
                         * @param {Object} node
+                        * @param {Object} event the ooriginal event (if any) 
which triggered the call (may be an empty object)
                         */
-                       this.trigger('activate_node', { 'node' : 
this.get_node(obj) });
+                       this.trigger('activate_node', { 'node' : 
this.get_node(obj), 'event' : e });
                },
                /**
                 * applies the hover state on a node, called when a node is 
hovered by the user. Used internally.
@@ -2826,7 +3083,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        dom = this.get_node(obj, true);
@@ -2879,7 +3136,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        dom = this.get_node(obj, true);
@@ -2911,7 +3168,7 @@
                 */
                select_all : function (supress_event) {
                        var tmp = this._data.core.selected.concat([]), i, j;
-                       this._data.core.selected = 
this._model.data['#'].children_d.concat();
+                       this._data.core.selected = 
this._model.data[$.jstree.root].children_d.concat();
                        for(i = 0, j = this._data.core.selected.length; i < j; 
i++) {
                                
if(this._model.data[this._data.core.selected[i]]) {
                                        
this._model.data[this._data.core.selected[i]].state.selected = true;
@@ -2964,7 +3221,7 @@
                 */
                is_selected : function (obj) {
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        return obj.state.selected;
@@ -3047,7 +3304,7 @@
                        }, i;
                        for(i in this._model.data) {
                                if(this._model.data.hasOwnProperty(i)) {
-                                       if(i !== '#') {
+                                       if(i !== $.jstree.root) {
                                                
if(this._model.data[i].state.opened) {
                                                        state.core.open.push(i);
                                                }
@@ -3063,51 +3320,25 @@
                 * sets the state of the tree. Used internally.
                 * @name set_state(state [, callback])
                 * @private
-                * @param {Object} state the state to restore
+                * @param {Object} state the state to restore. Keep in mind 
this object is passed by reference and jstree will modify it.
                 * @param {Function} callback an optional function to execute 
once the state is restored.
                 * @trigger set_state.jstree
                 */
                set_state : function (state, callback) {
                        if(state) {
                                if(state.core) {
-                                       var res, n, t, _this;
+                                       var res, n, t, _this, i;
                                        if(state.core.open) {
-                                               if(!$.isArray(state.core.open)) 
{
+                                               if(!$.isArray(state.core.open) 
|| !state.core.open.length) {
                                                        delete state.core.open;
                                                        this.set_state(state, 
callback);
-                                                       return false;
                                                }
-                                               res = true;
-                                               n = false;
-                                               t = this;
-                                               
$.each(state.core.open.concat([]), function (i, v) {
-                                                       n = t.get_node(v);
-                                                       if(n) {
-                                                               
if(t.is_loaded(v)) {
-                                                                       
if(t.is_closed(v)) {
-                                                                               
t.open_node(v, false, 0);
-                                                                       }
-                                                                       
if(state && state.core && state.core.open) {
-                                                                               
$.vakata.array_remove_item(state.core.open, v);
-                                                                       }
-                                                               }
-                                                               else {
-                                                                       
if(!t.is_loading(v)) {
-                                                                               
t.open_node(v, $.proxy(function (o, s) {
-                                                                               
        if(!s && state && state.core && state.core.open) {
-                                                                               
                $.vakata.array_remove_item(state.core.open, o.id);
-                                                                               
        }
-                                                                               
        this.set_state(state, callback);
-                                                                               
}, t), 0);
-                                                                       }
-                                                                       // 
there will be some async activity - so wait for it
-                                                                       res = 
false;
-                                                               }
-                                                       }
-                                               });
-                                               if(res) {
-                                                       delete state.core.open;
-                                                       this.set_state(state, 
callback);
+                                               else {
+                                                       
this._load_nodes(state.core.open, function (nodes) {
+                                                               
this.open_node(nodes, false, 0);
+                                                               delete 
state.core.open;
+                                                               
this.set_state(state, callback);
+                                                       }, true);
                                                }
                                                return false;
                                        }
@@ -3122,33 +3353,21 @@
                                                this.set_state(state, callback);
                                                return false;
                                        }
-                                       /*!
-                                       if(state.core.themes) {
-                                               if(state.core.themes.name) {
-                                                       
this.set_theme(state.core.themes.name);
-                                               }
-                                               if(typeof 
state.core.themes.dots !== 'undefined') {
-                                                       this[ 
state.core.themes.dots ? "show_dots" : "hide_dots" ]();
-                                               }
-                                               if(typeof 
state.core.themes.icons !== 'undefined') {
-                                                       this[ 
state.core.themes.icons ? "show_icons" : "hide_icons" ]();
-                                               }
-                                               delete state.core.themes;
-                                               delete state.core.open;
-                                               this.set_state(state, callback);
-                                               return false;
-                                       }
-                                       */
                                        if(state.core.selected) {
                                                _this = this;
                                                this.deselect_all();
                                                $.each(state.core.selected, 
function (i, v) {
-                                                       _this.select_node(v);
+                                                       _this.select_node(v, 
false, true);
                                                });
                                                delete state.core.selected;
                                                this.set_state(state, callback);
                                                return false;
                                        }
+                                       for(i in state) {
+                                               if(state.hasOwnProperty(i) && i 
!== "core" && $.inArray(i, this.settings.plugins) === -1) {
+                                                       delete state[i];
+                                               }
+                                       }
                                        if($.isEmptyObject(state.core)) {
                                                delete state.core;
                                                this.set_state(state, callback);
@@ -3181,22 +3400,25 @@
                        this._data.core.state = forget_state === true ? {} : 
this.get_state();
                        if(forget_state && $.isFunction(forget_state)) { 
this._data.core.state = forget_state.call(this, this._data.core.state); }
                        this._cnt = 0;
-                       this._model.data = {
-                               '#' : {
-                                       id : '#',
-                                       parent : null,
-                                       parents : [],
-                                       children : [],
-                                       children_d : [],
-                                       state : { loaded : false }
-                               }
+                       this._model.data = {};
+                       this._model.data[$.jstree.root] = {
+                               id : $.jstree.root,
+                               parent : null,
+                               parents : [],
+                               children : [],
+                               children_d : [],
+                               state : { loaded : false }
                        };
+                       this._data.core.selected = [];
+                       this._data.core.last_clicked = null;
+                       this._data.core.focused = null;
+
                        var c = this.get_container_ul()[0].className;
                        if(!skip_loading) {
                                this.element.html("<"+"ul class='"+c+"' 
role='group'><"+"li class='jstree-initial-node jstree-loading jstree-leaf 
jstree-last' role='treeitem' id='j"+this._id+"_loading'><i class='jstree-icon 
jstree-ocl'></i><"+"a class='jstree-anchor' href='#'><i class='jstree-icon 
jstree-themeicon-hidden'></i>" + this.get_string("Loading ...") + 
"</a></li></ul>");
                                
this.element.attr('aria-activedescendant','j'+this._id+'_loading');
                        }
-                       this.load_node('#', function (o, s) {
+                       this.load_node($.jstree.root, function (o, s) {
                                if(s) {
                                        this.get_container_ul()[0].className = 
c;
                                        
if(this._firstChild(this.get_container_ul()[0])) {
@@ -3222,7 +3444,7 @@
                 */
                refresh_node : function (obj) {
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
                        var opened = [], to_load = [], s = 
this._data.core.selected.concat([]);
                        to_load.push(obj.id);
                        if(obj.state.opened === true) { opened.push(obj.id); }
@@ -3249,7 +3471,7 @@
                 */
                set_id : function (obj, id) {
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
                        var i, j, m = this._model.data;
                        id = id.toString();
                        // update parents (replace current ID with new one in 
children and children_d)
@@ -3269,10 +3491,14 @@
                        // update model and obj itself (obj.id, 
this._model.data[KEY])
                        i = this.get_node(obj.id, true);
                        if(i) {
-                               i.attr('id', id);
+                               i.attr('id', 
id).children('.jstree-anchor').attr('id', id + 
'_anchor').end().attr('aria-labelledby', id + '_anchor');
+                               if(this.element.attr('aria-activedescendant') 
=== obj.id) {
+                                       
this.element.attr('aria-activedescendant', id);
+                               }
                        }
                        delete m[obj.id];
                        obj.id = id;
+                       obj.li_attr.id = id;
                        m[id] = obj;
                        return true;
                },
@@ -3284,7 +3510,7 @@
                 */
                get_text : function (obj) {
                        obj = this.get_node(obj);
-                       return (!obj || obj.id === '#') ? false : obj.text;
+                       return (!obj || obj.id === $.jstree.root) ? false : 
obj.text;
                },
                /**
                 * set the text value of a node. Used internally, please use 
`rename_node(obj, val)`.
@@ -3305,7 +3531,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
                        obj.text = val;
                        if(this.get_node(obj, true).length) {
                                this.redraw_node(obj.id);
@@ -3333,7 +3559,7 @@
                 * @return {Object}
                 */
                get_json : function (obj, options, flat) {
-                       obj = this.get_node(obj || '#');
+                       obj = this.get_node(obj || $.jstree.root);
                        if(!obj) { return false; }
                        if(options && options.flat && !flat) { flat = []; }
                        var tmp = {
@@ -3368,7 +3594,7 @@
                                        delete tmp.a_attr.id;
                                }
                        }
-                       if(options && options.flat && obj.id !== '#') {
+                       if(options && options.flat && obj.id !== $.jstree.root) 
{
                                flat.push(tmp);
                        }
                        if(!options || !options.no_children) {
@@ -3381,7 +3607,7 @@
                                        }
                                }
                        }
-                       return options && options.flat ? flat : (obj.id === '#' 
? tmp.children : tmp);
+                       return options && options.flat ? flat : (obj.id === 
$.jstree.root ? tmp.children : tmp);
                },
                /**
                 * create a new node (do not confuse with load_node)
@@ -3395,7 +3621,7 @@
                 * @trigger model.jstree, create_node.jstree
                 */
                create_node : function (par, node, pos, callback, is_loaded) {
-                       if(par === null) { par = "#"; }
+                       if(par === null) { par = $.jstree.root; }
                        par = this.get_node(par);
                        if(!par) { return false; }
                        pos = pos === undefined ? "last" : pos;
@@ -3403,10 +3629,11 @@
                                return this.load_node(par, function () { 
this.create_node(par, node, pos, callback, true); });
                        }
                        if(!node) { node = { "text" : this.get_string('New 
node') }; }
+                       if(typeof node === "string") { node = { "text" : node 
}; }
                        if(node.text === undefined) { node.text = 
this.get_string('New node'); }
                        var tmp, dpc, i, j;
 
-                       if(par.id === '#') {
+                       if(par.id === $.jstree.root) {
                                if(pos === "before") { pos = "first"; }
                                if(pos === "after") { pos = "last"; }
                        }
@@ -3490,7 +3717,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
                        old = obj.text;
                        if(!this.check("rename_node", obj, 
this.get_parent(obj), val)) {
                                this.settings.core.error.call(this, 
this._data.core.last_error);
@@ -3516,7 +3743,7 @@
                 * @trigger delete_node.jstree, changed.jstree
                 */
                delete_node : function (obj) {
-                       var t1, t2, par, pos, tmp, i, j, k, l, c;
+                       var t1, t2, par, pos, tmp, i, j, k, l, c, top, lft;
                        if($.isArray(obj)) {
                                obj = obj.slice();
                                for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
@@ -3525,7 +3752,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
                        par = this.get_node(obj.parent);
                        pos = $.inArray(obj.id, par.children);
                        c = false;
@@ -3567,6 +3794,19 @@
                        for(k = 0, l = tmp.length; k < l; k++) {
                                delete this._model.data[tmp[k]];
                        }
+                       if($.inArray(this._data.core.focused, tmp) !== -1) {
+                               this._data.core.focused = null;
+                               top = this.element[0].scrollTop;
+                               lft = this.element[0].scrollLeft;
+                               if(par.id === $.jstree.root) {
+                                       
this.get_node(this._model.data[$.jstree.root].children[0], 
true).children('.jstree-anchor').focus();
+                               }
+                               else {
+                                       this.get_node(par, 
true).children('.jstree-anchor').focus();
+                               }
+                               this.element[0].scrollTop  = top;
+                               this.element[0].scrollLeft = lft;
+                       }
                        this.redraw_node(par, true);
                        return true;
                },
@@ -3620,49 +3860,59 @@
                 * @param  {mixed} par the new parent
                 * @param  {mixed} pos the position to insert at (besides 
integer values, "first" and "last" are supported, as well as "before" and 
"after"), defaults to integer `0`
                 * @param  {function} callback a function to call once the move 
is completed, receives 3 arguments - the node, the new parent and the position
-                * @param  {Boolean} internal parameter indicating if the 
parent node has been loaded
-                * @param  {Boolean} internal parameter indicating if the tree 
should be redrawn
+                * @param  {Boolean} is_loaded internal parameter indicating if 
the parent node has been loaded
+                * @param  {Boolean} skip_redraw internal parameter indicating 
if the tree should be redrawn
+                * @param  {Boolean} instance internal parameter indicating if 
the node comes from another instance
                 * @trigger move_node.jstree
                 */
-               move_node : function (obj, par, pos, callback, is_loaded, 
skip_redraw) {
+               move_node : function (obj, par, pos, callback, is_loaded, 
skip_redraw, origin) {
                        var t1, t2, old_par, old_pos, new_par, old_ins, 
is_multi, dpc, tmp, i, j, k, l, p;
 
                        par = this.get_node(par);
                        pos = pos === undefined ? 0 : pos;
                        if(!par) { return false; }
                        if(!pos.toString().match(/^(before|after)$/) && 
!is_loaded && !this.is_loaded(par)) {
-                               return this.load_node(par, function () { 
this.move_node(obj, par, pos, callback, true); });
+                               return this.load_node(par, function () { 
this.move_node(obj, par, pos, callback, true, false, origin); });
                        }
 
                        if($.isArray(obj)) {
-                               obj = obj.slice();
-                               for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
-                                       if(this.move_node(obj[t1], par, pos, 
callback, is_loaded, true)) {
-                                               par = obj[t1];
-                                               pos = "after";
+                               if(obj.length === 1) {
+                                       obj = obj[0];
+                               }
+                               else {
+                                       //obj = obj.slice();
+                                       for(t1 = 0, t2 = obj.length; t1 < t2; 
t1++) {
+                                               if((tmp = 
this.move_node(obj[t1], par, pos, callback, is_loaded, false, origin))) {
+                                                       par = tmp;
+                                                       pos = "after";
+                                               }
                                        }
+                                       this.redraw();
+                                       return true;
                                }
-                               this.redraw();
-                               return true;
                        }
                        obj = obj && obj.id ? obj : this.get_node(obj);
 
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
 
-                       old_par = (obj.parent || '#').toString();
-                       new_par = (!pos.toString().match(/^(before|after)$/) || 
par.id === '#') ? par : this.get_node(par.parent);
-                       old_ins = obj.instance ? obj.instance : 
(this._model.data[obj.id] ? this : $.jstree.reference(obj.id));
+                       old_par = (obj.parent || $.jstree.root).toString();
+                       new_par = (!pos.toString().match(/^(before|after)$/) || 
par.id === $.jstree.root) ? par : this.get_node(par.parent);
+                       old_ins = origin ? origin : (this._model.data[obj.id] ? 
this : $.jstree.reference(obj.id));
                        is_multi = !old_ins || !old_ins._id || (this._id !== 
old_ins._id);
                        old_pos = old_ins && old_ins._id && old_par && 
old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? 
$.inArray(obj.id, old_ins._model.data[old_par].children) : -1;
+                       if(old_ins && old_ins._id) {
+                               obj = old_ins._model.data[obj.id];
+                       }
+
                        if(is_multi) {
-                               if(this.copy_node(obj, par, pos, callback, 
is_loaded)) {
+                               if((tmp = this.copy_node(obj, par, pos, 
callback, is_loaded, false, origin))) {
                                        if(old_ins) { old_ins.delete_node(obj); 
}
-                                       return true;
+                                       return tmp;
                                }
                                return false;
                        }
                        //var m = this._model.data;
-                       if(par.id === '#') {
+                       if(par.id === $.jstree.root) {
                                if(pos === "before") { pos = "first"; }
                                if(pos === "after") { pos = "last"; }
                        }
@@ -3685,7 +3935,7 @@
                                        break;
                        }
                        if(pos > new_par.children.length) { pos = 
new_par.children.length; }
-                       if(!this.check("move_node", obj, new_par, pos, { 'core' 
: true, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 
'is_foreign' : (!old_ins || !old_ins._id) })) {
+                       if(!this.check("move_node", obj, new_par, pos, { 'core' 
: true, 'origin' : origin, 'is_multi' : (old_ins && old_ins._id && old_ins._id 
!== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) {
                                this.settings.core.error.call(this, 
this._data.core.last_error);
                                return false;
                        }
@@ -3703,7 +3953,7 @@
                                tmp[pos] = obj.id;
                                new_par.children = tmp;
                                this._node_changed(new_par.id);
-                               this.redraw(new_par.id === '#');
+                               this.redraw(new_par.id === $.jstree.root);
                        }
                        else {
                                // clean old parent and up
@@ -3748,7 +3998,7 @@
                                        
Array.prototype.push.apply(this._model.data[obj.children_d[i]].parents, tmp);
                                }
 
-                               if(old_par === '#' || new_par.id === '#') {
+                               if(old_par === $.jstree.root || new_par.id === 
$.jstree.root) {
                                        this._model.force_full_redraw = true;
                                }
                                if(!this._model.force_full_redraw) {
@@ -3774,7 +4024,7 @@
                         * @param {jsTree} new_instance the instance of the new 
parent
                         */
                        this.trigger('move_node', { "node" : obj, "parent" : 
new_par.id, "position" : pos, "old_parent" : old_par, "old_position" : old_pos, 
'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' 
: (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this 
});
-                       return true;
+                       return obj.id;
                },
                /**
                 * copy a node to a new parent
@@ -3783,40 +4033,50 @@
                 * @param  {mixed} par the new parent
                 * @param  {mixed} pos the position to insert at (besides 
integer values, "first" and "last" are supported, as well as "before" and 
"after"), defaults to integer `0`
                 * @param  {function} callback a function to call once the move 
is completed, receives 3 arguments - the node, the new parent and the position
-                * @param  {Boolean} internal parameter indicating if the 
parent node has been loaded
-                * @param  {Boolean} internal parameter indicating if the tree 
should be redrawn
+                * @param  {Boolean} is_loaded internal parameter indicating if 
the parent node has been loaded
+                * @param  {Boolean} skip_redraw internal parameter indicating 
if the tree should be redrawn
+                * @param  {Boolean} instance internal parameter indicating if 
the node comes from another instance
                 * @trigger model.jstree copy_node.jstree
                 */
-               copy_node : function (obj, par, pos, callback, is_loaded, 
skip_redraw) {
+               copy_node : function (obj, par, pos, callback, is_loaded, 
skip_redraw, origin) {
                        var t1, t2, dpc, tmp, i, j, node, old_par, new_par, 
old_ins, is_multi;
 
                        par = this.get_node(par);
                        pos = pos === undefined ? 0 : pos;
                        if(!par) { return false; }
                        if(!pos.toString().match(/^(before|after)$/) && 
!is_loaded && !this.is_loaded(par)) {
-                               return this.load_node(par, function () { 
this.copy_node(obj, par, pos, callback, true); });
+                               return this.load_node(par, function () { 
this.copy_node(obj, par, pos, callback, true, false, origin); });
                        }
 
                        if($.isArray(obj)) {
-                               obj = obj.slice();
-                               for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
-                                       tmp = this.copy_node(obj[t1], par, pos, 
callback, is_loaded, true);
-                                       if(tmp) {
-                                               par = tmp;
-                                               pos = "after";
+                               if(obj.length === 1) {
+                                       obj = obj[0];
+                               }
+                               else {
+                                       //obj = obj.slice();
+                                       for(t1 = 0, t2 = obj.length; t1 < t2; 
t1++) {
+                                               if((tmp = 
this.copy_node(obj[t1], par, pos, callback, is_loaded, true, origin))) {
+                                                       par = tmp;
+                                                       pos = "after";
+                                               }
                                        }
+                                       this.redraw();
+                                       return true;
                                }
-                               this.redraw();
-                               return true;
                        }
                        obj = obj && obj.id ? obj : this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
 
-                       old_par = (obj.parent || '#').toString();
-                       new_par = (!pos.toString().match(/^(before|after)$/) || 
par.id === '#') ? par : this.get_node(par.parent);
-                       old_ins = obj.instance ? obj.instance : 
(this._model.data[obj.id] ? this : $.jstree.reference(obj.id));
+                       old_par = (obj.parent || $.jstree.root).toString();
+                       new_par = (!pos.toString().match(/^(before|after)$/) || 
par.id === $.jstree.root) ? par : this.get_node(par.parent);
+                       old_ins = origin ? origin : (this._model.data[obj.id] ? 
this : $.jstree.reference(obj.id));
                        is_multi = !old_ins || !old_ins._id || (this._id !== 
old_ins._id);
-                       if(par.id === '#') {
+
+                       if(old_ins && old_ins._id) {
+                               obj = old_ins._model.data[obj.id];
+                       }
+
+                       if(par.id === $.jstree.root) {
                                if(pos === "before") { pos = "first"; }
                                if(pos === "after") { pos = "last"; }
                        }
@@ -3839,7 +4099,7 @@
                                        break;
                        }
                        if(pos > new_par.children.length) { pos = 
new_par.children.length; }
-                       if(!this.check("copy_node", obj, new_par, pos, { 'core' 
: true, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 
'is_foreign' : (!old_ins || !old_ins._id) })) {
+                       if(!this.check("copy_node", obj, new_par, pos, { 'core' 
: true, 'origin' : origin, 'is_multi' : (old_ins && old_ins._id && old_ins._id 
!== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) {
                                this.settings.core.error.call(this, 
this._data.core.last_error);
                                return false;
                        }
@@ -3868,14 +4128,14 @@
                        new_par.children_d.push(tmp.id);
                        new_par.children_d = 
new_par.children_d.concat(tmp.children_d);
 
-                       if(new_par.id === '#') {
+                       if(new_par.id === $.jstree.root) {
                                this._model.force_full_redraw = true;
                        }
                        if(!this._model.force_full_redraw) {
                                this._node_changed(new_par.id);
                        }
                        if(!skip_redraw) {
-                               this.redraw(new_par.id === '#');
+                               this.redraw(new_par.id === $.jstree.root);
                        }
                        if(callback) { callback.call(this, tmp, new_par, pos); }
                        /**
@@ -3908,7 +4168,7 @@
                        var tmp = [], o, t1, t2;
                        for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
                                o = this.get_node(obj[t1]);
-                               if(o && o.id && o.id !== '#') { tmp.push(o); }
+                               if(o && o.id && o.id !== $.jstree.root) { 
tmp.push(o); }
                        }
                        if(!tmp.length) { return false; }
                        ccp_node = tmp;
@@ -3926,7 +4186,7 @@
                 * copy a node (a later call to `paste(obj)` would copy the 
node)
                 * @name copy(obj)
                 * @param  {mixed} obj multiple objects can be passed using an 
array
-                * @trigger copy.jstre
+                * @trigger copy.jstree
                 */
                copy : function (obj) {
                        if(!obj) { obj = this._data.core.selected.concat(); }
@@ -3935,7 +4195,7 @@
                        var tmp = [], o, t1, t2;
                        for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
                                o = this.get_node(obj[t1]);
-                               if(o && o.id && o.id !== '#') { tmp.push(o); }
+                               if(o && o.id && o.id !== $.jstree.root) { 
tmp.push(o); }
                        }
                        if(!tmp.length) { return false; }
                        ccp_node = tmp;
@@ -3975,7 +4235,7 @@
                paste : function (obj, pos) {
                        obj = this.get_node(obj);
                        if(!obj || !ccp_mode || 
!ccp_mode.match(/^(copy_node|move_node)$/) || !ccp_node) { return false; }
-                       if(this[ccp_mode](ccp_node, obj, pos)) {
+                       if(this[ccp_mode](ccp_node, obj, pos, false, false, 
false, ccp_inst)) {
                                /**
                                 * triggered when paste is invoked
                                 * @event
@@ -4008,11 +4268,13 @@
                },
                /**
                 * put a node in edit mode (input field to rename the node)
-                * @name edit(obj [, default_text])
+                * @name edit(obj [, default_text, callback])
                 * @param  {mixed} obj
-                * @param  {String} default_text the text to populate the input 
with (if omitted the node text value is used)
+                * @param  {String} default_text the text to populate the input 
with (if omitted or set to a non-string value the node's text value is used)
+                * @param  {Function} callback a function to be called once the 
text box is blurred, it is called in the instance's scope and receives the 
node, a status parameter (true if the rename is successful, false otherwise) 
and a boolean indicating if the user cancelled the edit. You can access the 
node's title using .text
                 */
-               edit : function (obj, default_text) {
+               edit : function (obj, default_text, callback) {
+                       var rtl, w, a, s, t, h1, h2, fn, tmp, cancel = false;
                        obj = this.get_node(obj);
                        if(!obj) { return false; }
                        if(this.settings.core.check_callback === false) {
@@ -4020,23 +4282,26 @@
                                this.settings.core.error.call(this, 
this._data.core.last_error);
                                return false;
                        }
+                       tmp = obj;
                        default_text = typeof default_text === 'string' ? 
default_text : obj.text;
                        this.set_text(obj, "");
                        obj = this._open_to(obj);
+                       tmp.text = default_text;
 
-                       var rtl = this._data.core.rtl,
-                               w  = this.element.width(),
-                               a  = obj.children('.jstree-anchor'),
-                               s  = $('<span>'),
-                               /*!
-                               oi = obj.children("i:visible"),
-                               ai = a.children("i:visible"),
-                               w1 = oi.width() * oi.length,
-                               w2 = ai.width() * ai.length,
-                               */
-                               t  = default_text,
-                               h1 = $("<"+"div />", { css : { "position" : 
"absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" 
: "hidden" } }).appendTo("body"),
-                               h2 = $("<"+"input />", {
+                       rtl = this._data.core.rtl;
+                       w  = this.element.width();
+                       this._data.core.focused = tmp.id;
+                       a  = obj.children('.jstree-anchor').focus();
+                       s  = $('<span>');
+                       /*!
+                       oi = obj.children("i:visible"),
+                       ai = a.children("i:visible"),
+                       w1 = oi.width() * oi.length,
+                       w2 = ai.width() * ai.length,
+                       */
+                       t  = default_text;
+                       h1 = $("<"+"div />", { css : { "position" : "absolute", 
"top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } 
}).appendTo("body");
+                       h2 = $("<"+"input />", {
                                                "value" : t,
                                                "class" : "jstree-rename-input",
                                                // "size" : t.length,
@@ -4049,40 +4314,58 @@
                                                        "lineHeight" : 
(this._data.core.li_height) + "px",
                                                        "width" : "150px" // 
will be set a bit further down
                                                },
-                                               "blur" : $.proxy(function () {
+                                               "blur" : $.proxy(function (e) {
+                                                       
e.stopImmediatePropagation();
+                                                       e.preventDefault();
                                                        var i = 
s.children(".jstree-rename-input"),
-                                                               v = i.val();
+                                                               v = i.val(),
+                                                               f = 
this.settings.core.force_text,
+                                                               nv;
                                                        if(v === "") { v = t; }
                                                        h1.remove();
                                                        s.replaceWith(a);
                                                        s.remove();
+                                                       t = f ? t : 
$('<div></div>').append($.parseHTML(t)).html();
                                                        this.set_text(obj, t);
-                                                       
if(this.rename_node(obj, $('<div></div>').text(v)[this.settings.core.force_text 
? 'text' : 'html']()) === false) {
+                                                       nv = 
!!this.rename_node(obj, f ? $('<div></div>').text(v).text() : 
$('<div></div>').append($.parseHTML(v)).html());
+                                                       if(!nv) {
                                                                
this.set_text(obj, t); // move this up? and fix #483
                                                        }
+                                                       this._data.core.focused 
= tmp.id;
+                                                       
setTimeout($.proxy(function () {
+                                                               var node = 
this.get_node(tmp.id, true);
+                                                               if(node.length) 
{
+                                                                       
this._data.core.focused = tmp.id;
+                                                                       
node.children('.jstree-anchor').focus();
+                                                               }
+                                                       }, this), 0);
+                                                       if(callback) {
+                                                               
callback.call(this, tmp, nv, cancel);
+                                                       }
                                                }, this),
-                                               "keydown" : function (event) {
-                                                       var key = event.which;
+                                               "keydown" : function (e) {
+                                                       var key = e.which;
                                                        if(key === 27) {
+                                                               cancel = true;
                                                                this.value = t;
                                                        }
                                                        if(key === 27 || key 
=== 13 || key === 37 || key === 38 || key === 39 || key === 40 || key === 32) {
-                                                               
event.stopImmediatePropagation();
+                                                               
e.stopImmediatePropagation();
                                                        }
                                                        if(key === 27 || key 
=== 13) {
-                                                               
event.preventDefault();
+                                                               
e.preventDefault();
                                                                this.blur();
                                                        }
                                                },
                                                "click" : function (e) { 
e.stopImmediatePropagation(); },
                                                "mousedown" : function (e) { 
e.stopImmediatePropagation(); },
-                                               "keyup" : function (event) {
+                                               "keyup" : function (e) {
                                                        
h2.width(Math.min(h1.text("pW" + this.value).width(),w));
                                                },
-                                               "keypress" : function(event) {
-                                                       if(event.which === 13) 
{ return false; }
+                                               "keypress" : function(e) {
+                                                       if(e.which === 13) { 
return false; }
                                                }
-                                       }),
+                                       });
                                fn = {
                                                fontFamily              : 
a.css('fontFamily')           || '',
                                                fontSize                : 
a.css('fontSize')                     || '',
@@ -4219,14 +4502,14 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
                        old = obj.icon;
-                       obj.icon = icon;
+                       obj.icon = icon === true || icon === null || icon === 
undefined || icon === '' ? true : icon;
                        dom = this.get_node(obj, 
true).children(".jstree-anchor").children(".jstree-themeicon");
                        if(icon === false) {
                                this.hide_icon(obj);
                        }
-                       else if(icon === true) {
+                       else if(icon === true || icon === null || icon === 
undefined || icon === '') {
                                dom.removeClass('jstree-themeicon-custom ' + 
old).css("background","").removeAttr("rel");
                                if(old === false) { this.show_icon(obj); }
                        }
@@ -4250,7 +4533,7 @@
                 */
                get_icon : function (obj) {
                        obj = this.get_node(obj);
-                       return (!obj || obj.id === '#') ? false : obj.icon;
+                       return (!obj || obj.id === $.jstree.root) ? false : 
obj.icon;
                },
                /**
                 * hide the icon on an individual node
@@ -4267,7 +4550,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj === '#') { return false; }
+                       if(!obj || obj === $.jstree.root) { return false; }
                        obj.icon = false;
                        this.get_node(obj, 
true).children(".jstree-anchor").children(".jstree-themeicon").addClass('jstree-themeicon-hidden');
                        return true;
@@ -4287,7 +4570,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj === '#') { return false; }
+                       if(!obj || obj === $.jstree.root) { return false; }
                        dom = this.get_node(obj, true);
                        obj.icon = dom.length ? 
dom.children(".jstree-anchor").children(".jstree-themeicon").attr('rel') : true;
                        if(!obj.icon) { obj.icon = true; }
@@ -4314,14 +4597,12 @@
                return attr;
        };
        $.vakata.array_unique = function(array) {
-               var a = [], i, j, l;
+               var a = [], i, j, l, o = {};
                for(i = 0, l = array.length; i < l; i++) {
-                       for(j = 0; j <= i; j++) {
-                               if(array[i] === array[j]) {
-                                       break;
-                               }
+                       if(o[array[i]] === undefined) {
+                               a.push(array[i]);
+                               o[array[i]] = true;
                        }
-                       if(j === i) { a.push(array[i]); }
                }
                return a;
        };
@@ -4338,10 +4619,64 @@
                return tmp !== -1 ? $.vakata.array_remove(array, tmp) : array;
        };
 
+
 /**
+ * ### Changed plugin
+ *
+ * This plugin adds more information to the `changed.jstree` event. The new 
data is contained in the `changed` event data property, and contains a lists of 
`selected` and `deselected` nodes.
+ */
+
+       $.jstree.plugins.changed = function (options, parent) {
+               var last = [];
+               this.trigger = function (ev, data) {
+                       var i, j;
+                       if(!data) {
+                               data = {};
+                       }
+                       if(ev.replace('.jstree','') === 'changed') {
+                               data.changed = { selected : [], deselected : [] 
};
+                               var tmp = {};
+                               for(i = 0, j = last.length; i < j; i++) {
+                                       tmp[last[i]] = 1;
+                               }
+                               for(i = 0, j = data.selected.length; i < j; 
i++) {
+                                       if(!tmp[data.selected[i]]) {
+                                               
data.changed.selected.push(data.selected[i]);
+                                       }
+                                       else {
+                                               tmp[data.selected[i]] = 2;
+                                       }
+                               }
+                               for(i = 0, j = last.length; i < j; i++) {
+                                       if(tmp[last[i]] === 1) {
+                                               
data.changed.deselected.push(last[i]);
+                                       }
+                               }
+                               last = data.selected.slice();
+                       }
+                       /**
+                        * triggered when selection changes (the "changed" 
plugin enhances the original event with more data)
+                        * @event
+                        * @name changed.jstree
+                        * @param {Object} node
+                        * @param {Object} action the action that caused the 
selection to change
+                        * @param {Array} selected the current selection
+                        * @param {Object} changed an object containing two 
properties `selected` and `deselected` - both arrays of node IDs, which were 
selected or deselected since the last changed event
+                        * @param {Object} event the event (if any) that 
triggered this changed event
+                        * @plugin changed
+                        */
+                       parent.trigger.call(this, ev, data);
+               };
+               this.refresh = function (skip_loading, forget_state) {
+                       last = [];
+                       return parent.refresh.apply(this, arguments);
+               };
+       };
+
+/**
  * ### Checkbox plugin
  *
- * This plugin renders checkbox icons in front of each node, making multiple 
selection much easier. 
+ * This plugin renders checkbox icons in front of each node, making multiple 
selection much easier.
  * It also supports tri-state behavior, meaning that if a node has a few of 
its children checked it will be rendered as undetermined, and state will be 
propagated up.
  */
 
@@ -4379,15 +4714,15 @@
                 */
                keep_selected_style     : true,
                /**
-                * This setting controls how cascading and undetermined nodes 
are applied. 
-                * If 'up' is in the string - cascading up is enabled, if 
'down' is in the string - cascading down is enabled, if 'undetermined' is in 
the string - undetermined nodes will be used. 
+                * This setting controls how cascading and undetermined nodes 
are applied.
+                * If 'up' is in the string - cascading up is enabled, if 
'down' is in the string - cascading down is enabled, if 'undetermined' is in 
the string - undetermined nodes will be used.
                 * If `three_state` is set to `true` this setting is 
automatically set to 'up+down+undetermined'. Defaults to ''.
                 * @name $.jstree.defaults.checkbox.cascade
                 * @plugin checkbox
                 */
                cascade                         : '',
                /**
-                * This setting controls if checkbox are bound to the general 
tree selection or to an internal array maintained by the checkbox plugin. 
Defaults to `true`, only set to `false` if you know exactly what you are doing. 
+                * This setting controls if checkbox are bound to the general 
tree selection or to an internal array maintained by the checkbox plugin. 
Defaults to `true`, only set to `false` if you know exactly what you are doing.
                 * @name $.jstree.defaults.checkbox.tie_selection
                 * @plugin checkbox
                 */
@@ -4430,7 +4765,7 @@
                                                        dpc = data.nodes,
                                                        i, j;
                                                for(i = 0, j = dpc.length; i < 
j; i++) {
-                                                       m[dpc[i]].state.checked 
= (m[dpc[i]].original && m[dpc[i]].original.state && 
m[dpc[i]].original.state.checked);
+                                                       m[dpc[i]].state.checked 
= m[dpc[i]].state.checked || (m[dpc[i]].original && m[dpc[i]].original.state && 
m[dpc[i]].original.state.checked);
                                                        
if(m[dpc[i]].state.checked) {
                                                                
this._data.checkbox.selected.push(dpc[i]);
                                                        }
@@ -4476,7 +4811,7 @@
                                                                chd = 
$.vakata.array_unique(chd);
                                                                for(k = 0, l = 
chd.length; k < l; k++) {
                                                                        p = 
m[chd[k]];
-                                                                       while(p 
&& p.id !== '#') {
+                                                                       while(p 
&& p.id !== $.jstree.root) {
                                                                                
c = 0;
                                                                                
for(i = 0, j = p.children.length; i < j; i++) {
                                                                                
        c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
@@ -4520,7 +4855,7 @@
 
                                                        // apply up
                                                        if(s.indexOf('up') !== 
-1) {
-                                                               while(par && 
par.id !== '#') {
+                                                               while(par && 
par.id !== $.jstree.root) {
                                                                        c = 0;
                                                                        for(i = 
0, j = par.children.length; i < j; i++) {
                                                                                
c += m[par.children[i]].state[ t ? 'selected' : 'checked' ];
@@ -4546,7 +4881,7 @@
                                                        }
                                                }, this))
                                        
.on(this.settings.checkbox.tie_selection ? 'deselect_all.jstree' : 
'uncheck_all.jstree', $.proxy(function (e, data) {
-                                                       var obj = 
this.get_node('#'),
+                                                       var obj = 
this.get_node($.jstree.root),
                                                                m = 
this._model.data,
                                                                i, j, tmp;
                                                        for(i = 0, j = 
obj.children_d.length; i < j; i++) {
@@ -4614,12 +4949,12 @@
                                                        var p = 
this.get_node(data.parent),
                                                                m = 
this._model.data,
                                                                i, j, c, tmp, t 
= this.settings.checkbox.tie_selection;
-                                                       while(p && p.id !== 
'#') {
+                                                       while(p && p.id !== 
$.jstree.root && !p.state[ t ? 'selected' : 'checked' ]) {
                                                                c = 0;
                                                                for(i = 0, j = 
p.children.length; i < j; i++) {
                                                                        c += 
m[p.children[i]].state[ t ? 'selected' : 'checked' ];
                                                                }
-                                                               if(c === j) {
+                                                               if(j > 0 && c 
=== j) {
                                                                        
p.state[ t ? 'selected' : 'checked' ] = true;
                                                                        
this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
                                                                        tmp = 
this.get_node(p, true);
@@ -4642,12 +4977,12 @@
                                                                p, c, i, j, 
tmp, t = this.settings.checkbox.tie_selection;
                                                        if(!is_multi) {
                                                                p = 
this.get_node(old_par);
-                                                               while(p && p.id 
!== '#') {
+                                                               while(p && p.id 
!== $.jstree.root && !p.state[ t ? 'selected' : 'checked' ]) {
                                                                        c = 0;
                                                                        for(i = 
0, j = p.children.length; i < j; i++) {
                                                                                
c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
                                                                        }
-                                                                       if(c 
=== j) {
+                                                                       if(j > 
0 && c === j) {
                                                                                
p.state[ t ? 'selected' : 'checked' ] = true;
                                                                                
this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
                                                                                
tmp = this.get_node(p, true);
@@ -4662,7 +4997,7 @@
                                                                }
                                                        }
                                                        p = new_par;
-                                                       while(p && p.id !== 
'#') {
+                                                       while(p && p.id !== 
$.jstree.root) {
                                                                c = 0;
                                                                for(i = 0, j = 
p.children.length; i < j; i++) {
                                                                        c += 
m[p.children[i]].state[ t ? 'selected' : 'checked' ];
@@ -4702,10 +5037,16 @@
                 * @plugin checkbox
                 */
                this._undetermined = function () {
-                       var i, j, m = this._model.data, t = 
this.settings.checkbox.tie_selection, s = this._data[ t ? 'core' : 'checkbox' 
].selected, p = [], tt = this;
+                       if(this.element === null) { return; }
+                       var i, j, k, l, o = {}, m = this._model.data, t = 
this.settings.checkbox.tie_selection, s = this._data[ t ? 'core' : 'checkbox' 
].selected, p = [], tt = this;
                        for(i = 0, j = s.length; i < j; i++) {
                                if(m[s[i]] && m[s[i]].parents) {
-                                       p = p.concat(m[s[i]].parents);
+                                       for(k = 0, l = m[s[i]].parents.length; 
k < l; k++) {
+                                               if(o[m[s[i]].parents[k]] === 
undefined && m[s[i]].parents[k] !== $.jstree.root) {
+                                                       o[m[s[i]].parents[k]] = 
true;
+                                                       
p.push(m[s[i]].parents[k]);
+                                               }
+                                       }
                                }
                        }
                        // attempt for server side undetermined state
@@ -4714,22 +5055,36 @@
                                        var tmp = tt.get_node(this), tmp2;
                                        if(!tmp.state.loaded) {
                                                if(tmp.original && 
tmp.original.state && tmp.original.state.undetermined && 
tmp.original.state.undetermined === true) {
-                                                       p.push(tmp.id);
-                                                       p = 
p.concat(tmp.parents);
+                                                       if(o[tmp.id] === 
undefined && tmp.id !== $.jstree.root) {
+                                                               o[tmp.id] = 
true;
+                                                               p.push(tmp.id);
+                                                       }
+                                                       for(k = 0, l = 
tmp.parents.length; k < l; k++) {
+                                                               
if(o[tmp.parents[k]] === undefined && tmp.parents[k] !== $.jstree.root) {
+                                                                       
o[tmp.parents[k]] = true;
+                                                                       
p.push(tmp.parents[k]);
+                                                               }
+                                                       }
                                                }
                                        }
                                        else {
                                                for(i = 0, j = 
tmp.children_d.length; i < j; i++) {
                                                        tmp2 = 
m[tmp.children_d[i]];
                                                        if(!tmp2.state.loaded 
&& tmp2.original && tmp2.original.state && tmp2.original.state.undetermined && 
tmp2.original.state.undetermined === true) {
-                                                               p.push(tmp2.id);
-                                                               p = 
p.concat(tmp2.parents);
+                                                               if(o[tmp2.id] 
=== undefined && tmp2.id !== $.jstree.root) {
+                                                                       
o[tmp2.id] = true;
+                                                                       
p.push(tmp2.id);
+                                                               }
+                                                               for(k = 0, l = 
tmp2.parents.length; k < l; k++) {
+                                                                       
if(o[tmp2.parents[k]] === undefined && tmp2.parents[k] !== $.jstree.root) {
+                                                                               
o[tmp2.parents[k]] = true;
+                                                                               
p.push(tmp2.parents[k]);
+                                                                       }
+                                                               }
                                                        }
                                                }
                                        }
                                });
-                       p = $.vakata.array_unique(p);
-                       p = $.vakata.array_remove_item(p,'#');
 
                        
this.element.find('.jstree-undetermined').removeClass('jstree-undetermined');
                        for(i = 0, j = p.length; i < j; i++) {
@@ -4744,7 +5099,7 @@
                this.redraw_node = function(obj, deep, is_callback, 
force_render) {
                        obj = parent.redraw_node.apply(this, arguments);
                        if(obj) {
-                               var i, j, tmp = null;
+                               var i, j, tmp = null, icon = null;
                                for(i = 0, j = obj.childNodes.length; i < j; 
i++) {
                                        if(obj.childNodes[i] && 
obj.childNodes[i].className && 
obj.childNodes[i].className.indexOf("jstree-anchor") !== -1) {
                                                tmp = obj.childNodes[i];
@@ -4753,7 +5108,9 @@
                                }
                                if(tmp) {
                                        
if(!this.settings.checkbox.tie_selection && 
this._model.data[obj.id].state.checked) { tmp.className += ' jstree-checked'; }
-                                       tmp.insertBefore(_i.cloneNode(false), 
tmp.childNodes[0]);
+                                       icon = _i.cloneNode(false);
+                                       
if(this._model.data[obj.id].state.checkbox_disabled) { icon.className += ' 
jstree-checkbox-disabled'; }
+                                       tmp.insertBefore(icon, 
tmp.childNodes[0]);
                                }
                        }
                        if(!is_callback && 
this.settings.checkbox.cascade.indexOf('undetermined') !== -1) {
@@ -4802,14 +5159,92 @@
                        }
                        return false;
                };
+               /**
+                * disable a node's checkbox
+                * @name disable_checkbox(obj)
+                * @param {mixed} obj an array can be used too
+                * @trigger disable_checkbox.jstree
+                * @plugin checkbox
+                */
+               this.disable_checkbox = function (obj) {
+                       var t1, t2, dom;
+                       if($.isArray(obj)) {
+                               obj = obj.slice();
+                               for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+                                       this.disable_checkbox(obj[t1]);
+                               }
+                               return true;
+                       }
+                       obj = this.get_node(obj);
+                       if(!obj || obj.id === $.jstree.root) {
+                               return false;
+                       }
+                       dom = this.get_node(obj, true);
+                       if(!obj.state.checkbox_disabled) {
+                               obj.state.checkbox_disabled = true;
+                               if(dom && dom.length) {
+                                       
dom.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-checkbox-disabled');
+                               }
+                               /**
+                                * triggered when an node's checkbox is disabled
+                                * @event
+                                * @name disable_checkbox.jstree
+                                * @param {Object} node
+                                * @plugin checkbox
+                                */
+                               this.trigger('disable_checkbox', { 'node' : obj 
});
+                       }
+               };
+               /**
+                * enable a node's checkbox
+                * @name disable_checkbox(obj)
+                * @param {mixed} obj an array can be used too
+                * @trigger enable_checkbox.jstree
+                * @plugin checkbox
+                */
+               this.enable_checkbox = function (obj) {
+                       var t1, t2, dom;
+                       if($.isArray(obj)) {
+                               obj = obj.slice();
+                               for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
+                                       this.enable_checkbox(obj[t1]);
+                               }
+                               return true;
+                       }
+                       obj = this.get_node(obj);
+                       if(!obj || obj.id === $.jstree.root) {
+                               return false;
+                       }
+                       dom = this.get_node(obj, true);
+                       if(obj.state.checkbox_disabled) {
+                               obj.state.checkbox_disabled = false;
+                               if(dom && dom.length) {
+                                       
dom.children('.jstree-anchor').children('.jstree-checkbox').removeClass('jstree-checkbox-disabled');
+                               }
+                               /**
+                                * triggered when an node's checkbox is enabled
+                                * @event
+                                * @name enable_checkbox.jstree
+                                * @param {Object} node
+                                * @plugin checkbox
+                                */
+                               this.trigger('enable_checkbox', { 'node' : obj 
});
+                       }
+               };
 
                this.activate_node = function (obj, e) {
+                       if($(e.target).hasClass('jstree-checkbox-disabled')) {
+                               return false;
+                       }
                        if(this.settings.checkbox.tie_selection && 
(this.settings.checkbox.whole_node || $(e.target).hasClass('jstree-checkbox'))) 
{
                                e.ctrlKey = true;
                        }
                        if(this.settings.checkbox.tie_selection || 
(!this.settings.checkbox.whole_node && 
!$(e.target).hasClass('jstree-checkbox'))) {
                                return parent.activate_node.call(this, obj, e);
                        }
+                       if(this.is_disabled(obj)) {
+                               return false;
+                       }
                        if(this.is_checked(obj)) {
                                this.uncheck_node(obj, e);
                        }
@@ -4837,7 +5272,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        dom = this.get_node(obj, true);
@@ -4861,8 +5296,8 @@
                };
                /**
                 * uncheck a node (only if tie_selection in checkbox settings 
is false, otherwise deselect_node will be called internally)
-                * @name deselect_node(obj)
-                * @param {mixed} obj an array can be used to deselect multiple 
nodes
+                * @name uncheck_node(obj)
+                * @param {mixed} obj an array can be used to uncheck multiple 
nodes
                 * @trigger uncheck_node.jstree
                 * @plugin checkbox
                 */
@@ -4877,7 +5312,7 @@
                                return true;
                        }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') {
+                       if(!obj || obj.id === $.jstree.root) {
                                return false;
                        }
                        dom = this.get_node(obj, true);
@@ -4908,7 +5343,7 @@
                this.check_all = function () {
                        if(this.settings.checkbox.tie_selection) { return 
this.select_all(); }
                        var tmp = this._data.checkbox.selected.concat([]), i, j;
-                       this._data.checkbox.selected = 
this._model.data['#'].children_d.concat();
+                       this._data.checkbox.selected = 
this._model.data[$.jstree.root].children_d.concat();
                        for(i = 0, j = this._data.checkbox.selected.length; i < 
j; i++) {
                                
if(this._model.data[this._data.checkbox.selected[i]]) {
                                        
this._model.data[this._data.checkbox.selected[i]].state.checked = true;
@@ -4960,7 +5395,7 @@
                this.is_checked = function (obj) {
                        if(this.settings.checkbox.tie_selection) { return 
this.is_selected(obj); }
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
                        return obj.state.checked;
                };
                /**
@@ -5021,12 +5456,77 @@
                        }
                        return full ? $.map(obj, $.proxy(function (i) { return 
this.get_node(i); }, this)) : obj;
                };
+               this.load_node = function (obj, callback) {
+                       var k, l, i, j, c, tmp;
+                       if(!$.isArray(obj) && 
!this.settings.checkbox.tie_selection) {
+                               tmp = this.get_node(obj);
+                               if(tmp && tmp.state.loaded) {
+                                       for(k = 0, l = tmp.children_d.length; k 
< l; k++) {
+                                               
if(this._model.data[tmp.children_d[k]].state.checked) {
+                                                       c = true;
+                                                       
this._data.checkbox.selected = 
$.vakata.array_remove_item(this._data.checkbox.selected, tmp.children_d[k]);
+                                               }
+                                       }
+                               }
+                       }
+                       return parent.load_node.apply(this, arguments);
+               };
+               this.get_state = function () {
+                       var state = parent.get_state.apply(this, arguments);
+                       if(this.settings.checkbox.tie_selection) { return 
state; }
+                       state.checkbox = this._data.checkbox.selected.slice();
+                       return state;
+               };
+               this.set_state = function (state, callback) {
+                       var res = parent.set_state.apply(this, arguments);
+                       if(res && state.checkbox) {
+                               if(!this.settings.checkbox.tie_selection) {
+                                       this.uncheck_all();
+                                       var _this = this;
+                                       $.each(state.checkbox, function (i, v) {
+                                               _this.check_node(v);
+                                       });
+                               }
+                               delete state.checkbox;
+                               this.set_state(state, callback);
+                               return false;
+                       }
+                       return res;
+               };
+               this.refresh = function (skip_loading, forget_state) {
+                       if(!this.settings.checkbox.tie_selection) {
+                               this._data.checkbox.selected = [];
+                       }
+                       return parent.refresh.apply(this, arguments);
+               };
        };
 
        // include the checkbox plugin by default
        // $.jstree.defaults.plugins.push("checkbox");
 
 /**
+ * ### Conditionalselect plugin
+ *
+ * This plugin allows defining a callback to allow or deny node selection by 
user input (activate node method).
+ */
+
+       /**
+        * a callback (function) which is invoked in the instance's scope and 
receives two arguments - the node and the event that triggered the 
`activate_node` call. Returning false prevents working with the node, returning 
true allows invoking activate_node. Defaults to returning `true`.
+        * @name $.jstree.defaults.checkbox.visible
+        * @plugin checkbox
+        */
+       $.jstree.defaults.conditionalselect = function () { return true; };
+       $.jstree.plugins.conditionalselect = function (options, parent) {
+               // own function
+               this.activate_node = function (obj, e) {
+                       if(this.settings.conditionalselect.call(this, 
this.get_node(obj), e)) {
+                               parent.activate_node.call(this, obj, e);
+                       }
+               };
+       };
+
+
+/**
  * ### Contextmenu plugin
  *
  * Shows a context menu when a node is right-clicked.
@@ -5052,9 +5552,9 @@
                show_at_node : true,
                /**
                 * an object of actions, or a function that accepts a node and 
a callback function and calls the callback function with an object of actions 
available for that node (you can also return the items too).
-                * 
+                *
                 * Each action consists of a key (a unique name) and a value 
which is an object with the following properties (only label and action are 
required):
-                * 
+                *
                 * * `separator_before` - a boolean indicating if there should 
be a separator before this item
                 * * `separator_after` - a boolean indicating if there should 
be a separator after this item
                 * * `_disabled` - a boolean indicating if this action should 
be disabled
@@ -5063,7 +5563,7 @@
                 * * `icon` - a string, can be a path to an icon or a 
className, if using an image that is in the current directory use a `./` 
prefix, otherwise it will be detected as a class
                 * * `shortcut` - keyCode which will trigger the action if the 
menu is open (for example `113` for rename, which equals F2)
                 * * `shortcut_label` - shortcut label (like for example `F2` 
for rename)
-                * 
+                *
                 * @name $.jstree.defaults.contextmenu.items
                 * @plugin contextmenu
                 */
@@ -5087,7 +5587,7 @@
                                        "separator_after"       : false,
                                        "_disabled"                     : 
false, //(this.check("rename_node", data.reference, 
this.get_parent(data.reference), "")),
                                        "label"                         : 
"Rename",
-                                       /*
+                                       /*!
                                        "shortcut"                      : 113,
                                        "shortcut_label"        : 'F2',
                                        "icon"                          : 
"glyphicon glyphicon-leaf",
@@ -5130,7 +5630,7 @@
                                                                var inst = 
$.jstree.reference(data.reference),
                                                                        obj = 
inst.get_node(data.reference);
                                                                
if(inst.is_selected(obj)) {
-                                                                       
inst.cut(inst.get_selected());
+                                                                       
inst.cut(inst.get_top_selected());
                                                                }
                                                                else {
                                                                        
inst.cut(obj);
@@ -5146,7 +5646,7 @@
                                                                var inst = 
$.jstree.reference(data.reference),
                                                                        obj = 
inst.get_node(data.reference);
                                                                
if(inst.is_selected(obj)) {
-                                                                       
inst.copy(inst.get_selected());
+                                                                       
inst.copy(inst.get_top_selected());
                                                                }
                                                                else {
                                                                        
inst.copy(obj);
@@ -5177,21 +5677,49 @@
                this.bind = function () {
                        parent.bind.call(this);
 
-                       var last_ts = 0;
+                       var last_ts = 0, cto = null, ex, ey;
                        this.element
-                               .on("contextmenu.jstree", ".jstree-anchor", 
$.proxy(function (e) {
+                               .on("contextmenu.jstree", ".jstree-anchor", 
$.proxy(function (e, data) {
                                                e.preventDefault();
-                                               last_ts = e.ctrlKey ? 
e.timeStamp : 0;
+                                               last_ts = e.ctrlKey ? +new 
Date() : 0;
+                                               if(data || cto) {
+                                                       last_ts = (+new Date()) 
+ 10000;
+                                               }
+                                               if(cto) {
+                                                       clearTimeout(cto);
+                                               }
                                                
if(!this.is_loading(e.currentTarget)) {
                                                        
this.show_contextmenu(e.currentTarget, e.pageX, e.pageY, e);
                                                }
                                        }, this))
                                .on("click.jstree", ".jstree-anchor", 
$.proxy(function (e) {
-                                               
if(this._data.contextmenu.visible && (!last_ts || e.timeStamp - last_ts > 250)) 
{ // work around safari & macOS ctrl+click
+                                               
if(this._data.contextmenu.visible && (!last_ts || (+new Date()) - last_ts > 
250)) { // work around safari & macOS ctrl+click
                                                        $.vakata.context.hide();
                                                }
-                                       }, this));
-                       /*
+                                               last_ts = 0;
+                                       }, this))
+                               .on("touchstart.jstree", ".jstree-anchor", 
function (e) {
+                                               if(!e.originalEvent || 
!e.originalEvent.changedTouches || !e.originalEvent.changedTouches[0]) {
+                                                       return;
+                                               }
+                                               ex = e.pageX;
+                                               ey = e.pageY;
+                                               cto = setTimeout(function () {
+                                                       
$(e.currentTarget).trigger('contextmenu', true);
+                                               }, 750);
+                                       })
+                               .on('touchmove.vakata.jstree', function (e) {
+                                               if(cto && e.originalEvent && 
e.originalEvent.changedTouches && e.originalEvent.changedTouches[0] && 
(Math.abs(ex - e.pageX) > 50 || Math.abs(ey - e.pageY) > 50)) {
+                                                       clearTimeout(cto);
+                                               }
+                                       })
+                               .on('touchend.vakata.jstree', function (e) {
+                                               if(cto) {
+                                                       clearTimeout(cto);
+                                               }
+                                       });
+
+                       /*!
                        if(!('oncontextmenu' in document.body) && 
('ontouchstart' in document.body)) {
                                var el = null, tm = null;
                                this.element
@@ -5233,7 +5761,7 @@
                 */
                this.show_contextmenu = function (obj, x, y, e) {
                        obj = this.get_node(obj);
-                       if(!obj || obj.id === '#') { return false; }
+                       if(!obj || obj.id === $.jstree.root) { return false; }
                        var s = this.settings.contextmenu,
                                d = this.get_node(obj, true),
                                a = d.children(".jstree-anchor"),
@@ -5446,7 +5974,7 @@
                                        dw = $(window).width() + 
$(window).scrollLeft();
                                        dh = $(window).height() + 
$(window).scrollTop();
                                        if(right_to_left) {
-                                               x -= e.outerWidth();
+                                               x -= (e.outerWidth() - 
$(reference).outerWidth());
                                                if(x < $(window).scrollLeft() + 
20) {
                                                        x = 
$(window).scrollLeft() + 20;
                                                }
@@ -5597,7 +6125,9 @@
 
                        $(document)
                                .on("mousedown.vakata.jstree", function (e) {
-                                       if(vakata_context.is_visible && 
!$.contains(vakata_context.element[0], e.target)) { $.vakata.context.hide(); }
+                                       if(vakata_context.is_visible && 
!$.contains(vakata_context.element[0], e.target)) {
+                                               $.vakata.context.hide();
+                                       }
                                })
                                .on("context_show.vakata.jstree", function (e, 
data) {
                                        
vakata_context.element.find("li:has(ul)").children("a").addClass("vakata-context-parent");
@@ -5636,7 +6166,7 @@
                 */
                open_timeout : 500,
                /**
-                * a function invoked each time a node is about to be dragged, 
invoked in the tree's scope and receives the nodes about to be dragged as an 
argument (array) - return `false` to prevent dragging
+                * a function invoked each time a node is about to be dragged, 
invoked in the tree's scope and receives the nodes about to be dragged as an 
argument (array) and the event that started the drag - return `false` to 
prevent dragging
                 * @name $.jstree.defaults.dnd.is_draggable
                 * @plugin dnd
                 */
@@ -5658,7 +6188,31 @@
                 * @name $.jstree.defaults.dnd.inside_pos
                 * @plugin dnd
                 */
-               inside_pos : 0
+               inside_pos : 0,
+               /**
+                * when starting the drag on a node that is selected this 
setting controls if all selected nodes are dragged or only the single node, 
default is `true`, which means all selected nodes are dragged when the drag is 
started on a selected node
+                * @name $.jstree.defaults.dnd.drag_selection
+                * @plugin dnd
+                */
+               drag_selection : true,
+               /**
+                * controls whether dnd works on touch devices. If left as 
boolean true dnd will work the same as in desktop browsers, which in some cases 
may impair scrolling. If set to boolean false dnd will not work on touch 
devices. There is a special third option - string "selected" which means only 
selected nodes can be dragged on touch devices.
+                * @name $.jstree.defaults.dnd.touch
+                * @plugin dnd
+                */
+               touch : true,
+               /**
+                * controls whether items can be dropped anywhere on the node, 
not just on the anchor, by default only the node anchor is a valid drop target. 
Works best with the wholerow plugin. If enabled on mobile depending on the 
interface it might be hard for the user to cancel the drop, since the whole 
tree container will be a valid drop target.
+                * @name $.jstree.defaults.dnd.large_drop_target
+                * @plugin dnd
+                */
+               large_drop_target : false,
+               /**
+                * controls whether a drag can be initiated from any part of 
the node and not just the text/icon part, works best with the wholerow plugin. 
Keep in mind it can cause problems with tree scrolling on mobile depending on 
the interface - in that case set the touch option to "selected".
+                * @name $.jstree.defaults.dnd.large_drag_target
+                * @plugin dnd
+                */
+               large_drag_target : false
        };
        // TODO: now check works by checking for each node individually, how 
about max_children, unique, etc?
        $.jstree.plugins.dnd = function (options, parent) {
@@ -5666,14 +6220,24 @@
                        parent.bind.call(this);
 
                        this.element
-                               .on('mousedown.jstree touchstart.jstree', 
'.jstree-anchor', $.proxy(function (e) {
+                               .on('mousedown.jstree touchstart.jstree', 
this.settings.dnd.large_drag_target ? '.jstree-node' : '.jstree-anchor', 
$.proxy(function (e) {
+                                       if(this.settings.dnd.large_drag_target 
&& $(e.target).closest('.jstree-node')[0] !== e.currentTarget) {
+                                               return true;
+                                       }
+                                       if(e.type === "touchstart" && 
(!this.settings.dnd.touch || (this.settings.dnd.touch === 'selected' && 
!$(e.currentTarget).closest('.jstree-node').children('.jstree-anchor').hasClass('jstree-clicked'))))
 {
+                                               return true;
+                                       }
                                        var obj = this.get_node(e.target),
-                                               mlt = this.is_selected(obj) ? 
this.get_selected().length : 1;
-                                       if(obj && obj.id && obj.id !== "#" && 
(e.which === 1 || e.type === "touchstart") &&
-                                               (this.settings.dnd.is_draggable 
=== true || ($.isFunction(this.settings.dnd.is_draggable) && 
this.settings.dnd.is_draggable.call(this, (mlt > 1 ? this.get_selected(true) : 
[obj]))))
+                                               mlt = this.is_selected(obj) && 
this.settings.dnd.drag_selection ? this.get_top_selected().length : 1,
+                                               txt = (mlt > 1 ? mlt + ' ' + 
this.get_string('nodes') : this.get_text(e.currentTarget));
+                                       if(this.settings.core.force_text) {
+                                               txt = $.vakata.html.escape(txt);
+                                       }
+                                       if(obj && obj.id && obj.id !== 
$.jstree.root && (e.which === 1 || e.type === "touchstart") &&
+                                               (this.settings.dnd.is_draggable 
=== true || ($.isFunction(this.settings.dnd.is_draggable) && 
this.settings.dnd.is_draggable.call(this, (mlt > 1 ? 
this.get_top_selected(true) : [obj]), e)))
                                        ) {
                                                
this.element.trigger('mousedown.jstree');
-                                               return $.vakata.dnd.start(e, { 
'jstree' : true, 'origin' : this, 'obj' : this.get_node(obj,true), 'nodes' : 
mlt > 1 ? this.get_selected() : [obj.id] }, '<div id="jstree-dnd" 
class="jstree-' + this.get_theme() + ' jstree-' + this.get_theme() + '-' + 
this.get_theme_variant() + ' ' + ( this.settings.core.themes.responsive ? ' 
jstree-dnd-responsive' : '' ) + '"><i class="jstree-icon jstree-er"></i>' + 
(mlt > 1 ? mlt + ' ' + this.get_string('nodes') : 
this.get_text(e.currentTarget, true)) + '<ins class="jstree-copy" 
style="display:none;">+</ins></div>');
+                                               return $.vakata.dnd.start(e, { 
'jstree' : true, 'origin' : this, 'obj' : this.get_node(obj,true), 'nodes' : 
mlt > 1 ? this.get_top_selected() : [obj.id] }, '<div id="jstree-dnd" 
class="jstree-' + this.get_theme() + ' jstree-' + this.get_theme() + '-' + 
this.get_theme_variant() + ' ' + ( this.settings.core.themes.responsive ? ' 
jstree-dnd-responsive' : '' ) + '"><i class="jstree-icon jstree-er"></i>' + txt 
+ '<ins class="jstree-copy" style="display:none;">+</ins></div>');
                                        }
                                }, this));
                };
@@ -5683,12 +6247,14 @@
                // bind only once for all instances
                var lastmv = false,
                        laster = false,
+                       lastev = false,
                        opento = false,
                        marker = $('<div 
id="jstree-marker">&#160;</div>').hide(); //.appendTo('body');
 
                $(document)
                        .on('dnd_start.vakata.jstree', function (e, data) {
                                lastmv = false;
+                               lastev = false;
                                if(!data || !data.data || !data.data.jstree) { 
return; }
                                marker.appendTo('body'); //.show();
                        })
@@ -5700,12 +6266,13 @@
                                if(data.event.target.id && data.event.target.id 
=== 'jstree-marker') {
                                        return;
                                }
+                               lastev = data.event;
 
                                var ins = $.jstree.reference(data.event.target),
                                        ref = false,
                                        off = false,
                                        rel = false,
-                                       l, t, h, p, i, o, ok, t1, t2, op, ps, 
pr, ip, tm;
+                                       tmp, l, t, h, p, i, o, ok, t1, t2, op, 
ps, pr, ip, tm;
                                // if we are over an instance
                                if(ins && ins._data && ins._data.dnd) {
                                        marker.attr('class', 'jstree-' + 
ins.get_theme() + ( ins.settings.core.themes.responsive ? ' 
jstree-dnd-responsive' : '' ));
@@ -5718,11 +6285,11 @@
                                        if( (data.event.target === 
ins.element[0] || data.event.target === ins.get_container_ul()[0]) && 
ins.get_container_ul().children().length === 0) {
                                                ok = true;
                                                for(t1 = 0, t2 = 
data.data.nodes.length; t1 < t2; t1++) {
-                                                       ok = ok && ins.check( 
(data.data.origin && (data.data.origin.settings.dnd.always_copy || 
(data.data.origin.settings.dnd.copy && (data.event.metaKey || 
data.event.ctrlKey)) ) ? "copy_node" : "move_node"), (data.data.origin && 
data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : 
data.data.nodes[t1]), '#', 'last', { 'dnd' : true, 'ref' : ins.get_node('#'), 
'pos' : 'i', 'is_multi' : (data.data.origin && data.data.origin !== ins), 
'is_foreign' : (!data.data.origin) });
+                                                       ok = ok && ins.check( 
(data.data.origin && (data.data.origin.settings.dnd.always_copy || 
(data.data.origin.settings.dnd.copy && (data.event.metaKey || 
data.event.ctrlKey)) ) ? "copy_node" : "move_node"), (data.data.origin && 
data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : 
data.data.nodes[t1]), $.jstree.root, 'last', { 'dnd' : true, 'ref' : 
ins.get_node($.jstree.root), 'pos' : 'i', 'origin' : data.data.origin, 
'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : 
(!data.data.origin) });
                                                        if(!ok) { break; }
                                                }
                                                if(ok) {
-                                                       lastmv = { 'ins' : ins, 
'par' : '#', 'pos' : 'last' };
+                                                       lastmv = { 'ins' : ins, 
'par' : $.jstree.root, 'pos' : 'last' };
                                                        marker.hide();
                                                        
data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');
                                                        return;
@@ -5730,11 +6297,11 @@
                                        }
                                        else {
                                                // if we are hovering a tree 
node
-                                               ref = 
$(data.event.target).closest('.jstree-anchor');
+                                               ref = 
ins.settings.dnd.large_drop_target ? 
$(data.event.target).closest('.jstree-node').children('.jstree-anchor') : 
$(data.event.target).closest('.jstree-anchor');
                                                if(ref && ref.length && 
ref.parent().is('.jstree-closed, .jstree-open, .jstree-leaf')) {
                                                        off = ref.offset();
                                                        rel = data.event.pageY 
- off.top;
-                                                       h = ref.height();
+                                                       h = ref.outerHeight();
                                                        if(rel < h / 3) {
                                                                o = ['b', 'i', 
'a'];
                                                        }
@@ -5777,7 +6344,7 @@
                                                                                
        ps -= 1;
                                                                                
}
                                                                        }
-                                                                       ok = ok 
&& ( (ins && ins.settings && ins.settings.dnd && 
ins.settings.dnd.check_while_dragging === false) || ins.check(op, 
(data.data.origin && data.data.origin !== ins ? 
data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), p, ps, { 
'dnd' : true, 'ref' : ins.get_node(ref.parent()), 'pos' : v, 'is_multi' : 
(data.data.origin && data.data.origin !== ins), 'is_foreign' : 
(!data.data.origin) }) );
+                                                                       ok = ok 
&& ( (ins && ins.settings && ins.settings.dnd && 
ins.settings.dnd.check_while_dragging === false) || ins.check(op, 
(data.data.origin && data.data.origin !== ins ? 
data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), p, ps, { 
'dnd' : true, 'ref' : ins.get_node(ref.parent()), 'pos' : v, 'origin' : 
data.data.origin, 'is_multi' : (data.data.origin && data.data.origin !== ins), 
'is_foreign' : (!data.data.origin) }) );
                                                                        if(!ok) 
{
                                                                                
if(ins && ins.last_error) { laster = ins.last_error(); }
                                                                                
break;
@@ -5807,6 +6374,7 @@
                                if(!data || !data.data || !data.data.jstree) { 
return; }
                                marker.hide();
                                lastmv = false;
+                               lastev = false;
                                
data.helper.find('.jstree-icon').first().removeClass('jstree-ok').addClass('jstree-er');
                        })
                        .on('dnd_stop.vakata.jstree', function (e, data) {
@@ -5817,16 +6385,8 @@
                                if(lastmv) {
                                        for(i = 0, j = data.data.nodes.length; 
i < j; i++) {
                                                nodes[i] = data.data.origin ? 
data.data.origin.get_node(data.data.nodes[i]) : data.data.nodes[i];
-                                               if(data.data.origin) {
-                                                       nodes[i].instance = 
data.data.origin;
-                                               }
                                        }
-                                       lastmv.ins[ data.data.origin && 
(data.data.origin.settings.dnd.always_copy || 
(data.data.origin.settings.dnd.copy && (data.event.metaKey || 
data.event.ctrlKey))) ? 'copy_node' : 'move_node' ](nodes, lastmv.par, 
lastmv.pos);
-                                       for(i = 0, j = nodes.length; i < j; 
i++) {
-                                               if(nodes[i].instance) {
-                                                       nodes[i].instance = 
null;
-                                               }
-                                       }
+                                       lastmv.ins[ data.data.origin && 
(data.data.origin.settings.dnd.always_copy || 
(data.data.origin.settings.dnd.copy && (data.event.metaKey || 
data.event.ctrlKey))) ? 'copy_node' : 'move_node' ](nodes, lastmv.par, 
lastmv.pos, false, false, false, data.data.origin);
                                }
                                else {
                                        i = 
$(data.event.target).closest('.jstree');
@@ -5837,17 +6397,33 @@
                                                }
                                        }
                                }
+                               lastev = false;
+                               lastmv = false;
                        })
                        .on('keyup.jstree keydown.jstree', function (e, data) {
                                data = $.vakata.dnd._get();
                                if(data && data.data && data.data.jstree) {
                                        
data.helper.find('.jstree-copy').first()[ data.data.origin && 
(data.data.origin.settings.dnd.always_copy || 
(data.data.origin.settings.dnd.copy && (e.metaKey || e.ctrlKey))) ? 'show' : 
'hide' ]();
+                                       if(lastev) {
+                                               lastev.metaKey = e.metaKey;
+                                               lastev.ctrlKey = e.ctrlKey;
+                                               $.vakata.dnd._trigger('move', 
lastev);
+                                       }
                                }
                        });
        });
 
        // helpers
        (function ($) {
+               $.vakata.html = {
+                       div : $('<div />'),
+                       escape : function (str) {
+                               return $.vakata.html.div.text(str).html();
+                       },
+                       strip : function (str) {
+                               return 
$.vakata.html.div.empty().append($.parseHTML(str)).text();
+                       }
+               };
                // private variable
                var vakata_dnd = {
                        element : false,
@@ -6107,6 +6683,90 @@
 
 
 /**
+ * ### Massload plugin
+ *
+ * Adds massload functionality to jsTree, so that multiple nodes can be loaded 
in a single request (only useful with lazy loading).
+ */
+
+       /**
+        * massload configuration
+        *
+        * It is possible to set this to a standard jQuery-like AJAX config.
+        * In addition to the standard jQuery ajax options here you can supply 
functions for `data` and `url`, the functions will be run in the current 
instance's scope and a param will be passed indicating which node IDs need to 
be loaded, the return value of those functions will be used.
+        *
+        * You can also set this to a function, that function will receive the 
node IDs being loaded as argument and a second param which is a function 
(callback) which should be called with the result.
+        *
+        * Both the AJAX and the function approach rely on the same return 
value - an object where the keys are the node IDs, and the value is the 
children of that node as an array.
+        *
+        *      {
+        *              "id1" : [{ "text" : "Child of ID1", "id" : "c1" }, { 
"text" : "Another child of ID1", "id" : "c2" }],
+        *              "id2" : [{ "text" : "Child of ID2", "id" : "c3" }]
+        *      }
+        * 
+        * @name $.jstree.defaults.massload
+        * @plugin massload
+        */
+       $.jstree.defaults.massload = null;
+       $.jstree.plugins.massload = function (options, parent) {
+               this.init = function (el, options) {
+                       parent.init.call(this, el, options);
+                       this._data.massload = {};
+               };
+               this._load_nodes = function (nodes, callback, is_callback) {
+                       var s = this.settings.massload;
+                       if(is_callback && 
!$.isEmptyObject(this._data.massload)) {
+                               return parent._load_nodes.call(this, nodes, 
callback, is_callback);
+                       }
+                       if($.isFunction(s)) {
+                               return s.call(this, nodes, $.proxy(function 
(data) {
+                                       if(data) {
+                                               for(var i in data) {
+                                                       
if(data.hasOwnProperty(i)) {
+                                                               
this._data.massload[i] = data[i];
+                                                       }
+                                               }
+                                       }
+                                       parent._load_nodes.call(this, nodes, 
callback, is_callback);
+                               }, this));
+                       }
+                       if(typeof s === 'object' && s && s.url) {
+                               s = $.extend(true, {}, s);
+                               if($.isFunction(s.url)) {
+                                       s.url = s.url.call(this, nodes);
+                               }
+                               if($.isFunction(s.data)) {
+                                       s.data = s.data.call(this, nodes);
+                               }
+                               return $.ajax(s)
+                                       .done($.proxy(function (data,t,x) {
+                                                       if(data) {
+                                                               for(var i in 
data) {
+                                                                       
if(data.hasOwnProperty(i)) {
+                                                                               
this._data.massload[i] = data[i];
+                                                                       }
+                                                               }
+                                                       }
+                                                       
parent._load_nodes.call(this, nodes, callback, is_callback);
+                                               }, this))
+                                       .fail($.proxy(function (f) {
+                                                       
parent._load_nodes.call(this, nodes, callback, is_callback);
+                                               }, this));
+                       }
+                       return parent._load_nodes.call(this, nodes, callback, 
is_callback);
+               };
+               this._load_node = function (obj, callback) {
+                       var d = this._data.massload[obj.id];
+                       if(d) {
+                               return this[typeof d === 'string' ? 
'_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? 
$($.parseHTML(d)).filter(function () { return this.nodeType !== 3; }) : d, 
function (status) {
+                                       callback.call(this, status);
+                                       delete this._data.massload[obj.id];
+                               });
+                       }
+                       return parent._load_node.call(this, obj, callback);
+               };
+       };
+
+/**
  * ### Search plugin
  *
  * Adds search functionality to jsTree.
@@ -6121,8 +6781,8 @@
                /**
                 * a jQuery-like AJAX config, which jstree uses if a server 
should be queried for results. 
                 * 
-                * A `str` (which is the search string) parameter will be added 
with the request. The expected result is a JSON array with nodes that need to 
be opened so that matching nodes will be revealed.
-                * Leave this setting as `false` to not query the server. You 
can also set this to a function, which will be invoked in the instance's scope 
and receive 2 parameters - the search string and the callback to call with the 
array of nodes to load.
+                * A `str` (which is the search string) parameter will be added 
with the request, an optional `inside` parameter will be added if the search is 
limited to a node id. The expected result is a JSON array with nodes that need 
to be opened so that matching nodes will be revealed.
+                * Leave this setting as `false` to not query the server. You 
can also set this to a function, which will be invoked in the instance's scope 
and receive 3 parameters - the search string, the callback to call with the 
array of nodes to load, and the optional node ID to limit the search to 
                 * @name $.jstree.defaults.search.ajax
                 * @plugin search
                 */
@@ -6147,6 +6807,13 @@
                 */
                show_only_matches : false,
                /**
+                * Indicates if the children of matched element are shown (when 
show_only_matches is true)
+                * This setting can be changed at runtime when calling the 
search method. Default is `false`.
+                * @name $.jstree.defaults.search.show_only_matches_children
+                * @plugin search
+                */
+               show_only_matches_children : false,
+               /**
                 * Indicates if all nodes opened to reveal the search result, 
should be closed when the search is cleared or a new search is performed. 
Default is `true`.
                 * @name $.jstree.defaults.search.close_opened_onclear
                 * @plugin search
@@ -6176,39 +6843,30 @@
                        this._data.search.res = [];
                        this._data.search.opn = [];
                        this._data.search.som = false;
+                       this._data.search.smc = false;
+                       this._data.search.hdn = [];
 
                        this.element
-                               .on('before_open.jstree', $.proxy(function (e, 
data) {
-                                               var i, j, f, r = 
this._data.search.res, s = [], o = $();
-                                               if(r && r.length) {
-                                                       this._data.search.dom = 
$(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return 
"0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + 
v.substr(1).replace($.jstree.idregex,'\\$&') : 
v.replace($.jstree.idregex,'\\$&'); }).join(', #')));
-                                                       
this._data.search.dom.children(".jstree-anchor").addClass('jstree-search');
-                                                       
if(this._data.search.som && this._data.search.res.length) {
-                                                               for(i = 0, j = 
r.length; i < j; i++) {
-                                                                       s = 
s.concat(this.get_node(r[i]).parents);
+                               .on("search.jstree", $.proxy(function (e, data) 
{
+                                               if(this._data.search.som && 
data.res.length) {
+                                                       var m = 
this._model.data, i, j, p = [];
+                                                       for(i = 0, j = 
data.res.length; i < j; i++) {
+                                                               
if(m[data.res[i]] && !m[data.res[i]].state.hidden) {
+                                                                       
p.push(data.res[i]);
+                                                                       p = 
p.concat(m[data.res[i]].parents);
+                                                                       
if(this._data.search.smc) {
+                                                                               
p = p.concat(m[data.res[i]].children_d);
+                                                                       }
                                                                }
-                                                               s = 
$.vakata.array_remove_item($.vakata.array_unique(s),'#');
-                                                               o = s.length ? 
$(this.element[0].querySelectorAll('#' + $.map(s, function (v) { return 
"0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + 
v.substr(1).replace($.jstree.idregex,'\\$&') : 
v.replace($.jstree.idregex,'\\$&'); }).join(', #'))) : $();
-
-                                                               
this.element.find(".jstree-node").hide().filter('.jstree-last').filter(function()
 { return this.nextSibling; }).removeClass('jstree-last');
-                                                               o = 
o.add(this._data.search.dom);
-                                                               
o.parentsUntil(".jstree").addBack().show()
-                                                                       
.filter(".jstree-children").each(function () { 
$(this).children(".jstree-node:visible").eq(-1).addClass("jstree-last"); });
                                                        }
+                                                       p = 
$.vakata.array_remove_item($.vakata.array_unique(p), $.jstree.root);
+                                                       this._data.search.hdn = 
this.hide_all(true);
+                                                       this.show_node(p);
                                                }
                                        }, this))
-                               .on("search.jstree", $.proxy(function (e, data) 
{
-                                               if(this._data.search.som) {
-                                                       if(data.nodes.length) {
-                                                               
this.element.find(".jstree-node").hide().filter('.jstree-last').filter(function()
 { return this.nextSibling; }).removeClass('jstree-last');
-                                                               
data.nodes.parentsUntil(".jstree").addBack().show()
-                                                                       
.filter(".jstree-children").each(function () { 
$(this).children(".jstree-node:visible").eq(-1).addClass("jstree-last"); });
-                                                       }
-                                               }
-                                       }, this))
                                .on("clear_search.jstree", $.proxy(function (e, 
data) {
-                                               if(this._data.search.som && 
data.nodes.length) {
-                                                       
this.element.find(".jstree-node").css("display","").filter('.jstree-last').filter(function()
 { return this.nextSibling; }).removeClass('jstree-last');
+                                               if(this._data.search.som && 
data.res.length) {
+                                                       
this.show_node(this._data.search.hdn);
                                                }
                                        }, this));
                };
@@ -6218,38 +6876,49 @@
                 * @param {String} str the search string
                 * @param {Boolean} skip_async if set to true server will not 
be queried even if configured
                 * @param {Boolean} show_only_matches if set to true only 
matching nodes will be shown (keep in mind this can be very slow on large trees 
or old browsers)
+                * @param {mixed} inside an optional node to whose children to 
limit the search
+                * @param {Boolean} append if set to true the results of this 
search are appended to the previous search
                 * @plugin search
                 * @trigger search.jstree
                 */
-               this.search = function (str, skip_async, show_only_matches) {
+               this.search = function (str, skip_async, show_only_matches, 
inside, append, show_only_matches_children) {
                        if(str === false || $.trim(str.toString()) === "") {
                                return this.clear_search();
                        }
+                       inside = this.get_node(inside);
+                       inside = inside && inside.id ? inside.id : null;
                        str = str.toString();
                        var s = this.settings.search,
                                a = s.ajax ? s.ajax : false,
+                               m = this._model.data,
                                f = null,
                                r = [],
                                p = [], i, j;
-                       if(this._data.search.res.length) {
+                       if(this._data.search.res.length && !append) {
                                this.clear_search();
                        }
                        if(show_only_matches === undefined) {
                                show_only_matches = s.show_only_matches;
                        }
+                       if(show_only_matches_children === undefined) {
+                               show_only_matches_children = 
s.show_only_matches_children;
+                       }
                        if(!skip_async && a !== false) {
                                if($.isFunction(a)) {
                                        return a.call(this, str, 
$.proxy(function (d) {
                                                        if(d && d.d) { d = d.d; 
}
                                                        
this._load_nodes(!$.isArray(d) ? [] : $.vakata.array_unique(d), function () {
-                                                               
this.search(str, true, show_only_matches);
+                                                               
this.search(str, true, show_only_matches, inside, append);
                                                        }, true);
-                                               }, this));
+                                               }, this), inside);
                                }
                                else {
                                        a = $.extend({}, a);
                                        if(!a.data) { a.data = {}; }
                                        a.data.str = str;
+                                       if(inside) {
+                                               a.data.inside = inside;
+                                       }
                                        return $.ajax(a)
                                                .fail($.proxy(function () {
                                                        
this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'search', 'id' : 
'search_01', 'reason' : 'Could not load search parents', 'data' : 
JSON.stringify(a) };
@@ -6258,30 +6927,43 @@
                                                .done($.proxy(function (d) {
                                                        if(d && d.d) { d = d.d; 
}
                                                        
this._load_nodes(!$.isArray(d) ? [] : $.vakata.array_unique(d), function () {
-                                                               
this.search(str, true, show_only_matches);
+                                                               
this.search(str, true, show_only_matches, inside, append);
                                                        }, true);
                                                }, this));
                                }
                        }
-                       this._data.search.str = str;
-                       this._data.search.dom = $();
-                       this._data.search.res = [];
-                       this._data.search.opn = [];
-                       this._data.search.som = show_only_matches;
+                       if(!append) {
+                               this._data.search.str = str;
+                               this._data.search.dom = $();
+                               this._data.search.res = [];
+                               this._data.search.opn = [];
+                               this._data.search.som = show_only_matches;
+                               this._data.search.smc = 
show_only_matches_children;
+                       }
 
                        f = new $.vakata.search(str, true, { caseSensitive : 
s.case_sensitive, fuzzy : s.fuzzy });
-
-                       $.each(this._model.data, function (i, v) {
-                               if(v.text && ( (s.search_callback && 
s.search_callback.call(this, str, v)) || (!s.search_callback && 
f.search(v.text).isMatch) ) && (!s.search_leaves_only || (v.state.loaded && 
v.children.length === 0)) ) {
+                       $.each(m[inside ? inside : $.jstree.root].children_d, 
function (ii, i) {
+                               var v = m[i];
+                               if(v.text && (!s.search_leaves_only || 
(v.state.loaded && v.children.length === 0)) && ( (s.search_callback && 
s.search_callback.call(this, str, v)) || (!s.search_callback && 
f.search(v.text).isMatch) ) ) {
                                        r.push(i);
                                        p = p.concat(v.parents);
                                }
                        });
                        if(r.length) {
                                p = $.vakata.array_unique(p);
-                               this._search_open(p);
-                               this._data.search.dom = 
$(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return 
"0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + 
v.substr(1).replace($.jstree.idregex,'\\$&') : 
v.replace($.jstree.idregex,'\\$&'); }).join(', #')));
-                               this._data.search.res = r;
+                               for(i = 0, j = p.length; i < j; i++) {
+                                       if(p[i] !== $.jstree.root && m[p[i]] && 
this.open_node(p[i], null, 0) === true) {
+                                               
this._data.search.opn.push(p[i]);
+                                       }
+                               }
+                               if(!append) {
+                                       this._data.search.dom = 
$(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return 
"0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + 
v.substr(1).replace($.jstree.idregex,'\\$&') : 
v.replace($.jstree.idregex,'\\$&'); }).join(', #')));
+                                       this._data.search.res = r;
+                               }
+                               else {
+                                       this._data.search.dom = 
this._data.search.dom.add($(this.element[0].querySelectorAll('#' + $.map(r, 
function (v) { return "0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + 
v.substr(1).replace($.jstree.idregex,'\\$&') : 
v.replace($.jstree.idregex,'\\$&'); }).join(', #'))));
+                                       this._data.search.res = 
$.vakata.array_unique(this._data.search.res.concat(r));
+                               }
                                
this._data.search.dom.children(".jstree-anchor").addClass('jstree-search');
                        }
                        /**
@@ -6302,7 +6984,6 @@
                 * @trigger clear_search.jstree
                 */
                this.clear_search = function () {
-                       
this._data.search.dom.children(".jstree-anchor").removeClass("jstree-search");
                        if(this.settings.search.close_opened_onclear) {
                                this.close_node(this._data.search.opn, 0);
                        }
@@ -6316,30 +6997,35 @@
                         * @plugin search
                         */
                        this.trigger('clear_search', { 'nodes' : 
this._data.search.dom, str : this._data.search.str, res : this._data.search.res 
});
+                       if(this._data.search.res.length) {
+                               this._data.search.dom = 
$(this.element[0].querySelectorAll('#' + $.map(this._data.search.res, function 
(v) {
+                                       return "0123456789".indexOf(v[0]) !== 
-1 ? '\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\$&') : 
v.replace($.jstree.idregex,'\\$&');
+                               }).join(', #')));
+                               
this._data.search.dom.children(".jstree-anchor").removeClass("jstree-search");
+                       }
                        this._data.search.str = "";
                        this._data.search.res = [];
                        this._data.search.opn = [];
                        this._data.search.dom = $();
                };
-               /**
-                * opens nodes that need to be opened to reveal the search 
results. Used only internally.
-                * @private
-                * @name _search_open(d)
-                * @param {Array} d an array of node IDs
-                * @plugin search
-                */
-               this._search_open = function (d) {
-                       var t = this;
-                       $.each(d.concat([]), function (i, v) {
-                               if(v === "#") { return true; }
-                               try { v = $('#' + 
v.replace($.jstree.idregex,'\\$&'), t.element); } catch(ignore) { }
-                               if(v && v.length) {
-                                       if(t.is_closed(v)) {
-                                               
t._data.search.opn.push(v[0].id);
-                                               t.open_node(v, function () { 
t._search_open(d); }, 0);
+
+               this.redraw_node = function(obj, deep, callback, force_render) {
+                       obj = parent.redraw_node.apply(this, arguments);
+                       if(obj) {
+                               if($.inArray(obj.id, this._data.search.res) !== 
-1) {
+                                       var i, j, tmp = null;
+                                       for(i = 0, j = obj.childNodes.length; i 
< j; i++) {
+                                               if(obj.childNodes[i] && 
obj.childNodes[i].className && 
obj.childNodes[i].className.indexOf("jstree-anchor") !== -1) {
+                                                       tmp = obj.childNodes[i];
+                                                       break;
+                                               }
                                        }
+                                       if(tmp) {
+                                               tmp.className += ' 
jstree-search';
+                                       }
                                }
-                       });
+                       }
+                       return obj;
                };
        };
 
@@ -6348,13 +7034,14 @@
                // from http://kiro.me/projects/fuse.html
                $.vakata.search = function(pattern, txt, options) {
                        options = options || {};
+                       options = $.extend({}, $.vakata.search.defaults, 
options);
                        if(options.fuzzy !== false) {
                                options.fuzzy = true;
                        }
                        pattern = options.caseSensitive ? pattern : 
pattern.toLowerCase();
-                       var MATCH_LOCATION      = options.location || 0,
-                               MATCH_DISTANCE  = options.distance || 100,
-                               MATCH_THRESHOLD = options.threshold || 0.6,
+                       var MATCH_LOCATION      = options.location,
+                               MATCH_DISTANCE  = options.distance,
+                               MATCH_THRESHOLD = options.threshold,
                                patternLen = pattern.length,
                                matchmask, pattern_alphabet, match_bitapScore, 
search;
                        if(patternLen > 32) {
@@ -6462,11 +7149,19 @@
                        };
                        return txt === true ? { 'search' : search } : 
search(txt);
                };
+               $.vakata.search.defaults = {
+                       location : 0,
+                       distance : 100,
+                       threshold : 0.6,
+                       fuzzy : false,
+                       caseSensitive : false
+               };
        }($));
 
        // include the search plugin by default
        // $.jstree.defaults.plugins.push("search");
 
+
 /**
  * ### Sort plugin
  *
@@ -6549,7 +7244,7 @@
                 * @name $.jstree.defaults.state.events
                 * @plugin state
                 */
-               events  : 'changed.jstree open_node.jstree close_node.jstree',
+               events  : 'changed.jstree open_node.jstree close_node.jstree 
check_node.jstree uncheck_node.jstree',
                /**
                 * Time in milliseconds after which the state will expire. 
Defaults to 'false' meaning - no expire.
                 * @name $.jstree.defaults.state.ttl
@@ -6571,6 +7266,13 @@
                                        if(to) { clearTimeout(to); }
                                        to = setTimeout($.proxy(function () { 
this.save_state(); }, this), 100);
                                }, this));
+                               /**
+                                * triggered when the state plugin is finished 
restoring the state (and immediately after ready if there is no state to 
restore).
+                                * @event
+                                * @name state_ready.jstree
+                                * @plugin state
+                                */
+                               this.trigger('state_ready');
                        }, this);
                        this.element
                                .on("ready.jstree", $.proxy(function (e, data) {
@@ -6635,31 +7337,31 @@
 
        /**
         * An object storing all types as key value pairs, where the key is the 
type name and the value is an object that could contain following keys (all 
optional).
-        * 
+        *
         * * `max_children` the maximum number of immediate children this node 
type can have. Do not specify or set to `-1` for unlimited.
         * * `max_depth` the maximum number of nesting this node type can have. 
A value of `1` would mean that the node can have children, but no 
grandchildren. Do not specify or set to `-1` for unlimited.
         * * `valid_children` an array of node type strings, that nodes of this 
type can have as children. Do not specify or set to `-1` for no limits.
         * * `icon` a string - can be a path to an icon or a className, if 
using an image that is in the current directory use a `./` prefix, otherwise it 
will be detected as a class. Omit to use the default icon from your theme.
         *
         * There are two predefined types:
-        * 
+        *
         * * `#` represents the root of the tree, for example `max_children` 
would control the maximum number of root nodes.
         * * `default` represents the default node - any settings here will be 
applied to all nodes that do not have a type specified.
-        * 
+        *
         * @name $.jstree.defaults.types
         * @plugin types
         */
        $.jstree.defaults.types = {
-               '#' : {},
                'default' : {}
        };
+       $.jstree.defaults.types[$.jstree.root] = {};
 
        $.jstree.plugins.types = function (options, parent) {
                this.init = function (el, options) {
                        var i, j;
                        if(options && options.types && 
options.types['default']) {
                                for(i in options.types) {
-                                       if(i !== "default" && i !== "#" && 
options.types.hasOwnProperty(i)) {
+                                       if(i !== "default" && i !== 
$.jstree.root && options.types.hasOwnProperty(i)) {
                                                for(j in 
options.types['default']) {
                                                        
if(options.types['default'].hasOwnProperty(j) && options.types[i][j] === 
undefined) {
                                                                
options.types[i][j] = options.types['default'][j];
@@ -6669,11 +7371,11 @@
                                }
                        }
                        parent.init.call(this, el, options);
-                       this._model.data['#'].type = '#';
+                       this._model.data[$.jstree.root].type = $.jstree.root;
                };
                this.refresh = function (skip_loading, forget_state) {
                        parent.refresh.call(this, skip_loading, forget_state);
-                       this._model.data['#'].type = '#';
+                       this._model.data[$.jstree.root].type = $.jstree.root;
                };
                this.bind = function () {
                        this.element
@@ -6695,7 +7397,7 @@
                                                                m[dpc[i]].icon 
= t[c].icon;
                                                        }
                                                }
-                                               m['#'].type = '#';
+                                               m[$.jstree.root].type = 
$.jstree.root;
                                        }, this));
                        parent.bind.call(this);
                };
@@ -6750,7 +7452,7 @@
                        if(parent.check.call(this, chk, obj, par, pos, more) 
=== false) { return false; }
                        obj = obj && obj.id ? obj : this.get_node(obj);
                        par = par && par.id ? par : this.get_node(par);
-                       var m = obj && obj.id ? $.jstree.reference(obj.id) : 
null, tmp, d, i, j;
+                       var m = obj && obj.id ? (more && more.origin ? 
more.origin : $.jstree.reference(obj.id)) : null, tmp, d, i, j;
                        m = m && m._model && m._model.data ? m._model.data : 
null;
                        switch(chk) {
                                case "create_node":
@@ -6911,7 +7613,7 @@
                                        }
                                        return i;
                                case "move_node":
-                                       i = (obj.parent === par.id || 
$.inArray(n, c) === -1);
+                                       i = ( (obj.parent === par.id && (!more 
|| !more.is_multi)) || $.inArray(n, c) === -1);
                                        if(!i) {
                                                this._data.core.last_error = { 
'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_03', 'reason' : 'Child 
with name ' + n + ' already exists. Preventing: ' + chk, 'data' : 
JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : 
false, 'par' : par && par.id ? par.id : false }) };
                                        }
@@ -6922,7 +7624,7 @@
                this.create_node = function (par, node, pos, callback, 
is_loaded) {
                        if(!node || node.text === undefined) {
                                if(par === null) {
-                                       par = "#";
+                                       par = $.jstree.root;
                                }
                                par = this.get_node(par);
                                if(!par) {
@@ -7001,6 +7703,15 @@
                                                var tmp = 
$.Event('contextmenu', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : 
e.altKey, shiftKey : e.shiftKey, pageX : e.pageX, pageY : e.pageY });
                                                
$(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp);
                                        }, this))
+                               /*!
+                               .on("mousedown.jstree touchstart.jstree", 
".jstree-wholerow", function (e) {
+                                               if(e.target === 
e.currentTarget) {
+                                                       var a = 
$(e.currentTarget).closest(".jstree-node").children(".jstree-anchor");
+                                                       e.target = a[0];
+                                                       a.trigger(e);
+                                               }
+                                       })
+                               */
                                .on("click.jstree", ".jstree-wholerow", 
function (e) {
                                                e.stopImmediatePropagation();
                                                var tmp = $.Event('click', { 
metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : 
e.shiftKey });
@@ -7042,9 +7753,6 @@
        };
        // include the wholerow plugin by default
        // $.jstree.defaults.plugins.push("wholerow");
-
-
-(function ($) {
        if(document.registerElement && Object && Object.create) {
                var proto = Object.create(HTMLElement.prototype);
                proto.createdCallback = function () {
@@ -7062,12 +7770,12 @@
                                        c.core[i] = 
JSON.parse(this.getAttribute(i)) || this.getAttribute(i);
                                }
                        }
-                       jQuery(this).jstree(c);
+                       $(this).jstree(c);
                };
                // proto.attributeChangedCallback = function (name, previous, 
value) { };
                try {
                        document.registerElement("vakata-jstree", { prototype: 
proto });
                } catch(ignore) { }
        }
-}(jQuery));
+
 }));
\ No newline at end of file

Modified: branches/dev-syncromind/phpgwapi/js/jquery/treeview/jstree.min.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/jquery/treeview/jstree.min.js   
2015-11-20 15:01:27 UTC (rev 14435)
+++ branches/dev-syncromind/phpgwapi/js/jquery/treeview/jstree.min.js   
2015-11-20 15:05:42 UTC (rev 14436)
@@ -1,5 +1,5 @@
-/*! jsTree - v3.0.8 - 2014-10-23 - (MIT) */

@@ Diff output truncated at 153600 characters. @@



reply via email to

[Prev in Thread] Current Thread [Next in Thread]