vendor/assets/javascripts/jstree.js in jstree-rails-4-3.1.1 vs vendor/assets/javascripts/jstree.js in jstree-rails-4-3.2.0

- old
+ new

@@ -1,21 +1,21 @@ -/*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); } }(function ($, undefined) { "use strict"; /*! - * jsTree 3.1.1 + * jsTree 3.2.0 * http://jstree.com/ * * Copyright (c) 2014 Ivan Bozhanov (http://vakata.com) * * Licensed same as jquery - under the terms of the MIT License @@ -26,11 +26,10 @@ * jslint: browser: true, ass: true, bitwise: true, continue: true, nomen: true, plusplus: true, regexp: true, unparam: true, todo: true, white: true */ // prevent another load? maybe there is a better way? if($.jstree) { - return; } /** * ### jsTree core functionality */ @@ -69,11 +68,11 @@ $.jstree = { /** * specifies the jstree version in use * @name $.jstree.version */ - version : '3.1.1', + version : '3.2.0', /** * holds all the default options used when creating new instances * @name $.jstree.defaults */ defaults : { @@ -87,11 +86,12 @@ * stores all loaded jstree plugins (used internally) * @name $.jstree.plugins */ plugins : {}, path : src && src.indexOf('/') !== -1 ? src.replace(/\/[^\/]+$/,'') : '', - idregex : /[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g + idregex : /[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g, + root : '#' }; /** * creates a jstree instance * @name $.jstree.create(el [, options]) * @param {DOMElement|jQuery|String} el the element to create the instance on, can be jQuery extended or a selector @@ -469,30 +469,29 @@ * @param {Object} options options for this instance * @trigger init.jstree, loading.jstree, loaded.jstree, ready.jstree, changed.jstree */ 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, default_state : { loaded : true, opened : false, selected : false, 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._data.core.ready = false; @@ -529,11 +528,11 @@ * triggered after the loading text is shown and before loading starts * @event * @name loading.jstree */ this.trigger("loading"); - this.load_node('#'); + this.load_node($.jstree.root); }, /** * destroy an instance * @name destroy() * @param {Boolean} keep_html if not set to `true` the container will be emptied, otherwise the current DOM elements will be kept intact @@ -572,11 +571,12 @@ bind : function () { var word = '', 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(); } else { if(window.getSelection) { @@ -599,21 +599,22 @@ }) .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; } else if(e.which === 39) { e.which = 37; } @@ -634,11 +635,11 @@ if(this.is_open(e.currentTarget)) { this.close_node(e.currentTarget); } 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 e.preventDefault(); o = this.get_prev_dom(e.currentTarget); @@ -674,20 +675,20 @@ /* // 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); } break; // f2 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; default: // console.log(e.which); @@ -695,11 +696,11 @@ */ } }, 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); } /** @@ -737,11 +738,11 @@ } } }, 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 = ''; }, 500); @@ -771,11 +772,11 @@ } }, this)); 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) { $(v).focus(); end = true; @@ -958,18 +959,18 @@ } else if((dom = $(obj, this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) { 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; } }, /** @@ -980,11 +981,11 @@ * @param {Boolean} ids if set to true build the path using ID, otherwise node text is used * @return {mixed} */ 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 = []; p.push(ids ? obj.id : obj.text); for(i = 0, j = obj.parents.length; i < j; i++) { @@ -1085,11 +1086,11 @@ * @param {mixed} obj * @return {String} */ get_parent : function (obj) { obj = this.get_node(obj); - if(!obj || obj.id === '#') { + if(!obj || obj.id === $.jstree.root) { return false; } return obj.parent; }, /** @@ -1211,12 +1212,18 @@ this._load_node(obj, $.proxy(function (status) { obj = this._model.data[obj.id]; obj.state.loading = false; obj.state.loaded = status; obj.state.failed = !obj.state.loaded; - var dom = this.get_node(obj, true); - if(obj.state.loaded && !obj.children.length && dom && dom.length && !dom.hasClass('jstree-leaf')) { + 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); /** * triggered after a node is loaded @@ -1269,11 +1276,11 @@ * @param {mixed} obj the node to load recursively, omit to load all nodes in the tree * @param {function} callback a function to be executed once loading all the nodes is complete, * @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 = [], m = this._model.data, c = m[obj.id].children_d, @@ -1312,19 +1319,19 @@ */ _load_node : function (obj, callback) { 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); }); } 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); @@ -1364,34 +1371,34 @@ this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'core', 'id' : 'core_04', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : f }) }; this.settings.core.error.call(this, this._data.core.last_error); }, 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); }); } else { this._data.core.last_error = { 'error' : 'nodata', 'plugin' : 'core', 'id' : 'core_05', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id }) }; 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 === '#') { + 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); }); } else { this._data.core.last_error = { 'error' : 'nodata', 'plugin' : 'core', 'id' : 'core_06', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id }) }; 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); }, /** * adds a node to the list of nodes to redraw. Used only internally. @@ -1446,11 +1453,11 @@ * @name model.jstree * @param {Array} nodes an array of node IDs * @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(); } else { this.get_container_ul().children('.jstree-initial-node').remove(); @@ -1791,11 +1798,11 @@ this._data.core.selected = this._data.core.selected.concat(rslt.add); } this.trigger('model', { "nodes" : rslt.dpc, 'parent' : rslt.par }); - if(rslt.par !== '#') { + if(rslt.par !== $.jstree.root) { this._node_changed(rslt.par); this.redraw(); } else { // this.get_container_ul().children('.jstree-initial-node').remove(); @@ -2184,11 +2191,11 @@ * @private * @name _redraw() * @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); if(tmp && this._model.force_full_redraw) { f.appendChild(tmp); @@ -2245,11 +2252,11 @@ i = false, j = false, k = false, d = document; if(!obj) { return false; } - if(obj.id === '#') { return this.redraw(true); } + 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]; @@ -2285,24 +2292,26 @@ m = this._model.data, f = false, s = false, tmp = null, t = 0, - l = 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 { node = $(node); if(!is_callback) { @@ -2347,18 +2356,43 @@ node.setAttribute('aria-labelledby', obj.a_attr.id); if(obj.state.disabled) { 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; node.className = c; c = ( obj.state.selected ? ' jstree-clicked' : '') + ( obj.state.disabled ? ' jstree-disabled' : ''); @@ -2468,11 +2502,11 @@ this.open_node(obj[t1], callback, animation); } 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; if(!this.is_closed(obj)) { if(callback) { @@ -2555,16 +2589,16 @@ * @param {mixed} obj the node to reveal * @private */ _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); } } return $('#' + obj.id.replace($.jstree.idregex,'\\$&'), this.element); }, @@ -2583,11 +2617,11 @@ this.close_node(obj[t1], animation); } return true; } obj = this.get_node(obj); - if(!obj || obj.id === '#') { + if(!obj || obj.id === $.jstree.root) { return false; } if(this.is_closed(obj)) { return false; } @@ -2656,14 +2690,14 @@ * @param {Number} animation the animation duration in milliseconds when opening the nodes, the default is no animation * @param {jQuery} reference to the node that started the process (internal use) * @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]])) { this._model.data[obj.children_d[i]].state.opened = true; } @@ -2696,23 +2730,22 @@ * @param {mixed} obj the node to close recursively, omit to close all nodes in the tree * @param {Number} animation the animation duration in milliseconds when closing the nodes, the default is no animation * @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 * @name close_all.jstree * @param {Object} node the closed node @@ -2743,11 +2776,11 @@ this.enable_node(obj[t1]); } return true; } obj = this.get_node(obj); - if(!obj || obj.id === '#') { + if(!obj || obj.id === $.jstree.root) { return false; } obj.state.disabled = false; this.get_node(obj,true).children('.jstree-anchor').removeClass('jstree-disabled').attr('aria-disabled', false); /** @@ -2772,11 +2805,11 @@ this.disable_node(obj[t1]); } return true; } obj = this.get_node(obj); - if(!obj || obj.id === '#') { + if(!obj || obj.id === $.jstree.root) { return false; } obj.state.disabled = true; this.get_node(obj,true).children('.jstree-anchor').addClass('jstree-disabled').attr('aria-disabled', true); /** @@ -2786,10 +2819,130 @@ * @param {Object} node the disabled node */ 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 (obj) { + 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; + 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 (obj) { + 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; + 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) * @param {mixed} obj the node * @param {Object} e the related event @@ -2797,10 +2950,13 @@ */ activate_node : function (obj, e) { 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; if(this._data.core.last_clicked && !this._data.core.last_clicked.state.selected) { this._data.core.last_clicked = null; } if(!this._data.core.last_clicked && this._data.core.selected.length) { this._data.core.last_clicked = this.get_node(this._data.core.selected[this._data.core.selected.length - 1]); } @@ -2851,12 +3007,13 @@ /** * triggered when an node is clicked or intercated with by the user * @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. * @private * @name hover_node(obj) @@ -2918,11 +3075,11 @@ this.select_node(obj[t1], supress_event, prevent_open, e); } 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); if(!obj.state.selected) { obj.state.selected = true; @@ -2971,11 +3128,11 @@ this.deselect_node(obj[t1], supress_event, e); } 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); if(obj.state.selected) { obj.state.selected = false; @@ -3003,11 +3160,11 @@ * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered * @trigger select_all.jstree, changed.jstree */ 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; } } @@ -3056,11 +3213,11 @@ * @param {mixed} obj * @return {Boolean} */ 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; }, /** @@ -3139,11 +3296,11 @@ 'selected' : [] } }, 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); } if(this._model.data[i].state.selected) { state.core.selected.push(i); @@ -3155,11 +3312,11 @@ }, /** * 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) { @@ -3235,26 +3392,29 @@ */ refresh : function (skip_loading, forget_state) { 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])) { this.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id); } @@ -3276,11 +3436,11 @@ * @param {mixed} obj the node * @trigger refresh_node.jstree */ 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); } this.get_node(obj, true).find('.jstree-open').each(function() { opened.push(this.id); }); this._load_nodes(to_load, $.proxy(function (nodes) { @@ -3303,11 +3463,11 @@ * @param {String} id the new ID * @return {Boolean} */ 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) m[obj.parent].children[$.inArray(obj.id, m[obj.parent].children)] = id; for(i = 0, j = obj.parents.length; i < j; i++) { @@ -3342,11 +3502,11 @@ * @param {mixed} obj the node * @return {String} */ 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)`. * @private * @name set_text(obj, val) @@ -3363,11 +3523,11 @@ this.set_text(obj[t1], val); } 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); } /** @@ -3391,11 +3551,11 @@ * @param {Boolean} options.no_data do not include node data * @param {Boolean} options.flat return flat JSON instead of nested * @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 = { 'id' : obj.id, 'text' : obj.text, @@ -3426,11 +3586,11 @@ } if(tmp.a_attr && tmp.a_attr.id) { 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) { for(i = 0, j = obj.children.length; i < j; i++) { if(options && options.flat) { @@ -3439,11 +3599,11 @@ else { tmp.children.push(this.get_json(obj.children[i], options)); } } } - 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) * @name create_node([obj, node, pos, callback, is_loaded]) * @param {mixed} par the parent node (to create a root node use either "#" (string) or `null`) @@ -3453,11 +3613,11 @@ * @param {Boolean} is_loaded internal argument indicating if the parent node was succesfully loaded * @return {String} the ID of the newly create node * @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; if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) { return this.load_node(par, function () { this.create_node(par, node, pos, callback, true); }); @@ -3465,11 +3625,11 @@ 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"; } } switch(pos) { case "before": @@ -3549,11 +3709,11 @@ this.rename_node(obj[t1], val); } 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); return false; } @@ -3575,20 +3735,20 @@ * @param {mixed} obj the node, you can pass an array to delete multiple nodes * @return {Boolean} * @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++) { this.delete_node(obj[t1]); } 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; if(!this.check("delete_node", obj, par, pos)) { this.settings.core.error.call(this, this._data.core.last_error); @@ -3626,10 +3786,23 @@ this.trigger('changed', { 'action' : 'delete_node', 'node' : obj, 'selected' : this._data.core.selected, 'parent' : par.id }); } 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; }, /** * check if an operation is premitted on the tree. Used internally. @@ -3712,14 +3885,14 @@ 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_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]; @@ -3731,11 +3904,11 @@ 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"; } } switch(pos) { case "before": @@ -3772,11 +3945,11 @@ tmp[i >= pos ? i+1 : i] = dpc[i]; } 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 tmp = obj.children_d.concat(); tmp.push(obj.id); @@ -3817,11 +3990,11 @@ for(i = 0, j = obj.children_d.length; i < j; i++) { this._model.data[obj.children_d[i]].parents = this._model.data[obj.children_d[i]].parents.slice(0,p*-1); 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) { this._node_changed(old_par); this._node_changed(new_par.id); @@ -3884,22 +4057,22 @@ 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_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(old_ins && old_ins._id) { obj = old_ins._model.data[obj.id]; } - if(par.id === '#') { + if(par.id === $.jstree.root) { if(pos === "before") { pos = "first"; } if(pos === "after") { pos = "last"; } } switch(pos) { case "before": @@ -3947,18 +4120,18 @@ dpc[pos] = tmp.id; new_par.children = dpc; 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); } /** * triggered when a node is copied * @event @@ -3987,11 +4160,11 @@ if(!$.isArray(obj)) { obj = [obj]; } if(!obj.length) { return false; } 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; ccp_inst = this; ccp_mode = 'move_node'; @@ -4014,11 +4187,11 @@ if(!$.isArray(obj)) { obj = [obj]; } if(!obj.length) { return false; } 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; ccp_inst = this; ccp_mode = 'copy_node'; @@ -4090,14 +4263,14 @@ /** * put a node in edit mode (input field to rename the node) * @name edit(obj [, default_text, callback]) * @param {mixed} obj * @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 and a status parameter - true if the rename is successful, false otherwise. You can access the node's title using .text + * @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, callback) { - var rtl, w, a, s, t, h1, h2, fn, tmp; + 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) { this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_07', 'reason' : 'Could not edit node because of check_callback' }; this.settings.core.error.call(this, this._data.core.last_error); @@ -4109,11 +4282,12 @@ obj = this._open_to(obj); tmp.text = default_text; rtl = this._data.core.rtl; w = this.element.width(); - a = obj.children('.jstree-anchor'); + 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, @@ -4132,11 +4306,13 @@ "display" : "inline-block", "height" : (this._data.core.li_height) + "px", "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(), f = this.settings.core.force_text, nv; if(v === "") { v = t; } @@ -4147,34 +4323,43 @@ this.set_text(obj, t); 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); + 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') || '', @@ -4309,11 +4494,11 @@ this.set_icon(obj[t1], icon); } 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 === 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); @@ -4340,11 +4525,11 @@ * @param {mixed} obj * @return {String} */ 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 * @name hide_icon(obj) * @param {mixed} obj @@ -4357,11 +4542,11 @@ this.hide_icon(obj[t1]); } 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; }, /** @@ -4377,11 +4562,11 @@ this.show_icon(obj[t1]); } 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; } dom.children(".jstree-anchor").children(".jstree-themeicon").removeClass('jstree-themeicon-hidden'); return true; @@ -4428,10 +4613,63 @@ 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. * 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. */ @@ -4519,11 +4757,11 @@ var m = this._model.data, p = m[data.parent], 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]); } } }, this)); @@ -4565,11 +4803,11 @@ } } 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' ]; } if(c === j) { @@ -4609,11 +4847,11 @@ } } // 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' ]; } if(c === j) { @@ -4635,11 +4873,11 @@ if(s.indexOf('down') !== -1 && dom.length) { dom.find('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked').parent().attr('aria-selected', true); } }, 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++) { tmp = m[obj.children_d[i]]; if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) { @@ -4703,11 +4941,11 @@ .on('delete_node.jstree', $.proxy(function (e, data) { // apply up (whole handler) 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) { c = 0; for(i = 0, j = p.children.length; i < j; i++) { c += m[p.children[i]].state[ t ? 'selected' : 'checked' ]; } if(c === j) { @@ -4731,11 +4969,11 @@ new_par = this.get_node(data.parent), m = this._model.data, 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) { c = 0; for(i = 0, j = p.children.length; i < j; i++) { c += m[p.children[i]].state[ t ? 'selected' : 'checked' ]; } if(c === j) { @@ -4751,11 +4989,11 @@ } p = this.get_node(p.parent); } } 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' ]; } if(c === j) { @@ -4796,11 +5034,11 @@ 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) { 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] !== '#') { + 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]); } } } @@ -4809,32 +5047,32 @@ this.element.find('.jstree-closed').not(':has(.jstree-children)') .each(function () { 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) { - if(o[tmp.id] === undefined && tmp.id !== '#') { + 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] !== '#') { + 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) { - if(o[tmp2.id] === undefined && tmp2.id !== '#') { + 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] !== '#') { + if(o[tmp2.parents[k]] === undefined && tmp2.parents[k] !== $.jstree.root) { o[tmp2.parents[k]] = true; p.push(tmp2.parents[k]); } } } @@ -4853,20 +5091,22 @@ } }; 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]; break; } } 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) { if(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); } this._data.checkbox.uto = setTimeout($.proxy(this._undetermined, this), 50); @@ -4911,12 +5151,87 @@ return true; } } 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); @@ -4949,11 +5264,11 @@ this.check_node(obj[t1], e); } 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); if(!obj.state.checked) { obj.state.checked = true; @@ -4989,11 +5304,11 @@ this.uncheck_node(obj[t1], e); } 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); if(obj.state.checked) { obj.state.checked = false; @@ -5020,11 +5335,11 @@ * @plugin checkbox */ 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; } } @@ -5072,11 +5387,11 @@ * @plugin checkbox */ 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; }; /** * get an array of all checked nodes (if tie_selection is on in the settings this function will return the same as get_selected) * @name get_checked([full]) @@ -5170,16 +5485,44 @@ 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. */ @@ -5410,11 +5753,11 @@ * @plugin contextmenu * @trigger show_contextmenu.jstree */ 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"), o = false, i = false; @@ -5815,11 +6158,11 @@ * @name $.jstree.defaults.dnd.open_timeout * @plugin dnd */ 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 */ is_draggable : true, /** @@ -5882,12 +6225,12 @@ 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 !== "#" && (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])))) + 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_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)); @@ -5896,16 +6239,18 @@ $(function() { // 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(); }) .on('dnd_move.vakata.jstree', function (e, data) { if(opento) { clearTimeout(opento); } @@ -5913,10 +6258,11 @@ // if we are hovering the marker image do nothing (can happen on "inside" drags) 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, @@ -5931,15 +6277,15 @@ // if are hovering the container itself add a new root node 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', 'origin' : data.data.origin, '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; } } @@ -6020,10 +6366,11 @@ }) .on('dnd_scroll.vakata.jstree', function (e, data) { 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) { if(opento) { clearTimeout(opento); } if(!data || !data.data || !data.data.jstree) { return; } @@ -6042,15 +6389,22 @@ if(i) { i.settings.core.error.call(this, laster); } } } + 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 @@ -6482,49 +6836,33 @@ this._data.search.dom = $(); 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); - } - 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); - if(this._data.search.smc) { - this._data.search.dom.children(".jstree-children").find(".jstree-node").show(); - } - o.parentsUntil(".jstree").addBack().show() - .filter(".jstree-children").each(function () { $(this).children(".jstree-node:visible").eq(-1).addClass("jstree-last"); }); - } - } - }, 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'); - if(this._data.search.smc) { - data.nodes.children(".jstree-children").find(".jstree-node").show(); + 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); + } } - data.nodes.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(); + this.show_node(p); } }, 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)); }; /** * used to search the tree nodes for a given string @@ -6596,13 +6934,13 @@ 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(m[inside ? inside : '#'].children_d, function (ii, i) { + $.each(m[inside ? inside : $.jstree.root].children_d, function (ii, i) { var v = m[i]; - 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)) ) { + 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) { @@ -6634,11 +6972,10 @@ * @name clear_search() * @plugin search * @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); } /** * triggered after search is complete @@ -6648,10 +6985,16 @@ * @param {String} str the search string (the last search string) * @param {Array} res a collection of objects represeing the matching nodes (the result from the last search) * @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 = $(); }; @@ -6663,20 +7006,39 @@ * @plugin search */ this._search_open = function (d) { var t = this; $.each(d.concat([]), function (i, v) { - if(v === "#") { return true; } + if(v === $.jstree.root) { 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; + }; }; // helpers (function ($) { // from http://kiro.me/projects/fuse.html @@ -6807,10 +7169,11 @@ }($)); // include the search plugin by default // $.jstree.defaults.plugins.push("search"); + /** * ### Sort plugin * * Automatically sorts all siblings in the tree according to a sorting function. */ @@ -6997,34 +7360,34 @@ * * @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]; } } } } } 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 .on('model.jstree', $.proxy(function (e, data) { var m = this._model.data, @@ -7042,11 +7405,11 @@ m[dpc[i]].type = c; if(m[dpc[i]].icon === true && t[c].icon !== undefined) { m[dpc[i]].icon = t[c].icon; } } - m['#'].type = '#'; + m[$.jstree.root].type = $.jstree.root; }, this)); parent.bind.call(this); }; this.get_json = function (obj, options, flat) { var i, j, @@ -7269,11 +7632,11 @@ return true; }; 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) { return parent.create_node.call(this, par, node, pos, callback, is_loaded); } @@ -7423,6 +7786,7 @@ try { document.registerElement("vakata-jstree", { prototype: proto }); } catch(ignore) { } } + return $.fn.jstree; })); \ No newline at end of file