vendor/assets/javascripts/jstree.js in jstree-rails-4-3.2.1 vs vendor/assets/javascripts/jstree.js in jstree-rails-4-3.3.3
- old
+ new
@@ -11,22 +11,23 @@
factory(jQuery);
}
}(function ($, undefined) {
"use strict";
/*!
- * jsTree 3.2.1
+ * jsTree 3.3.3
* http://jstree.com/
*
* Copyright (c) 2014 Ivan Bozhanov (http://vakata.com)
*
* Licensed same as jquery - under the terms of the MIT License
* http://www.opensource.org/licenses/mit-license.php
*/
/*!
* 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
+ * jslint: loopfunc: true, browser: true, ass: true, bitwise: true, continue: true, nomen: true, plusplus: true, regexp: true, unparam: true, todo: true, white: true
*/
+/*jshint -W083 */
// prevent another load? maybe there is a better way?
if($.jstree) {
return;
}
@@ -40,40 +41,22 @@
ccp_node = false,
ccp_mode = false,
ccp_inst = false,
themes_loaded = [],
src = $('script:last').attr('src'),
- document = window.document, // local variable is always faster to access then a global
- _node = document.createElement('LI'), _temp1, _temp2;
+ document = window.document; // local variable is always faster to access then a global
- _node.setAttribute('role', 'treeitem');
- _temp1 = document.createElement('I');
- _temp1.className = 'jstree-icon jstree-ocl';
- _temp1.setAttribute('role', 'presentation');
- _node.appendChild(_temp1);
- _temp1 = document.createElement('A');
- _temp1.className = 'jstree-anchor';
- _temp1.setAttribute('href','#');
- _temp1.setAttribute('tabindex','-1');
- _temp2 = document.createElement('I');
- _temp2.className = 'jstree-icon jstree-themeicon';
- _temp2.setAttribute('role', 'presentation');
- _temp1.appendChild(_temp2);
- _node.appendChild(_temp1);
- _temp1 = _temp2 = null;
-
-
/**
* holds all jstree related functions and variables, including the actual class and methods to create, access and manipulate instances.
* @name $.jstree
*/
$.jstree = {
/**
* specifies the jstree version in use
* @name $.jstree.version
*/
- version : '3.2.1',
+ version : '3.3.3',
/**
* holds all the default options used when creating new instances
* @name $.jstree.defaults
*/
defaults : {
@@ -90,10 +73,11 @@
plugins : {},
path : src && src.indexOf('/') !== -1 ? src.replace(/\/[^\/]+$/,'') : '',
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
* @param {Object} options options for this instance (extends `$.jstree.defaults`)
@@ -136,11 +120,12 @@
this._data = {
core : {
themes : {
name : false,
dots : false,
- icons : false
+ icons : false,
+ ellipsis : false
},
selected : [],
last_error : {},
working : false,
worker_queue : [],
@@ -258,11 +243,11 @@
* });
*
* @name $(':jstree')
* @return {jQuery}
*/
- $.expr[':'].jstree = $.expr.createPseudo(function(search) {
+ $.expr.pseudos.jstree = $.expr.createPseudo(function(search) {
return function(a) {
return $(a).hasClass('jstree') &&
$(a).data('jstree') !== undefined;
};
});
@@ -307,11 +292,12 @@
* 'text' : 'Root node with options',
* 'state' : { 'opened' : true, 'selected' : true },
* 'children' : [ { 'text' : 'Child 1' }, 'Child 2']
* }
* ]
- * });
+ * }
+ * });
*
* // function
* $('#tree').jstree({
* 'core' : {
* 'data' : function (obj, callback) {
@@ -406,10 +392,15 @@
* a boolean indicating if node icons are shown
* @name $.jstree.defaults.core.themes.icons
*/
icons : true,
/**
+ * a boolean indicating if node ellipsis should be shown - this only works with a fixed with on the container
+ * @name $.jstree.defaults.core.themes.ellipsis
+ */
+ ellipsis : false,
+ /**
* a boolean indicating if the tree background is striped
* @name $.jstree.defaults.core.themes.stripes
*/
stripes : false,
/**
@@ -523,10 +514,11 @@
})
.remove();
this.element.html("<"+"ul class='jstree-container-ul jstree-children' role='group'><"+"li id='j"+this._id+"_loading' class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='tree-item'><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._data.core.li_height = this.get_container_ul().children("li").first().height() || 24;
+ this._data.core.node = this._create_prototype_node();
/**
* triggered after the loading text is shown and before loading starts
* @event
* @name loading.jstree
*/
@@ -548,10 +540,33 @@
}
if(!keep_html) { this.element.empty(); }
this.teardown();
},
/**
+ * Create prototype node
+ */
+ _create_prototype_node : function () {
+ var _node = document.createElement('LI'), _temp1, _temp2;
+ _node.setAttribute('role', 'treeitem');
+ _temp1 = document.createElement('I');
+ _temp1.className = 'jstree-icon jstree-ocl';
+ _temp1.setAttribute('role', 'presentation');
+ _node.appendChild(_temp1);
+ _temp1 = document.createElement('A');
+ _temp1.className = 'jstree-anchor';
+ _temp1.setAttribute('href','#');
+ _temp1.setAttribute('tabindex','-1');
+ _temp2 = document.createElement('I');
+ _temp2.className = 'jstree-icon jstree-themeicon';
+ _temp2.setAttribute('role', 'presentation');
+ _temp1.appendChild(_temp2);
+ _node.appendChild(_temp1);
+ _temp1 = _temp2 = null;
+
+ return _node;
+ },
+ /**
* part of the destroying of an instance. Used internally.
* @private
* @name teardown()
*/
teardown : function () {
@@ -629,11 +644,11 @@
break;
case 13: // enter
e.type = "click";
$(e.currentTarget).trigger(e);
break;
- case 37: // right
+ case 37: // left
e.preventDefault();
if(this.is_open(e.currentTarget)) {
this.close_node(e.currentTarget);
}
else {
@@ -644,11 +659,11 @@
case 38: // up
e.preventDefault();
o = this.get_prev_dom(e.currentTarget);
if(o && o.length) { o.children('.jstree-anchor').focus(); }
break;
- case 39: // left
+ case 39: // right
e.preventDefault();
if(this.is_closed(e.currentTarget)) {
this.open_node(e.currentTarget, function (o) { this.get_node(o, true).children('.jstree-anchor').focus(); });
}
else if (this.is_open(e.currentTarget)) {
@@ -671,31 +686,27 @@
break;
case 35: // end
e.preventDefault();
this.element.find('.jstree-anchor').filter(':visible').last().focus();
break;
+ case 113: // f2 - safe to include - if check_callback is false it will fail
+ e.preventDefault();
+ this.edit(e.currentTarget);
+ break;
+ default:
+ break;
/*!
// delete
case 46:
e.preventDefault();
o = this.get_node(e.currentTarget);
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 !== $.jstree.root) {
- // this.edit(o);
- }
- break;
- default:
- // console.log(e.which);
- break;
+
*/
}
}, this))
.on("load_node.jstree", $.proxy(function (e, data) {
if(data.status) {
@@ -801,17 +812,19 @@
.on("init.jstree", $.proxy(function () {
var s = this.settings.core.themes;
this._data.core.themes.dots = s.dots;
this._data.core.themes.stripes = s.stripes;
this._data.core.themes.icons = s.icons;
+ this._data.core.themes.ellipsis = s.ellipsis;
this.set_theme(s.name || "default", s.url);
this.set_theme_variant(s.variant);
}, this))
.on("loading.jstree", $.proxy(function () {
this[ this._data.core.themes.dots ? "show_dots" : "hide_dots" ]();
this[ this._data.core.themes.icons ? "show_icons" : "hide_icons" ]();
this[ this._data.core.themes.stripes ? "show_stripes" : "hide_stripes" ]();
+ this[ this._data.core.themes.ellipsis ? "show_ellipsis" : "hide_ellipsis" ]();
}, this))
.on('blur.jstree', '.jstree-anchor', $.proxy(function (e) {
this._data.core.focused = null;
$(e.currentTarget).filter('.jstree-hovered').mouseleave();
this.element.attr('tabindex', '0');
@@ -1189,20 +1202,26 @@
return false;
}
// if(obj.state.loading) { } // the node is already loading - just wait for it to load and invoke callback? but if called implicitly it should be loaded again?
if(obj.state.loaded) {
obj.state.loaded = false;
+ for(i = 0, j = obj.parents.length; i < j; i++) {
+ this._model.data[obj.parents[i]].children_d = $.vakata.array_filter(this._model.data[obj.parents[i]].children_d, function (v) {
+ return $.inArray(v, obj.children_d) === -1;
+ });
+ }
for(k = 0, l = obj.children_d.length; k < l; k++) {
- for(i = 0, j = obj.parents.length; i < j; i++) {
- this._model.data[obj.parents[i]].children_d = $.vakata.array_remove_item(this._model.data[obj.parents[i]].children_d, obj.children_d[k]);
- }
if(this._model.data[obj.children_d[k]].state.selected) {
c = true;
- this._data.core.selected = $.vakata.array_remove_item(this._data.core.selected, obj.children_d[k]);
}
delete this._model.data[obj.children_d[k]];
}
+ if (c) {
+ this._data.core.selected = $.vakata.array_filter(this._data.core.selected, function (v) {
+ return $.inArray(v, obj.children_d) === -1;
+ });
+ }
obj.children = [];
obj.children_d = [];
if(c) {
this.trigger('changed', { 'action' : 'load_node', 'node' : obj, 'selected' : this._data.core.selected });
}
@@ -1220,12 +1239,20 @@
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');
+ if(obj.state.loaded && dom && dom.length) {
+ dom.removeClass('jstree-closed jstree-open jstree-leaf');
+ if (!has_children) {
+ dom.addClass('jstree-leaf');
+ }
+ else {
+ if (obj.id !== '#') {
+ dom.addClass(obj.state.opened ? 'jstree-open' : 'jstree-closed');
+ }
+ }
}
dom.removeClass("jstree-loading").attr('aria-busy',false);
/**
* triggered after a node is loaded
* @event
@@ -1245,16 +1272,16 @@
* @private
* @name _load_nodes(nodes [, callback])
* @param {array} nodes
* @param {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives one argument - the array passed to _load_nodes
*/
- _load_nodes : function (nodes, callback, is_callback) {
+ _load_nodes : function (nodes, callback, is_callback, force_reload) {
var r = true,
c = function () { this._load_nodes(nodes, callback, true); },
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 && !m[nodes[i]].state.failed) || !is_callback)) {
+ if(m[nodes[i]] && ( (!m[nodes[i]].state.loaded && !m[nodes[i]].state.failed) || (!is_callback && force_reload) )) {
if(!this.is_loading(nodes[i])) {
this.load_node(nodes[i], c);
}
r = false;
}
@@ -1318,10 +1345,13 @@
* @param {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives one argument - a boolean status
* @return {Boolean}
*/
_load_node : function (obj, callback) {
var s = this.settings.core.data, t;
+ var notTextOrCommentNode = function notTextOrCommentNode () {
+ return this.nodeType !== 3 && this.nodeType !== 8;
+ };
// use original HTML
if(!s) {
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);
@@ -1335,13 +1365,15 @@
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' ? $($.parseHTML(d)).filter(function () { return this.nodeType !== 3; }) : d, function (status) {
- callback.call(this, status);
- });
+ else {
+ this[typeof d === 'string' ? '_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $($.parseHTML(d)).filter(notTextOrCommentNode) : 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));
}, this));
}
if(typeof s === 'object') {
if(s.url) {
@@ -1358,11 +1390,11 @@
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 && 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 this._append_html_data(obj, $($.parseHTML(d)).filter(notTextOrCommentNode), 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 }) };
this.settings.core.error.call(this, this._data.core.last_error);
return callback.call(this, false);
@@ -1386,11 +1418,11 @@
}
//return callback.call(this, (obj.id === $.jstree.root ? this._append_json_data(obj, t) : false) );
}
if(typeof s === 'string') {
if(obj.id === $.jstree.root) {
- return this._append_html_data(obj, $($.parseHTML(s)).filter(function () { return this.nodeType !== 3; }), function (status) {
+ return this._append_html_data(obj, $($.parseHTML(s)).filter(notTextOrCommentNode), 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 }) };
@@ -1773,14 +1805,21 @@
}
},
rslt = function (rslt, worker) {
if(this.element === null) { return; }
this._cnt = rslt.cnt;
+ var i, m = this._model.data;
+ for (i in m) {
+ if (m.hasOwnProperty(i) && m[i].state && m[i].state.loading && rslt.mod[i]) {
+ rslt.mod[i].state.loading = true;
+ }
+ }
this._model.data = rslt.mod; // breaks the reference in load_node - careful
if(worker) {
- var i, j, a = rslt.add, r = rslt.sel, s = this._data.core.selected.slice(), m = this._model.data;
+ var j, a = rslt.add, r = rslt.sel, s = this._data.core.selected.slice();
+ m = this._model.data;
// if selection was changed while calculating in worker
if(r.length !== s.length || $.vakata.array_unique(r.concat(s)).length !== r.length) {
// deselect nodes that are no longer selected
for(i = 0, j = r.length; i < j; i++) {
if($.inArray(r[i], a) === -1 && $.inArray(r[i], s) === -1) {
@@ -2332,11 +2371,11 @@
f = node.children('.jstree-anchor')[0] === document.activeElement;
node.remove();
//node = d.createElement('LI');
//node = node[0];
}
- node = _node.cloneNode(true);
+ node = this._data.core.node.cloneNode(true);
// node is DOM, deep is boolean
c = 'jstree-node ';
for(i in obj.li_attr) {
if(obj.li_attr.hasOwnProperty(i)) {
@@ -2417,11 +2456,11 @@
}
else if(obj.icon.indexOf('/') === -1 && obj.icon.indexOf('.') === -1) {
node.childNodes[1].childNodes[0].className += ' ' + obj.icon + ' jstree-themeicon-custom';
}
else {
- node.childNodes[1].childNodes[0].style.backgroundImage = 'url('+obj.icon+')';
+ node.childNodes[1].childNodes[0].style.backgroundImage = 'url("'+obj.icon+'")';
node.childNodes[1].childNodes[0].style.backgroundPosition = 'center center';
node.childNodes[1].childNodes[0].style.backgroundSize = 'auto';
node.childNodes[1].childNodes[0].className += ' jstree-themeicon-custom';
}
}
@@ -2547,11 +2586,13 @@
.children(".jstree-children").css("display","none").end()
.removeClass("jstree-closed").addClass("jstree-open").attr("aria-expanded", true)
.children(".jstree-children").stop(true, true)
.slideDown(animation, function () {
this.style.display = "";
- t.trigger("after_open", { "node" : obj });
+ if (t.element) {
+ t.trigger("after_open", { "node" : obj });
+ }
});
}
}
obj.state.opened = true;
if(callback) {
@@ -2628,43 +2669,47 @@
return false;
}
animation = animation === undefined ? this.settings.core.animation : animation;
t = this;
d = this.get_node(obj, true);
- if(d.length) {
- if(!animation) {
- d[0].className = d[0].className.replace('jstree-open', 'jstree-closed');
- d.attr("aria-expanded", false).children('.jstree-children').remove();
- }
- else {
- d
- .children(".jstree-children").attr("style","display:block !important").end()
- .removeClass("jstree-open").addClass("jstree-closed").attr("aria-expanded", false)
- .children(".jstree-children").stop(true, true).slideUp(animation, function () {
- this.style.display = "";
- d.children('.jstree-children').remove();
- t.trigger("after_close", { "node" : obj });
- });
- }
- }
+
obj.state.opened = false;
/**
* triggered when a node is closed (if there is an animation it will not be complete yet)
* @event
* @name close_node.jstree
* @param {Object} node the closed node
*/
this.trigger('close_node',{ "node" : obj });
- if(!animation || !d.length) {
+ if(!d.length) {
/**
* triggered when a node is closed and the animation is complete
* @event
* @name after_close.jstree
* @param {Object} node the closed node
*/
this.trigger("after_close", { "node" : obj });
}
+ else {
+ if(!animation) {
+ d[0].className = d[0].className.replace('jstree-open', 'jstree-closed');
+ d.attr("aria-expanded", false).children('.jstree-children').remove();
+ this.trigger("after_close", { "node" : obj });
+ }
+ else {
+ d
+ .children(".jstree-children").attr("style","display:block !important").end()
+ .removeClass("jstree-open").addClass("jstree-closed").attr("aria-expanded", false)
+ .children(".jstree-children").stop(true, true).slideUp(animation, function () {
+ this.style.display = "";
+ d.children('.jstree-children').remove();
+ if (t.element) {
+ t.trigger("after_close", { "node" : obj });
+ }
+ });
+ }
+ }
},
/**
* toggles a node - closing it if it is open, opening it if it is closed
* @name toggle_node(obj)
* @param {mixed} obj the node to toggle
@@ -2821,24 +2866,35 @@
* @param {Object} node the disabled node
*/
this.trigger('disable_node', { 'node' : obj });
},
/**
+ * determines if a node is hidden
+ * @name is_hidden(obj)
+ * @param {mixed} obj the node
+ */
+ is_hidden : function (obj) {
+ obj = this.get_node(obj);
+ return obj.state.hidden === true;
+ },
+ /**
* 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
+ * @param {Boolean} skip_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();
+ if (!skip_redraw) {
+ this.redraw();
+ }
return true;
}
obj = this.get_node(obj);
if(!obj || obj.id === $.jstree.root) {
return false;
@@ -2870,11 +2926,13 @@
if($.isArray(obj)) {
obj = obj.slice();
for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
this.show_node(obj[t1], true);
}
- this.redraw();
+ if (!skip_redraw) {
+ this.redraw();
+ }
return true;
}
obj = this.get_node(obj);
if(!obj || obj.id === $.jstree.root) {
return false;
@@ -2991,11 +3049,13 @@
}
if(p[i] === l) {
c = !c;
}
if(!this.is_disabled(p[i]) && (c || p[i] === o || p[i] === l)) {
- this.select_node(p[i], true, false, e);
+ if (!this.is_hidden(p[i])) {
+ this.select_node(p[i], true, false, e);
+ }
}
else {
this.deselect_node(p[i], true, e);
}
}
@@ -3336,11 +3396,11 @@
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;
}
if(state.core.scroll) {
if(state.core.scroll && state.core.scroll.left !== undefined) {
@@ -3446,35 +3506,36 @@
obj = this.get_node(obj);
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.get_node(obj, true).find('.jstree-open').each(function() { to_load.push(this.id); opened.push(this.id); });
this._load_nodes(to_load, $.proxy(function (nodes) {
this.open_node(opened, false, 0);
- this.select_node(this._data.core.selected);
+ this.select_node(s);
/**
* triggered when a node is refreshed
* @event
* @name refresh_node.jstree
* @param {Object} node - the refreshed node
* @param {Array} nodes - an array of the IDs of the nodes that were reloaded
*/
this.trigger('refresh_node', { 'node' : obj, 'nodes' : nodes });
- }, this));
+ }, this), false, true);
},
/**
* set (change) the ID of a node
* @name set_id(obj, id)
* @param {mixed} obj the node
* @param {String} id the new ID
* @return {Boolean}
+ * @trigger set_id.jstree
*/
set_id : function (obj, id) {
obj = this.get_node(obj);
if(!obj || obj.id === $.jstree.root) { return false; }
- var i, j, m = this._model.data;
+ var i, j, m = this._model.data, old = obj.id;
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++) {
m[obj.parents[i]].children_d[$.inArray(obj.id, m[obj.parents[i]].children_d)] = id;
@@ -3489,19 +3550,27 @@
i = $.inArray(obj.id, this._data.core.selected);
if(i !== -1) { this._data.core.selected[i] = id; }
// update model and obj itself (obj.id, this._model.data[KEY])
i = this.get_node(obj.id, true);
if(i) {
- i.attr('id', id).children('.jstree-anchor').attr('id', id + '_anchor').end().attr('aria-labelledby', id + '_anchor');
+ 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;
+ /**
+ * triggered when a node id value is changed
+ * @event
+ * @name set_id.jstree
+ * @param {Object} node
+ * @param {String} old the old id
+ */
+ this.trigger('set_id',{ "node" : obj, "new" : obj.id, "old" : old });
return true;
},
/**
* get the text value of a node
* @name get_text(obj)
@@ -3553,10 +3622,12 @@
* @param {Object} options
* @param {Boolean} options.no_state do not return state information
* @param {Boolean} options.no_id do not return ID
* @param {Boolean} options.no_children do not include children
* @param {Boolean} options.no_data do not include node data
+ * @param {Boolean} options.no_li_attr do not include LI attributes
+ * @param {Boolean} options.no_a_attr do not include A attributes
* @param {Boolean} options.flat return flat JSON instead of nested
* @return {Object}
*/
get_json : function (obj, options, flat) {
obj = this.get_node(obj || $.jstree.root);
@@ -3582,11 +3653,19 @@
for(i in obj.state) {
if(obj.state.hasOwnProperty(i)) {
tmp.state[i] = obj.state[i];
}
}
+ } else {
+ delete tmp.state;
}
+ if(options && options.no_li_attr) {
+ delete tmp.li_attr;
+ }
+ if(options && options.no_a_attr) {
+ delete tmp.a_attr;
+ }
if(options && options.no_id) {
delete tmp.id;
if(tmp.li_attr && tmp.li_attr.id) {
delete tmp.li_attr.id;
}
@@ -3609,11 +3688,11 @@
}
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])
+ * @name create_node([par, node, pos, callback, is_loaded])
* @param {mixed} par the parent node (to create a root node use either "#" (string) or `null`)
* @param {mixed} node the data for the new node (a valid JSON object, or a simple string with the name)
* @param {mixed} pos the index at which to insert the node, "first" and "last" are also supported, default is "last"
* @param {Function} callback a function to be called once the node is created
* @param {Boolean} is_loaded internal argument indicating if the parent node was succesfully loaded
@@ -3763,25 +3842,26 @@
if(pos !== -1) {
par.children = $.vakata.array_remove(par.children, pos);
}
tmp = obj.children_d.concat([]);
tmp.push(obj.id);
+ for(i = 0, j = obj.parents.length; i < j; i++) {
+ this._model.data[obj.parents[i]].children_d = $.vakata.array_filter(this._model.data[obj.parents[i]].children_d, function (v) {
+ return $.inArray(v, tmp) === -1;
+ });
+ }
for(k = 0, l = tmp.length; k < l; k++) {
- for(i = 0, j = obj.parents.length; i < j; i++) {
- pos = $.inArray(tmp[k], this._model.data[obj.parents[i]].children_d);
- if(pos !== -1) {
- this._model.data[obj.parents[i]].children_d = $.vakata.array_remove(this._model.data[obj.parents[i]].children_d, pos);
- }
- }
if(this._model.data[tmp[k]].state.selected) {
c = true;
- pos = $.inArray(tmp[k], this._data.core.selected);
- if(pos !== -1) {
- this._data.core.selected = $.vakata.array_remove(this._data.core.selected, pos);
- }
+ break;
}
}
+ if (c) {
+ this._data.core.selected = $.vakata.array_filter(this._data.core.selected, function (v) {
+ return $.inArray(v, tmp) === -1;
+ });
+ }
/**
* triggered when a node is deleted
* @event
* @name delete_node.jstree
* @param {Object} node
@@ -3797,11 +3877,13 @@
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();
+ if (this._model.data[$.jstree.root].children[0]) {
+ 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;
@@ -3825,11 +3907,11 @@
obj = obj && obj.id ? obj : this.get_node(obj);
par = par && par.id ? par : this.get_node(par);
var tmp = chk.match(/^move_node|copy_node|create_node$/i) ? par : obj,
chc = this.settings.core.check_callback;
if(chk === "move_node" || chk === "copy_node") {
- if((!more || !more.is_multi) && (obj.id === par.id || $.inArray(obj.id, par.children) === pos || $.inArray(par.id, obj.children_d) !== -1)) {
+ if((!more || !more.is_multi) && (obj.id === par.id || (chk === "move_node" && $.inArray(obj.id, par.children) === pos) || $.inArray(par.id, obj.children_d) !== -1)) {
this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_01', 'reason' : 'Moving parent inside child', 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
return false;
}
}
if(tmp && tmp.data) { tmp = tmp.data; }
@@ -4340,10 +4422,11 @@
}
}, this), 0);
if(callback) {
callback.call(this, tmp, nv, cancel);
}
+ h2 = null;
}, this),
"keydown" : function (e) {
var key = e.which;
if(key === 27) {
cancel = true;
@@ -4378,10 +4461,15 @@
};
s.attr('class', a.attr('class')).append(a.contents().clone()).append(h2);
a.replaceWith(s);
h1.css(fn);
h2.css(fn).width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select();
+ $(document).one('mousedown.jstree touchstart.jstree dnd_start.vakata', function (e) {
+ if (h2 && e.target !== h2) {
+ $(h2).blur();
+ }
+ });
},
/**
* changes the theme
@@ -4443,52 +4531,139 @@
get_theme_variant : function () { return this._data.core.themes.variant; },
/**
* shows a striped background on the container (if the theme supports it)
* @name show_stripes()
*/
- show_stripes : function () { this._data.core.themes.stripes = true; this.get_container_ul().addClass("jstree-striped"); },
+ show_stripes : function () {
+ this._data.core.themes.stripes = true;
+ this.get_container_ul().addClass("jstree-striped");
+ /**
+ * triggered when stripes are shown
+ * @event
+ * @name show_stripes.jstree
+ */
+ this.trigger('show_stripes');
+ },
/**
* hides the striped background on the container
* @name hide_stripes()
*/
- hide_stripes : function () { this._data.core.themes.stripes = false; this.get_container_ul().removeClass("jstree-striped"); },
+ hide_stripes : function () {
+ this._data.core.themes.stripes = false;
+ this.get_container_ul().removeClass("jstree-striped");
+ /**
+ * triggered when stripes are hidden
+ * @event
+ * @name hide_stripes.jstree
+ */
+ this.trigger('hide_stripes');
+ },
/**
* toggles the striped background on the container
* @name toggle_stripes()
*/
toggle_stripes : function () { if(this._data.core.themes.stripes) { this.hide_stripes(); } else { this.show_stripes(); } },
/**
* shows the connecting dots (if the theme supports it)
* @name show_dots()
*/
- show_dots : function () { this._data.core.themes.dots = true; this.get_container_ul().removeClass("jstree-no-dots"); },
+ show_dots : function () {
+ this._data.core.themes.dots = true;
+ this.get_container_ul().removeClass("jstree-no-dots");
+ /**
+ * triggered when dots are shown
+ * @event
+ * @name show_dots.jstree
+ */
+ this.trigger('show_dots');
+ },
/**
* hides the connecting dots
* @name hide_dots()
*/
- hide_dots : function () { this._data.core.themes.dots = false; this.get_container_ul().addClass("jstree-no-dots"); },
+ hide_dots : function () {
+ this._data.core.themes.dots = false;
+ this.get_container_ul().addClass("jstree-no-dots");
+ /**
+ * triggered when dots are hidden
+ * @event
+ * @name hide_dots.jstree
+ */
+ this.trigger('hide_dots');
+ },
/**
* toggles the connecting dots
* @name toggle_dots()
*/
toggle_dots : function () { if(this._data.core.themes.dots) { this.hide_dots(); } else { this.show_dots(); } },
/**
* show the node icons
* @name show_icons()
*/
- show_icons : function () { this._data.core.themes.icons = true; this.get_container_ul().removeClass("jstree-no-icons"); },
+ show_icons : function () {
+ this._data.core.themes.icons = true;
+ this.get_container_ul().removeClass("jstree-no-icons");
+ /**
+ * triggered when icons are shown
+ * @event
+ * @name show_icons.jstree
+ */
+ this.trigger('show_icons');
+ },
/**
* hide the node icons
* @name hide_icons()
*/
- hide_icons : function () { this._data.core.themes.icons = false; this.get_container_ul().addClass("jstree-no-icons"); },
+ hide_icons : function () {
+ this._data.core.themes.icons = false;
+ this.get_container_ul().addClass("jstree-no-icons");
+ /**
+ * triggered when icons are hidden
+ * @event
+ * @name hide_icons.jstree
+ */
+ this.trigger('hide_icons');
+ },
/**
* toggle the node icons
* @name toggle_icons()
*/
toggle_icons : function () { if(this._data.core.themes.icons) { this.hide_icons(); } else { this.show_icons(); } },
/**
+ * show the node ellipsis
+ * @name show_icons()
+ */
+ show_ellipsis : function () {
+ this._data.core.themes.ellipsis = true;
+ this.get_container_ul().addClass("jstree-ellipsis");
+ /**
+ * triggered when ellisis is shown
+ * @event
+ * @name show_ellipsis.jstree
+ */
+ this.trigger('show_ellipsis');
+ },
+ /**
+ * hide the node ellipsis
+ * @name hide_ellipsis()
+ */
+ hide_ellipsis : function () {
+ this._data.core.themes.ellipsis = false;
+ this.get_container_ul().removeClass("jstree-ellipsis");
+ /**
+ * triggered when ellisis is hidden
+ * @event
+ * @name hide_ellipsis.jstree
+ */
+ this.trigger('hide_ellipsis');
+ },
+ /**
+ * toggle the node ellipsis
+ * @name toggle_icons()
+ */
+ toggle_ellipsis : function () { if(this._data.core.themes.ellipsis) { this.hide_ellipsis(); } else { this.show_ellipsis(); } },
+ /**
* set the node icon for a node
* @name set_icon(obj, icon)
* @param {mixed} obj
* @param {String} icon the new icon - 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
*/
@@ -4605,21 +4780,35 @@
}
}
return a;
};
// remove item from array
- $.vakata.array_remove = function(array, from, to) {
- var rest = array.slice((to || from) + 1 || array.length);
- array.length = from < 0 ? array.length + from : from;
- array.push.apply(array, rest);
+ $.vakata.array_remove = function(array, from) {
+ array.splice(from, 1);
return array;
+ //var rest = array.slice((to || from) + 1 || array.length);
+ //array.length = from < 0 ? array.length + from : from;
+ //array.push.apply(array, rest);
+ //return array;
};
// remove item from array
$.vakata.array_remove_item = function(array, item) {
var tmp = $.inArray(item, array);
return tmp !== -1 ? $.vakata.array_remove(array, tmp) : array;
};
+ $.vakata.array_filter = function(c,a,b,d,e) {
+ if (c.filter) {
+ return c.filter(a, b);
+ }
+ d=[];
+ for (e in c) {
+ if (~~e+''===e+'' && e>=0 && a.call(b,c[e],+e,c)) {
+ d.push(c[e]);
+ }
+ }
+ return d;
+ };
/**
* ### Changed plugin
*
@@ -4837,16 +5026,21 @@
.on(this.settings.checkbox.tie_selection ? 'select_node.jstree' : 'check_node.jstree', $.proxy(function (e, data) {
var obj = data.node,
m = this._model.data,
par = this.get_node(obj.parent),
dom = this.get_node(obj, true),
- i, j, c, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection;
+ i, j, c, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection,
+ sel = {}, cur = this._data[ t ? 'core' : 'checkbox' ].selected;
+ for (i = 0, j = cur.length; i < j; i++) {
+ sel[cur[i]] = true;
+ }
// apply down
if(s.indexOf('down') !== -1) {
- this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected.concat(obj.children_d));
+ //this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected.concat(obj.children_d));
for(i = 0, j = obj.children_d.length; i < j; i++) {
+ sel[obj.children_d[i]] = true;
tmp = m[obj.children_d[i]];
tmp.state[ t ? 'selected' : 'checked' ] = true;
if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {
tmp.original.state.undetermined = false;
}
@@ -4860,11 +5054,12 @@
for(i = 0, j = par.children.length; i < j; i++) {
c += m[par.children[i]].state[ t ? 'selected' : 'checked' ];
}
if(c === j) {
par.state[ t ? 'selected' : 'checked' ] = true;
- this._data[ t ? 'core' : 'checkbox' ].selected.push(par.id);
+ sel[par.id] = true;
+ //this._data[ t ? 'core' : 'checkbox' ].selected.push(par.id);
tmp = this.get_node(par, true);
if(tmp && tmp.length) {
tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
}
}
@@ -4873,10 +5068,18 @@
}
par = this.get_node(par.parent);
}
}
+ cur = [];
+ for (i in sel) {
+ if (sel.hasOwnProperty(i)) {
+ cur.push(i);
+ }
+ }
+ this._data[ t ? 'core' : 'checkbox' ].selected = cur;
+
// apply down (process .children separately?)
if(s.indexOf('down') !== -1 && dom.length) {
dom.find('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked').parent().attr('aria-selected', true);
}
}, this))
@@ -4892,11 +5095,12 @@
}
}, this))
.on(this.settings.checkbox.tie_selection ? 'deselect_node.jstree' : 'uncheck_node.jstree', $.proxy(function (e, data) {
var obj = data.node,
dom = this.get_node(obj, true),
- i, j, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection;
+ i, j, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection,
+ cur = this._data[ t ? 'core' : 'checkbox' ].selected, sel = {};
if(obj && obj.original && obj.original.state && obj.original.state.undetermined) {
obj.original.state.undetermined = false;
}
// apply down
@@ -4922,22 +5126,28 @@
if(tmp && tmp.length) {
tmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
}
}
}
- tmp = [];
- for(i = 0, j = this._data[ t ? 'core' : 'checkbox' ].selected.length; i < j; i++) {
+ sel = {};
+ for(i = 0, j = cur.length; i < j; i++) {
// apply down + apply up
if(
- (s.indexOf('down') === -1 || $.inArray(this._data[ t ? 'core' : 'checkbox' ].selected[i], obj.children_d) === -1) &&
- (s.indexOf('up') === -1 || $.inArray(this._data[ t ? 'core' : 'checkbox' ].selected[i], obj.parents) === -1)
+ (s.indexOf('down') === -1 || $.inArray(cur[i], obj.children_d) === -1) &&
+ (s.indexOf('up') === -1 || $.inArray(cur[i], obj.parents) === -1)
) {
- tmp.push(this._data[ t ? 'core' : 'checkbox' ].selected[i]);
+ sel[cur[i]] = true;
}
}
- this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(tmp);
-
+ cur = [];
+ for (i in sel) {
+ if (sel.hasOwnProperty(i)) {
+ cur.push(i);
+ }
+ }
+ this._data[ t ? 'core' : 'checkbox' ].selected = cur;
+
// apply down (process .children separately?)
if(s.indexOf('down') !== -1 && dom.length) {
dom.find('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked').parent().attr('aria-selected', false);
}
}, this));
@@ -5040,11 +5250,14 @@
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] !== $.jstree.root) {
+ if(o[m[s[i]].parents[k]] !== undefined) {
+ break;
+ }
+ if(m[s[i]].parents[k] !== $.jstree.root) {
o[m[s[i]].parents[k]] = true;
p.push(m[s[i]].parents[k]);
}
}
}
@@ -5551,20 +5764,22 @@
*/
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):
+ * 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). Once a menu item is activated the `action` function will be invoked with an object containing the following keys: item - the contextmenu item definition as seen below, reference - the DOM node that was used (the tree node), element - the contextmenu DOM element, position - an object with x/y properties indicating the position of the menu.
*
* * `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
* * `label` - a string - the name of the action (could be a function returning a string)
- * * `action` - a function to be executed if this item is chosen
+ * * `title` - a string - an optional tooltip for the item
+ * * `action` - a function to be executed if this item is chosen, the function will receive
* * `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)
+ * * `submenu` - an object with the same structure as $.jstree.defaults.contextmenu.items which can be used to create a submenu - each key will be rendered as a separate option in a submenu that will appear once the current item is hovered
*
* @name $.jstree.defaults.contextmenu.items
* @plugin contextmenu
*/
items : function (o, cb) { // Could be an object directly
@@ -5678,10 +5893,13 @@
parent.bind.call(this);
var last_ts = 0, cto = null, ex, ey;
this.element
.on("contextmenu.jstree", ".jstree-anchor", $.proxy(function (e, data) {
+ if (e.target.tagName.toLowerCase() === 'input') {
+ return;
+ }
e.preventDefault();
last_ts = e.ctrlKey ? +new Date() : 0;
if(data || cto) {
last_ts = (+new Date()) + 10000;
}
@@ -5700,18 +5918,18 @@
}, 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;
+ ex = e.originalEvent.changedTouches[0].clientX;
+ ey = e.originalEvent.changedTouches[0].clientY;
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)) {
+ if(cto && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0] && (Math.abs(ex - e.originalEvent.changedTouches[0].clientX) > 50 || Math.abs(ey - e.originalEvent.changedTouches[0].clientY) > 50)) {
clearTimeout(cto);
}
})
.on('touchend.vakata.jstree', function (e) {
if(cto) {
@@ -5738,11 +5956,14 @@
tm = null;
});
});
}
*/
- $(document).on("context_hide.vakata.jstree", $.proxy(function () { this._data.contextmenu.visible = false; }, this));
+ $(document).on("context_hide.vakata.jstree", $.proxy(function (e, data) {
+ this._data.contextmenu.visible = false;
+ $(data.reference).removeClass('jstree-context');
+ }, this));
};
this.teardown = function () {
if(this._data.contextmenu.visible) {
$.vakata.context.hide();
}
@@ -5801,10 +6022,11 @@
var d = this.get_node(obj, true),
a = d.children(".jstree-anchor");
$(document).one("context_show.vakata.jstree", $.proxy(function (e, data) {
var cls = 'jstree-contextmenu jstree-' + this.get_theme() + '-contextmenu';
$(data.element).addClass(cls);
+ a.addClass('jstree-context');
}, this));
this._data.contextmenu.visible = true;
$.vakata.context.show(a, { 'x' : x, 'y' : y }, i);
/**
* triggered when the contextmenu is shown for a node
@@ -5876,11 +6098,11 @@
if(!sep && val.separator_before) {
str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + "> <"+"/a><"+"/li>";
}
sep = false;
str += "<"+"li class='" + (val._class || "") + (val._disabled === true || ($.isFunction(val._disabled) && val._disabled({ "item" : val, "reference" : vakata_context.reference, "element" : vakata_context.element })) ? " vakata-contextmenu-disabled " : "") + "' "+(val.shortcut?" data-shortcut='"+val.shortcut+"' ":'')+">";
- str += "<"+"a href='#' rel='" + (vakata_context.items.length - 1) + "'>";
+ str += "<"+"a href='#' rel='" + (vakata_context.items.length - 1) + "' " + (val.title ? "title='" + val.title + "'" : "") + ">";
if($.vakata.context.settings.icons) {
str += "<"+"i ";
if(val.icon) {
if(val.icon.indexOf("/") !== -1 || val.icon.indexOf(".") !== -1) { str += " style='background:url(\"" + val.icon + "\") center center no-repeat' "; }
else { str += " class='" + val.icon + "' "; }
@@ -5914,26 +6136,39 @@
},
_show_submenu : function (o) {
o = $(o);
if(!o.length || !o.children("ul").length) { return; }
var e = o.children("ul"),
- x = o.offset().left + o.outerWidth(),
+ xl = o.offset().left,
+ x = xl + o.outerWidth(),
y = o.offset().top,
w = e.width(),
h = e.height(),
dw = $(window).width() + $(window).scrollLeft(),
dh = $(window).height() + $(window).scrollTop();
// може да се спести е една проверка - дали няма някой от класовете вече нагоре
if(right_to_left) {
o[x - (w + 10 + o.outerWidth()) < 0 ? "addClass" : "removeClass"]("vakata-context-left");
}
else {
- o[x + w + 10 > dw ? "addClass" : "removeClass"]("vakata-context-right");
+ o[x + w > dw && xl > dw - x ? "addClass" : "removeClass"]("vakata-context-right");
}
if(y + h + 10 > dh) {
e.css("bottom","-1px");
}
+
+ //if does not fit - stick it to the side
+ if (o.hasClass('vakata-context-right')) {
+ if (xl < w) {
+ e.css("margin-right", xl - w);
+ }
+ } else {
+ if (dw - x < w) {
+ e.css("margin-left", dw - x - w);
+ }
+ }
+
e.show();
},
show : function (reference, position, data) {
var o, e, x, y, w, h, dw, dh, cond = true;
if(vakata_context.element && vakata_context.element.length) {
@@ -6068,11 +6303,11 @@
.on('keydown', 'a', function (e) {
var o = null;
switch(e.which) {
case 13:
case 32:
- e.type = "mouseup";
+ e.type = "click";
e.preventDefault();
$(e.currentTarget).trigger(e);
break;
case 37:
if(vakata_context.is_visible) {
@@ -6139,10 +6374,11 @@
});
});
}($));
// $.jstree.defaults.plugins.push("contextmenu");
+
/**
* ### Drag'n'drop plugin
*
* Enables dragging and dropping of nodes in the tree, resulting in a move or copy operations.
*/
@@ -6210,38 +6446,94 @@
/**
* 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
+ large_drag_target : false,
+ /**
+ * controls whether use HTML5 dnd api instead of classical. That will allow better integration of dnd events with other HTML5 controls.
+ * @reference http://caniuse.com/#feat=dragndrop
+ * @name $.jstree.defaults.dnd.use_html5
+ * @plugin dnd
+ */
+ use_html5: false
};
+ var drg, elm;
// TODO: now check works by checking for each node individually, how about max_children, unique, etc?
$.jstree.plugins.dnd = function (options, parent) {
+ this.init = function (el, options) {
+ parent.init.call(this, el, options);
+ this.settings.dnd.use_html5 = this.settings.dnd.use_html5 && ('draggable' in document.createElement('span'));
+ };
this.bind = function () {
parent.bind.call(this);
this.element
- .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;
+ .on(this.settings.dnd.use_html5 ? 'dragstart.jstree' : '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.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" || e.type === "dragstart") &&
+ (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)))
+ ) {
+ drg = { 'jstree' : true, 'origin' : this, 'obj' : this.get_node(obj,true), 'nodes' : mlt > 1 ? this.get_top_selected() : [obj.id] };
+ elm = e.currentTarget;
+ if (this.settings.dnd.use_html5) {
+ $.vakata.dnd._trigger('start', e, { 'helper': $(), 'element': elm, 'data': drg });
+ } else {
+ this.element.trigger('mousedown.jstree');
+ return $.vakata.dnd.start(e, drg, '<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));
+ if (this.settings.dnd.use_html5) {
+ this.element
+ .on('dragover.jstree', function (e) {
+ e.preventDefault();
+ $.vakata.dnd._trigger('move', e, { 'helper': $(), 'element': elm, 'data': drg });
+ return false;
+ })
+ //.on('dragenter.jstree', this.settings.dnd.large_drop_target ? '.jstree-node' : '.jstree-anchor', $.proxy(function (e) {
+ // e.preventDefault();
+ // $.vakata.dnd._trigger('move', e, { 'helper': $(), 'element': elm, 'data': drg });
+ // return false;
+ // }, this))
+ .on('drop.jstree', $.proxy(function (e) {
+ e.preventDefault();
+ $.vakata.dnd._trigger('stop', e, { 'helper': $(), 'element': elm, 'data': drg });
+ return false;
+ }, this));
+ }
+ };
+ this.redraw_node = function(obj, deep, callback, force_render) {
+ obj = parent.redraw_node.apply(this, arguments);
+ if (obj && this.settings.dnd.use_html5) {
+ if (this.settings.dnd.large_drag_target) {
+ obj.setAttribute('draggable', true);
+ } else {
+ 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(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;
+ if(tmp) {
+ tmp.setAttribute('draggable', true);
}
- var obj = this.get_node(e.target),
- 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_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));
+ }
+ }
+ return obj;
};
};
$(function() {
// bind only once for all instances
@@ -6257,11 +6549,15 @@
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); }
+ if(opento) {
+ if (!data.event || data.event.type !== 'dragover' || data.event.target !== lastev.target) {
+ clearTimeout(opento);
+ }
+ }
if(!data || !data.data || !data.data.jstree) { return; }
// 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;
@@ -6270,39 +6566,43 @@
var ins = $.jstree.reference(data.event.target),
ref = false,
off = false,
rel = false,
- tmp, 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, is_copy, pn;
// 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' : '' ));
+ is_copy = data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey)));
data.helper
.children().attr('class', 'jstree-' + ins.get_theme() + ' jstree-' + ins.get_theme() + '-' + ins.get_theme_variant() + ' ' + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ))
- .find('.jstree-copy').first()[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? 'show' : 'hide' ]();
+ .find('.jstree-copy').first()[ is_copy ? 'show' : 'hide' ]();
-
// if are hovering the container itself add a new root node
+ //console.log(data.event);
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]), $.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' : $.jstree.root, 'pos' : 'last' };
marker.hide();
data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');
+ if (data.event.originalEvent && data.event.originalEvent.dataTransfer) {
+ data.event.originalEvent.dataTransfer.dropEffect = is_copy ? 'copy' : 'move';
+ }
return;
}
}
else {
// if we are hovering a tree node
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;
+ rel = (data.event.pageY !== undefined ? data.event.pageY : data.event.originalEvent.pageY) - off.top;
h = ref.outerHeight();
if(rel < h / 3) {
o = ['b', 'i', 'a'];
}
else if(rel > h - h / 3) {
@@ -6352,34 +6652,47 @@
}
if(v === 'i' && ref.parent().is('.jstree-closed') && ins.settings.dnd.open_timeout) {
opento = setTimeout((function (x, z) { return function () { x.open_node(z); }; }(ins, ref)), ins.settings.dnd.open_timeout);
}
if(ok) {
+ pn = ins.get_node(p, true);
+ if (!pn.hasClass('.jstree-dnd-parent')) {
+ $('.jstree-dnd-parent').removeClass('jstree-dnd-parent');
+ pn.addClass('jstree-dnd-parent');
+ }
lastmv = { 'ins' : ins, 'par' : p, 'pos' : v === 'i' && ip === 'last' && i === 0 && !ins.is_loaded(tm) ? 'last' : i };
marker.css({ 'left' : l + 'px', 'top' : t + 'px' }).show();
data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');
+ if (data.event.originalEvent && data.event.originalEvent.dataTransfer) {
+ data.event.originalEvent.dataTransfer.dropEffect = is_copy ? 'copy' : 'move';
+ }
laster = {};
o = true;
return false;
}
});
if(o === true) { return; }
}
}
}
+ $('.jstree-dnd-parent').removeClass('jstree-dnd-parent');
lastmv = false;
data.helper.find('.jstree-icon').removeClass('jstree-ok').addClass('jstree-er');
+ if (data.event.originalEvent && data.event.originalEvent.dataTransfer) {
+ data.event.originalEvent.dataTransfer.dropEffect = 'none';
+ }
marker.hide();
})
.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) {
+ $('.jstree-dnd-parent').removeClass('jstree-dnd-parent');
if(opento) { clearTimeout(opento); }
if(!data || !data.data || !data.data.jstree) { return; }
marker.hide().detach();
var i, j, nodes = [];
if(lastmv) {
@@ -6401,15 +6714,25 @@
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);
+ if (e.type === "keyup" && e.which === 27) {
+ if (opento) { clearTimeout(opento); }
+ lastmv = false;
+ laster = false;
+ lastev = false;
+ opento = false;
+ marker.hide().detach();
+ $.vakata.dnd._clean();
+ } else {
+ 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);
+ }
}
}
});
});
@@ -6448,12 +6771,14 @@
helper_left : 5,
helper_top : 10,
threshold : 5,
threshold_touch : 50
},
- _trigger : function (event_name, e) {
- var data = $.vakata.dnd._get();
+ _trigger : function (event_name, e, data) {
+ if (data === undefined) {
+ data = $.vakata.dnd._get();
+ }
data.event = e;
$(document).triggerHandler("dnd_" + event_name + ".vakata", data);
},
_get : function () {
return {
@@ -6521,11 +6846,15 @@
}
if(vakata_dnd.is_drag) { $.vakata.dnd.stop({}); }
try {
e.currentTarget.unselectable = "on";
e.currentTarget.onselectstart = function() { return false; };
- if(e.currentTarget.style) { e.currentTarget.style.MozUserSelect = "none"; }
+ if(e.currentTarget.style) {
+ e.currentTarget.style.touchAction = "none";
+ e.currentTarget.style.msTouchAction = "none";
+ e.currentTarget.style.MozUserSelect = "none";
+ }
} catch(ignore) { }
vakata_dnd.init_x = e.pageX;
vakata_dnd.init_y = e.pageY;
vakata_dnd.data = data;
vakata_dnd.is_down = true;
@@ -6562,10 +6891,11 @@
if(vakata_dnd.helper) {
vakata_dnd.helper.appendTo("body");
vakata_dnd.helper_w = vakata_dnd.helper.outerWidth();
}
vakata_dnd.is_drag = true;
+ $(vakata_dnd.target).one('click.vakata', false);
/**
* triggered on the document when a drag starts
* @event
* @plugin dnd
* @name dnd_start.vakata
@@ -6662,10 +6992,13 @@
* @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
* @param {DOM} element the DOM element being dragged
* @param {jQuery} helper the helper shown next to the mouse
* @param {Object} event the event that caused the stop
*/
+ if (e.target !== vakata_dnd.target) {
+ $(vakata_dnd.target).off('click.vakata');
+ }
$.vakata.dnd._trigger("stop", e);
}
else {
if(e.type === "touchend" && e.target === vakata_dnd.target) {
var to = setTimeout(function () { $(e.target).click(); }, 100);
@@ -6707,62 +7040,99 @@
* @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 = {};
+ parent.init.call(this, el, options);
};
- 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];
- }
+ this._load_nodes = function (nodes, callback, is_callback, force_reload) {
+ var s = this.settings.massload,
+ nodesString = JSON.stringify(nodes),
+ toLoad = [],
+ m = this._model.data,
+ i, j, dom;
+ if (!is_callback) {
+ for(i = 0, j = nodes.length; i < j; i++) {
+ if(!m[nodes[i]] || ( (!m[nodes[i]].state.loaded && !m[nodes[i]].state.failed) || force_reload) ) {
+ toLoad.push(nodes[i]);
+ dom = this.get_node(nodes[i], true);
+ if (dom && dom.length) {
+ dom.addClass("jstree-loading").attr('aria-busy',true);
}
}
- 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) {
+ this._data.massload = {};
+ if (toLoad.length) {
+ if($.isFunction(s)) {
+ return s.call(this, toLoad, $.proxy(function (data) {
+ var i, j;
if(data) {
- for(var i in data) {
+ for(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);
+ for(i = 0, j = nodes.length; i < j; i++) {
+ dom = this.get_node(nodes[i], true);
+ if (dom && dom.length) {
+ dom.removeClass("jstree-loading").attr('aria-busy',false);
+ }
+ }
+ parent._load_nodes.call(this, nodes, callback, is_callback, force_reload);
}, this));
+ }
+ if(typeof s === 'object' && s && s.url) {
+ s = $.extend(true, {}, s);
+ if($.isFunction(s.url)) {
+ s.url = s.url.call(this, toLoad);
+ }
+ if($.isFunction(s.data)) {
+ s.data = s.data.call(this, toLoad);
+ }
+ return $.ajax(s)
+ .done($.proxy(function (data,t,x) {
+ var i, j;
+ if(data) {
+ for(i in data) {
+ if(data.hasOwnProperty(i)) {
+ this._data.massload[i] = data[i];
+ }
+ }
+ }
+ for(i = 0, j = nodes.length; i < j; i++) {
+ dom = this.get_node(nodes[i], true);
+ if (dom && dom.length) {
+ dom.removeClass("jstree-loading").attr('aria-busy',false);
+ }
+ }
+ parent._load_nodes.call(this, nodes, callback, is_callback, force_reload);
+ }, this))
+ .fail($.proxy(function (f) {
+ parent._load_nodes.call(this, nodes, callback, is_callback, force_reload);
+ }, this));
+ }
+ }
}
- return parent._load_nodes.call(this, nodes, callback, is_callback);
+ return parent._load_nodes.call(this, nodes, callback, is_callback, force_reload);
};
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];
- });
+ var data = this._data.massload[obj.id],
+ rslt = null, dom;
+ if(data) {
+ rslt = this[typeof data === 'string' ? '_append_html_data' : '_append_json_data'](
+ obj,
+ typeof data === 'string' ? $($.parseHTML(data)).filter(function () { return this.nodeType !== 3; }) : data,
+ function (status) { callback.call(this, status); }
+ );
+ dom = this.get_node(obj.id, true);
+ if (dom && dom.length) {
+ dom.removeClass("jstree-loading").attr('aria-busy',false);
+ }
+ delete this._data.massload[obj.id];
+ return rslt;
}
return parent._load_node.call(this, obj, callback);
};
};
@@ -6777,14 +7147,14 @@
* @name $.jstree.defaults.search
* @plugin search
*/
$.jstree.defaults.search = {
/**
- * a jQuery-like AJAX config, which jstree uses if a server should be queried for results.
- *
+ * 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, 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
+ * 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
*/
ajax : false,
/**
@@ -6798,11 +7168,11 @@
* @name $.jstree.defaults.search.case_sensitive
* @plugin search
*/
case_sensitive : false,
/**
- * Indicates if the tree should be filtered (by default) to show only matching nodes (keep in mind this can be a heavy on large trees in old browsers).
+ * Indicates if the tree should be filtered (by default) to show only matching nodes (keep in mind this can be a heavy on large trees in old browsers).
* This setting can be changed at runtime when calling the search method. Default is `false`.
* @name $.jstree.defaults.search.show_only_matches
* @plugin search
*/
show_only_matches : false,
@@ -6847,28 +7217,34 @@
this._data.search.hdn = [];
this.element
.on("search.jstree", $.proxy(function (e, data) {
if(this._data.search.som && data.res.length) {
- var m = this._model.data, i, j, p = [];
+ var m = this._model.data, i, j, p = [], k, l;
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);
+ for (k = 0, l = m[data.res[i]].children_d.length; k < l; k++) {
+ if (m[m[data.res[i]].children_d[k]] && !m[m[data.res[i]].children_d[k]].state.hidden) {
+ p.push(m[data.res[i]].children_d[k]);
+ }
+ }
}
}
}
p = $.vakata.array_remove_item($.vakata.array_unique(p), $.jstree.root);
this._data.search.hdn = this.hide_all(true);
- this.show_node(p);
+ this.show_node(p, true);
+ this.redraw(true);
}
}, this))
.on("clear_search.jstree", $.proxy(function (e, data) {
if(this._data.search.som && data.res.length) {
- this.show_node(this._data.search.hdn);
+ this.show_node(this._data.search.hdn, true);
+ this.redraw(true);
}
}, this));
};
/**
* used to search the tree nodes for a given string
@@ -6906,32 +7282,36 @@
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, inside, append);
- }, true);
+ this.search(str, true, show_only_matches, inside, append, show_only_matches_children);
+ });
}, this), inside);
}
else {
a = $.extend({}, a);
if(!a.data) { a.data = {}; }
a.data.str = str;
if(inside) {
a.data.inside = inside;
}
- return $.ajax(a)
+ if (this._data.search.lastRequest) {
+ this._data.search.lastRequest.abort();
+ }
+ this._data.search.lastRequest = $.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) };
this.settings.core.error.call(this, this._data.core.last_error);
}, this))
.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, inside, append);
- }, true);
+ this.search(str, true, show_only_matches, inside, append, show_only_matches_children);
+ });
}, this));
+ return this._data.search.lastRequest;
}
}
if(!append) {
this._data.search.str = str;
this._data.search.dom = $();
@@ -6942,11 +7322,11 @@
}
f = new $.vakata.search(str, true, { caseSensitive : s.case_sensitive, fuzzy : s.fuzzy });
$.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) ) ) {
+ if(v.text && !v.state.hidden && (!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) {
@@ -7340,10 +7720,12 @@
*
* * `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.
+ * * `li_attr` an object of values which will be used to add HTML attributes on the resulting LI DOM node (merged with the node's own data)
+ * * `a_attr` an object of values which will be used to add HTML attributes on the resulting A DOM node (merged with the node's own data)
*
* 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.
@@ -7381,11 +7763,11 @@
this.element
.on('model.jstree', $.proxy(function (e, data) {
var m = this._model.data,
dpc = data.nodes,
t = this.settings.types,
- i, j, c = 'default';
+ i, j, c = 'default', k;
for(i = 0, j = dpc.length; i < j; i++) {
c = 'default';
if(m[dpc[i]].original && m[dpc[i]].original.type && t[m[dpc[i]].original.type]) {
c = m[dpc[i]].original.type;
}
@@ -7394,10 +7776,43 @@
}
m[dpc[i]].type = c;
if(m[dpc[i]].icon === true && t[c].icon !== undefined) {
m[dpc[i]].icon = t[c].icon;
}
+ if(t[c].li_attr !== undefined && typeof t[c].li_attr === 'object') {
+ for (k in t[c].li_attr) {
+ if (t[c].li_attr.hasOwnProperty(k)) {
+ if (k === 'id') {
+ continue;
+ }
+ else if (m[dpc[i]].li_attr[k] === undefined) {
+ m[dpc[i]].li_attr[k] = t[c].li_attr[k];
+ }
+ else if (k === 'class') {
+ m[dpc[i]].li_attr['class'] = t[c].li_attr['class'] + ' ' + m[dpc[i]].li_attr['class'];
+ }
+ }
+ }
+ }
+ if(t[c].a_attr !== undefined && typeof t[c].a_attr === 'object') {
+ for (k in t[c].a_attr) {
+ if (t[c].a_attr.hasOwnProperty(k)) {
+ if (k === 'id') {
+ continue;
+ }
+ else if (m[dpc[i]].a_attr[k] === undefined) {
+ m[dpc[i]].a_attr[k] = t[c].a_attr[k];
+ }
+ else if (k === 'href' && m[dpc[i]].a_attr[k] === '#') {
+ m[dpc[i]].a_attr['href'] = t[c].a_attr['href'];
+ }
+ else if (k === 'class') {
+ m[dpc[i]].a_attr['class'] = t[c].a_attr['class'] + ' ' + m[dpc[i]].a_attr['class'];
+ }
+ }
+ }
+ }
}
m[$.jstree.root].type = $.jstree.root;
}, this));
parent.bind.call(this);
};
@@ -7524,33 +7939,135 @@
* @param {mixed} obj the node to change
* @param {String} type the new type
* @plugin types
*/
this.set_type = function (obj, type) {
- var t, t1, t2, old_type, old_icon;
+ var m = this._model.data, t, t1, t2, old_type, old_icon, k, d, a;
if($.isArray(obj)) {
obj = obj.slice();
for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
this.set_type(obj[t1], type);
}
return true;
}
t = this.settings.types;
obj = this.get_node(obj);
if(!t[type] || !obj) { return false; }
+ d = this.get_node(obj, true);
+ if (d && d.length) {
+ a = d.children('.jstree-anchor');
+ }
old_type = obj.type;
old_icon = this.get_icon(obj);
obj.type = type;
- if(old_icon === true || (t[old_type] && t[old_type].icon !== undefined && old_icon === t[old_type].icon)) {
+ if(old_icon === true || !t[old_type] || (t[old_type].icon !== undefined && old_icon === t[old_type].icon)) {
this.set_icon(obj, t[type].icon !== undefined ? t[type].icon : true);
}
+
+ // remove old type props
+ if(t[old_type] && t[old_type].li_attr !== undefined && typeof t[old_type].li_attr === 'object') {
+ for (k in t[old_type].li_attr) {
+ if (t[old_type].li_attr.hasOwnProperty(k)) {
+ if (k === 'id') {
+ continue;
+ }
+ else if (k === 'class') {
+ m[obj.id].li_attr['class'] = (m[obj.id].li_attr['class'] || '').replace(t[old_type].li_attr[k], '');
+ if (d) { d.removeClass(t[old_type].li_attr[k]); }
+ }
+ else if (m[obj.id].li_attr[k] === t[old_type].li_attr[k]) {
+ m[obj.id].li_attr[k] = null;
+ if (d) { d.removeAttr(k); }
+ }
+ }
+ }
+ }
+ if(t[old_type] && t[old_type].a_attr !== undefined && typeof t[old_type].a_attr === 'object') {
+ for (k in t[old_type].a_attr) {
+ if (t[old_type].a_attr.hasOwnProperty(k)) {
+ if (k === 'id') {
+ continue;
+ }
+ else if (k === 'class') {
+ m[obj.id].a_attr['class'] = (m[obj.id].a_attr['class'] || '').replace(t[old_type].a_attr[k], '');
+ if (a) { a.removeClass(t[old_type].a_attr[k]); }
+ }
+ else if (m[obj.id].a_attr[k] === t[old_type].a_attr[k]) {
+ if (k === 'href') {
+ m[obj.id].a_attr[k] = '#';
+ if (a) { a.attr('href', '#'); }
+ }
+ else {
+ delete m[obj.id].a_attr[k];
+ if (a) { a.removeAttr(k); }
+ }
+ }
+ }
+ }
+ }
+
+ // add new props
+ if(t[type].li_attr !== undefined && typeof t[type].li_attr === 'object') {
+ for (k in t[type].li_attr) {
+ if (t[type].li_attr.hasOwnProperty(k)) {
+ if (k === 'id') {
+ continue;
+ }
+ else if (m[obj.id].li_attr[k] === undefined) {
+ m[obj.id].li_attr[k] = t[type].li_attr[k];
+ if (d) {
+ if (k === 'class') {
+ d.addClass(t[type].li_attr[k]);
+ }
+ else {
+ d.attr(k, t[type].li_attr[k]);
+ }
+ }
+ }
+ else if (k === 'class') {
+ m[obj.id].li_attr['class'] = t[type].li_attr[k] + ' ' + m[obj.id].li_attr['class'];
+ if (d) { d.addClass(t[type].li_attr[k]); }
+ }
+ }
+ }
+ }
+ if(t[type].a_attr !== undefined && typeof t[type].a_attr === 'object') {
+ for (k in t[type].a_attr) {
+ if (t[type].a_attr.hasOwnProperty(k)) {
+ if (k === 'id') {
+ continue;
+ }
+ else if (m[obj.id].a_attr[k] === undefined) {
+ m[obj.id].a_attr[k] = t[type].a_attr[k];
+ if (a) {
+ if (k === 'class') {
+ a.addClass(t[type].a_attr[k]);
+ }
+ else {
+ a.attr(k, t[type].a_attr[k]);
+ }
+ }
+ }
+ else if (k === 'href' && m[obj.id].a_attr[k] === '#') {
+ m[obj.id].a_attr['href'] = t[type].a_attr['href'];
+ if (a) { a.attr('href', t[type].a_attr['href']); }
+ }
+ else if (k === 'class') {
+ m[obj.id].a_attr['class'] = t[type].a_attr['class'] + ' ' + m[obj.id].a_attr['class'];
+ if (a) { a.addClass(t[type].a_attr[k]); }
+ }
+ }
+ }
+ }
+
return true;
};
};
// include the types plugin by default
// $.jstree.defaults.plugins.push("types");
+
/**
* ### Unique plugin
*
* Enforces that no nodes with the same name can coexist as siblings.
*/
@@ -7697,13 +8214,15 @@
.on("hover_node.jstree dehover_node.jstree", $.proxy(function (e, data) {
if(e.type === "hover_node" && this.is_disabled(data.node)) { return; }
this.get_node(data.node, true).children('.jstree-wholerow')[e.type === "hover_node"?"addClass":"removeClass"]('jstree-wholerow-hovered');
}, this))
.on("contextmenu.jstree", ".jstree-wholerow", $.proxy(function (e) {
- e.preventDefault();
- 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);
+ if (this._data.contextmenu) {
+ e.preventDefault();
+ 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");
@@ -7713,9 +8232,14 @@
})
*/
.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 });
+ $(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp).focus();
+ })
+ .on("dblclick.jstree", ".jstree-wholerow", function (e) {
+ e.stopImmediatePropagation();
+ var tmp = $.Event('dblclick', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey });
$(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp).focus();
})
.on("click.jstree", ".jstree-leaf > .jstree-ocl", $.proxy(function (e) {
e.stopImmediatePropagation();
var tmp = $.Event('click', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey });
\ No newline at end of file