vendor/assets/javascripts/jstree.js in jstree-rails-4-3.3.4 vs vendor/assets/javascripts/jstree.js in jstree-rails-4-3.3.8
- old
+ new
@@ -11,11 +11,11 @@
factory(jQuery);
}
}(function ($, undefined) {
"use strict";
/*!
- * jsTree 3.3.4
+ * jsTree 3.3.8
* http://jstree.com/
*
* Copyright (c) 2014 Ivan Bozhanov (http://vakata.com)
*
* Licensed same as jquery - under the terms of the MIT License
@@ -52,11 +52,11 @@
$.jstree = {
/**
* specifies the jstree version in use
* @name $.jstree.version
*/
- version : '3.3.4',
+ version : '3.3.8',
/**
* holds all the default options used when creating new instances
* @name $.jstree.defaults
*/
defaults : {
@@ -428,14 +428,94 @@
* Force node text to plain text (and escape HTML). Defaults to `false`
* @name $.jstree.defaults.core.force_text
*/
force_text : false,
/**
- * Should the node should be toggled if the text is double clicked . Defaults to `true`
+ * Should the node be toggled if the text is double clicked. Defaults to `true`
* @name $.jstree.defaults.core.dblclick_toggle
*/
- dblclick_toggle : true
+ dblclick_toggle : true,
+ /**
+ * Should the loaded nodes be part of the state. Defaults to `false`
+ * @name $.jstree.defaults.core.loaded_state
+ */
+ loaded_state : false,
+ /**
+ * Should the last active node be focused when the tree container is blurred and the focused again. This helps working with screen readers. Defaults to `true`
+ * @name $.jstree.defaults.core.restore_focus
+ */
+ restore_focus : true,
+ /**
+ * Default keyboard shortcuts (an object where each key is the button name or combo - like 'enter', 'ctrl-space', 'p', etc and the value is the function to execute in the instance's scope)
+ * @name $.jstree.defaults.core.keyboard
+ */
+ keyboard : {
+ 'ctrl-space': function (e) {
+ // aria defines space only with Ctrl
+ e.type = "click";
+ $(e.currentTarget).trigger(e);
+ },
+ 'enter': function (e) {
+ // enter
+ e.type = "click";
+ $(e.currentTarget).trigger(e);
+ },
+ 'left': function (e) {
+ // left
+ e.preventDefault();
+ if(this.is_open(e.currentTarget)) {
+ this.close_node(e.currentTarget);
+ }
+ else {
+ var o = this.get_parent(e.currentTarget);
+ if(o && o.id !== $.jstree.root) { this.get_node(o, true).children('.jstree-anchor').focus(); }
+ }
+ },
+ 'up': function (e) {
+ // up
+ e.preventDefault();
+ var o = this.get_prev_dom(e.currentTarget);
+ if(o && o.length) { o.children('.jstree-anchor').focus(); }
+ },
+ 'right': function (e) {
+ // 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)) {
+ var o = this.get_node(e.currentTarget, true).children('.jstree-children')[0];
+ if(o) { $(this._firstChild(o)).children('.jstree-anchor').focus(); }
+ }
+ },
+ 'down': function (e) {
+ // down
+ e.preventDefault();
+ var o = this.get_next_dom(e.currentTarget);
+ if(o && o.length) { o.children('.jstree-anchor').focus(); }
+ },
+ '*': function (e) {
+ // aria defines * on numpad as open_all - not very common
+ this.open_all();
+ },
+ 'home': function (e) {
+ // home
+ e.preventDefault();
+ var o = this._firstChild(this.get_container_ul()[0]);
+ if(o) { $(o).children('.jstree-anchor').filter(':visible').focus(); }
+ },
+ 'end': function (e) {
+ // end
+ e.preventDefault();
+ this.element.find('.jstree-anchor').filter(':visible').last().focus();
+ },
+ 'f2': function (e) {
+ // f2 - safe to include - if check_callback is false it will fail
+ e.preventDefault();
+ this.edit(e.currentTarget);
+ }
+ }
};
$.jstree.core.prototype = {
/**
* used to decorate an instance with a plugin. Used internally.
* @private
@@ -546,11 +626,13 @@
}
if(!keep_html) { this.element.empty(); }
this.teardown();
},
/**
- * Create prototype node
+ * Create a prototype node
+ * @name _create_prototype_node()
+ * @return {DOMElement}
*/
_create_prototype_node : function () {
var _node = document.createElement('LI'), _temp1, _temp2;
_node.setAttribute('role', 'treeitem');
_temp1 = document.createElement('I');
@@ -568,10 +650,52 @@
_node.appendChild(_temp1);
_temp1 = _temp2 = null;
return _node;
},
+ _kbevent_to_func : function (e) {
+ var keys = {
+ 8: "Backspace", 9: "Tab", 13: "Enter", 19: "Pause", 27: "Esc",
+ 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home",
+ 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "Print", 45: "Insert",
+ 46: "Delete", 96: "Numpad0", 97: "Numpad1", 98: "Numpad2", 99 : "Numpad3",
+ 100: "Numpad4", 101: "Numpad5", 102: "Numpad6", 103: "Numpad7",
+ 104: "Numpad8", 105: "Numpad9", '-13': "NumpadEnter", 112: "F1",
+ 113: "F2", 114: "F3", 115: "F4", 116: "F5", 117: "F6", 118: "F7",
+ 119: "F8", 120: "F9", 121: "F10", 122: "F11", 123: "F12", 144: "Numlock",
+ 145: "Scrolllock", 16: 'Shift', 17: 'Ctrl', 18: 'Alt',
+ 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5',
+ 54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a',
+ 66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h',
+ 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o',
+ 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
+ 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
+ 186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`',
+ 219: '[', 220: '\\',221: ']', 222: "'", 111: '/', 106: '*', 173: '-'
+ };
+ var parts = [];
+ if (e.ctrlKey) { parts.push('ctrl'); }
+ if (e.altKey) { parts.push('alt'); }
+ if (e.shiftKey) { parts.push('shift'); }
+ parts.push(keys[e.which] || e.which);
+ parts = parts.sort().join('-').toLowerCase();
+
+ var kb = this.settings.core.keyboard, i, tmp;
+ for (i in kb) {
+ if (kb.hasOwnProperty(i)) {
+ tmp = i;
+ if (tmp !== '-' && tmp !== '+') {
+ tmp = tmp.replace('--', '-MINUS').replace('+-', '-MINUS').replace('++', '-PLUS').replace('-+', '-PLUS');
+ tmp = tmp.split(/-|\+/).sort().join('-').replace('MINUS', '-').replace('PLUS', '+').toLowerCase();
+ }
+ if (tmp === parts) {
+ return kb[i];
+ }
+ }
+ }
+ return null;
+ },
/**
* part of the destroying of an instance. Used internally.
* @private
* @name teardown()
*/
@@ -633,87 +757,20 @@
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 && 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; }
}
- switch(e.which) {
- case 32: // aria defines space only with Ctrl
- if(e.ctrlKey) {
- e.type = "click";
- $(e.currentTarget).trigger(e);
- }
- break;
- case 13: // enter
- e.type = "click";
- $(e.currentTarget).trigger(e);
- break;
- case 37: // left
- e.preventDefault();
- if(this.is_open(e.currentTarget)) {
- this.close_node(e.currentTarget);
- }
- else {
- o = this.get_parent(e.currentTarget);
- 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);
- if(o && o.length) { o.children('.jstree-anchor').focus(); }
- break;
- 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)) {
- o = this.get_node(e.currentTarget, true).children('.jstree-children')[0];
- if(o) { $(this._firstChild(o)).children('.jstree-anchor').focus(); }
- }
- break;
- case 40: // down
- e.preventDefault();
- o = this.get_next_dom(e.currentTarget);
- if(o && o.length) { o.children('.jstree-anchor').focus(); }
- break;
- case 106: // aria defines * on numpad as open_all - not very common
- this.open_all();
- break;
- case 36: // home
- e.preventDefault();
- o = this._firstChild(this.get_container_ul()[0]);
- if(o) { $(o).children('.jstree-anchor').filter(':visible').focus(); }
- 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;
-
- */
+ var f = this._kbevent_to_func(e);
+ if (f) {
+ var r = f.call(this, e);
+ if (r === false || r === true) {
+ return r;
+ }
}
}, this))
.on("load_node.jstree", $.proxy(function (e, data) {
if(data.status) {
if(data.node.id === $.jstree.root && !this._data.core.loaded) {
@@ -830,24 +887,24 @@
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();
+ $(e.currentTarget).filter('.jstree-hovered').trigger('mouseleave');
this.element.attr('tabindex', '0');
}, this))
.on('focus.jstree', '.jstree-anchor', $.proxy(function (e) {
var tmp = this.get_node(e.currentTarget);
if(tmp && tmp.id) {
this._data.core.focused = tmp.id;
}
- this.element.find('.jstree-hovered').not(e.currentTarget).mouseleave();
- $(e.currentTarget).mouseenter();
+ this.element.find('.jstree-hovered').not(e.currentTarget).trigger('mouseleave');
+ $(e.currentTarget).trigger('mouseenter');
this.element.attr('tabindex', '-1');
}, this))
.on('focus.jstree', $.proxy(function () {
- if(+(new Date()) - was_click > 500 && !this._data.core.focused) {
+ if(+(new Date()) - was_click > 500 && !this._data.core.focused && this.settings.core.restore_focus) {
was_click = 0;
var act = this.get_node(this.element.attr('aria-activedescendant'), true);
if(act) {
act.find('> .jstree-anchor').focus();
}
@@ -964,10 +1021,13 @@
*/
get_node : function (obj, as_dom) {
if(obj && obj.id) {
obj = obj.id;
}
+ if (obj instanceof $ && obj.length && obj[0].id) {
+ obj = obj[0].id;
+ }
var dom;
try {
if(this._model.data[obj]) {
obj = this._model.data[obj];
}
@@ -975,14 +1035,14 @@
obj = this._model.data[obj.replace(/^#/, '')];
}
else if(typeof obj === "string" && (dom = $('#' + obj.replace($.jstree.idregex,'\\$&'), 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 && this._model.data[dom.closest('.jstree-node').attr('id')]) {
+ else if((dom = this.element.find(obj)).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')) {
+ else if((dom = this.element.find(obj)).length && dom.hasClass('jstree')) {
obj = this._model.data[$.jstree.root];
}
else {
return false;
}
@@ -1112,11 +1172,11 @@
return false;
}
return obj.parent;
},
/**
- * get a jQuery collection of all the children of a node (node must be rendered)
+ * get a jQuery collection of all the children of a node (node must be rendered), returns false on error
* @name get_children_dom(obj)
* @param {mixed} obj
* @return {jQuery}
*/
get_children_dom : function (obj) {
@@ -1272,11 +1332,11 @@
}
}, this));
return true;
},
/**
- * load an array of nodes (will also load unavailable nodes as soon as the appear in the structure). Used internally.
+ * load an array of nodes (will also load unavailable nodes as soon as they appear in the structure). Used internally.
* @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
*/
@@ -1451,11 +1511,11 @@
* @name _node_changed(obj [, callback])
* @param {mixed} obj
*/
_node_changed : function (obj) {
obj = this.get_node(obj);
- if(obj) {
+ if (obj && $.inArray(obj.id, this._model.changed) === -1) {
this._model.changed.push(obj.id);
}
},
/**
* appends HTML content to the tree. Used internally.
@@ -1543,10 +1603,11 @@
'm' : this._model.data,
't_id' : this._id,
't_cnt' : this._cnt,
'sel' : this._data.core.selected
},
+ inst = this,
func = function (data, undefined) {
if(data.data) { data = data.data; }
var dat = data.dat,
par = data.par,
chd = [],
@@ -1753,14 +1814,25 @@
// 1) convert to object (foreach)
for(i = 0, j = dat.length; i < j; i++) {
if(!dat[i].children) {
dat[i].children = [];
}
+ if(!dat[i].state) {
+ dat[i].state = {};
+ }
m[dat[i].id.toString()] = dat[i];
}
// 2) populate children (foreach)
for(i = 0, j = dat.length; i < j; i++) {
+ if (!m[dat[i].parent.toString()]) {
+ if (typeof inst !== "undefined") {
+ inst._data.core.last_error = { 'error' : 'parse', 'plugin' : 'core', 'id' : 'core_07', 'reason' : 'Node with invalid parent', 'data' : JSON.stringify({ 'id' : dat[i].id.toString(), 'parent' : dat[i].parent.toString() }) };
+ inst.settings.core.error.call(inst, inst._data.core.last_error);
+ }
+ continue;
+ }
+
m[dat[i].parent.toString()].children.push(dat[i].id.toString());
// populate parent.children_d
p.children_d.push(dat[i].id.toString());
}
// 3) normalize && populate parents and children_d with recursion
@@ -2220,11 +2292,11 @@
tmp.children.push(c);
if(e.children_d.length) {
tmp.children_d = tmp.children_d.concat(e.children_d);
}
}
- tmp.children_d = tmp.children_d.concat(tmp.children);
+ tmp.children_d = tmp.children.concat(tmp.children_d);
}
if(d && d.children && d.children === true) {
tmp.state.loaded = false;
tmp.children = [];
tmp.children_d = [];
@@ -2257,11 +2329,11 @@
f.className = this.get_container_ul()[0].className;
f.setAttribute('role','group');
this.element.empty().append(f);
//this.get_container_ul()[0].appendChild(f);
}
- if(fe !== null) {
+ if(fe !== null && this.settings.core.restore_focus) {
tmp = this.get_node(fe, true);
if(tmp && tmp.length && tmp.children('.jstree-anchor')[0] !== document.activeElement) {
tmp.children('.jstree-anchor').focus();
}
else {
@@ -2433,10 +2505,13 @@
}
if(obj.state.hidden) {
c += ' jstree-hidden';
}
+ if (obj.state.loading) {
+ c += ' jstree-loading';
+ }
if(obj.state.loaded && !has_children) {
c += ' jstree-leaf';
}
else {
c += obj.state.opened && obj.state.loaded ? ' jstree-open' : ' jstree-closed';
@@ -2537,11 +2612,11 @@
}, this), 0);
}
return node;
},
/**
- * opens a node, revaling its children. If the node is not loaded it will be loaded and opened once ready.
+ * opens a node, revealing its children. If the node is not loaded it will be loaded and opened once ready.
* @name open_node(obj [, callback, animation])
* @param {mixed} obj the node to open
* @param {Function} callback a function to execute once the node is opened
* @param {Number} animation the animation duration in milliseconds when opening the node (overrides the `core.animation` setting). Use `false` for no animation.
* @trigger open_node.jstree, after_open.jstree, before_open.jstree
@@ -2741,11 +2816,11 @@
if(this.is_open(obj)) {
return this.close_node(obj);
}
},
/**
- * opens all nodes within a node (or the tree), revaling their children. If the node is not loaded it will be loaded and opened once ready.
+ * opens all nodes within a node (or the tree), revealing their children. If the node is not loaded it will be loaded and opened once ready.
* @name open_all([obj, animation, original_obj])
* @param {mixed} obj the node to open recursively, omit to open all nodes in the tree
* @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
@@ -2782,11 +2857,11 @@
*/
this.trigger('open_all', { "node" : this.get_node(original_obj) });
}
},
/**
- * closes all nodes within a node (or the tree), revaling their children
+ * closes all nodes within a node (or the tree), revealing their children
* @name close_all([obj, animation])
* @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
*/
@@ -3358,10 +3433,11 @@
*/
get_state : function () {
var state = {
'core' : {
'open' : [],
+ 'loaded' : [],
'scroll' : {
'left' : this.element.scrollLeft(),
'top' : this.element.scrollTop()
},
/*!
@@ -3375,10 +3451,13 @@
}
}, i;
for(i in this._model.data) {
if(this._model.data.hasOwnProperty(i)) {
if(i !== $.jstree.root) {
+ if(this._model.data[i].state.loaded && this.settings.core.loaded_state) {
+ state.core.loaded.push(i);
+ }
if(this._model.data[i].state.opened) {
state.core.open.push(i);
}
if(this._model.data[i].state.selected) {
state.core.selected.push(i);
@@ -3401,10 +3480,23 @@
if(state.core && state.core.selected && state.core.initial_selection === undefined) {
state.core.initial_selection = this._data.core.selected.concat([]).sort().join(',');
}
if(state.core) {
var res, n, t, _this, i;
+ if(state.core.loaded) {
+ if(!this.settings.core.loaded_state || !$.isArray(state.core.loaded) || !state.core.loaded.length) {
+ delete state.core.loaded;
+ this.set_state(state, callback);
+ }
+ else {
+ this._load_nodes(state.core.loaded, function (nodes) {
+ delete state.core.loaded;
+ this.set_state(state, callback);
+ });
+ }
+ return false;
+ }
if(state.core.open) {
if(!$.isArray(state.core.open) || !state.core.open.length) {
delete state.core.open;
this.set_state(state, callback);
}
@@ -3931,10 +4023,14 @@
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) && (chk === "move_node" && $.inArray(obj.id, par.children) === pos)) {
+ this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_08', 'reason' : 'Moving node to its current position', 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
+ return false;
+ }
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;
}
}
@@ -4403,11 +4499,11 @@
ai = a.children("i:visible"),
w1 = oi.width() * oi.length,
w2 = ai.width() * ai.length,
*/
t = default_text;
- h1 = $("<"+"div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body");
+ h1 = $("<"+"div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo(document.body);
h2 = $("<"+"input />", {
"value" : t,
"class" : "jstree-rename-input",
// "size" : t.length,
"css" : {
@@ -4429,10 +4525,11 @@
if(v === "") { v = t; }
h1.remove();
s.replaceWith(a);
s.remove();
t = f ? t : $('<div></div>').append($.parseHTML(t)).html();
+ obj = this.get_node(obj);
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
}
@@ -4703,10 +4800,11 @@
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) {
+ dom.removeClass('jstree-themeicon-custom ' + old).css("background","").removeAttr("rel");
this.hide_icon(obj);
}
else if(icon === true || icon === null || icon === undefined || icon === '') {
dom.removeClass('jstree-themeicon-custom ' + old).css("background","").removeAttr("rel");
if(old === false) { this.show_icon(obj); }
@@ -5075,18 +5173,19 @@
// 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));
var selectedIds = this._cascade_new_checked_state(obj.id, true);
- obj.children_d.concat(obj.id).forEach(function(id) {
- if (selectedIds.indexOf(id) > -1) {
- sel[id] = true;
- }
- else {
- delete sel[id];
- }
- });
+ var temp = obj.children_d.concat(obj.id);
+ for (i = 0, j = temp.length; i < j; i++) {
+ if (selectedIds.indexOf(temp[i]) > -1) {
+ sel[temp[i]] = true;
+ }
+ else {
+ delete sel[temp[i]];
+ }
+ }
}
// apply up
if(s.indexOf('up') !== -1) {
while(par && par.id !== $.jstree.root) {
@@ -5140,11 +5239,11 @@
// apply down
if(s.indexOf('down') !== -1) {
var selectedIds = this._cascade_new_checked_state(obj.id, false);
- cur = cur.filter(function(id) {
+ cur = $.vakata.array_filter(cur, function(id) {
return allIds.indexOf(id) === -1 || selectedIds.indexOf(id) > -1;
});
}
// only apply up if cascade up is enabled and if this node is not selected
@@ -5160,11 +5259,11 @@
if(tmp && tmp.length) {
tmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
}
}
- cur = cur.filter(function(id) {
+ cur = $.vakata.array_filter(cur, function(id) {
return obj.parents.indexOf(id) === -1;
});
}
this._data[ t ? 'core' : 'checkbox' ].selected = cur;
@@ -5256,20 +5355,22 @@
p = this.get_node(p.parent);
}
}, this));
}
};
-
/**
- * set the undetermined state where and if necessary. Used internally.
- * @private
- * @name _undetermined()
+ * get an array of all nodes whose state is "undetermined"
+ * @name get_undetermined([full])
+ * @param {boolean} full: if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
+ * @return {Array}
* @plugin checkbox
*/
- this._undetermined = function () {
- 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;
+ this.get_undetermined = function (full) {
+ if (this.settings.checkbox.cascade.indexOf('undetermined') === -1) {
+ 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, r = [];
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) {
break;
@@ -5318,18 +5419,32 @@
}
}
}
}
});
+ for (i = 0, j = p.length; i < j; i++) {
+ if(!m[p[i]].state[ t ? 'selected' : 'checked' ]) {
+ r.push(full ? m[p[i]] : p[i]);
+ }
+ }
+ return r;
+ };
+ /**
+ * set the undetermined state where and if necessary. Used internally.
+ * @private
+ * @name _undetermined()
+ * @plugin checkbox
+ */
+ this._undetermined = function () {
+ if(this.element === null) { return; }
+ var p = this.get_undetermined(false), i, j, s;
this.element.find('.jstree-undetermined').removeClass('jstree-undetermined');
- for(i = 0, j = p.length; i < j; i++) {
- if(!m[p[i]].state[ t ? 'selected' : 'checked' ]) {
- s = this.get_node(p[i], true);
- if(s && s.length) {
- s.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-undetermined');
- }
+ for (i = 0, j = p.length; i < j; i++) {
+ s = this.get_node(p[i], true);
+ if(s && s.length) {
+ s.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-undetermined');
}
}
};
this.redraw_node = function(obj, deep, is_callback, force_render) {
obj = parent.redraw_node.apply(this, arguments);
@@ -5430,11 +5545,11 @@
this.trigger('disable_checkbox', { 'node' : obj });
}
};
/**
* enable a node's checkbox
- * @name disable_checkbox(obj)
+ * @name enable_checkbox(obj)
* @param {mixed} obj an array can be used too
* @trigger enable_checkbox.jstree
* @plugin checkbox
*/
this.enable_checkbox = function (obj) {
@@ -5488,67 +5603,69 @@
}
this.trigger('activate_node', { 'node' : this.get_node(obj) });
};
/**
- * Unchecks a node and all its descendants. This function does NOT affect hidden and disabled nodes (or their descendants).
+ * Cascades checked state to a node and all its descendants. This function does NOT affect hidden and disabled nodes (or their descendants).
* However if these unaffected nodes are already selected their ids will be included in the returned array.
- * @param id
- * @param checkedState
+ * @private
+ * @param {string} id the node ID
+ * @param {bool} checkedState should the nodes be checked or not
* @returns {Array} Array of all node id's (in this tree branch) that are checked.
*/
- this._cascade_new_checked_state = function(id, checkedState) {
+ this._cascade_new_checked_state = function (id, checkedState) {
var self = this;
var t = this.settings.checkbox.tie_selection;
var node = this._model.data[id];
var selectedNodeIds = [];
- var selectedChildrenIds = [];
+ var selectedChildrenIds = [], i, j, selectedChildIds;
if (
(this.settings.checkbox.cascade_to_disabled || !node.state.disabled) &&
(this.settings.checkbox.cascade_to_hidden || !node.state.hidden)
) {
- //First try and check/uncheck the children
- if (node.children) {
- node.children.forEach(function(childId) {
- var selectedChildIds = self._cascade_new_checked_state(childId, checkedState);
+ //First try and check/uncheck the children
+ if (node.children) {
+ for (i = 0, j = node.children.length; i < j; i++) {
+ var childId = node.children[i];
+ selectedChildIds = self._cascade_new_checked_state(childId, checkedState);
selectedNodeIds = selectedNodeIds.concat(selectedChildIds);
if (selectedChildIds.indexOf(childId) > -1) {
selectedChildrenIds.push(childId);
}
- });
+ }
}
var dom = self.get_node(node, true);
- //A node's state is undetermined if some but not all of it's children are checked/selected .
+ //A node's state is undetermined if some but not all of it's children are checked/selected .
var undetermined = selectedChildrenIds.length > 0 && selectedChildrenIds.length < node.children.length;
if(node.original && node.original.state && node.original.state.undetermined) {
node.original.state.undetermined = undetermined;
}
- //If a node is undetermined then remove selected class
+ //If a node is undetermined then remove selected class
if (undetermined) {
- node.state[ t ? 'selected' : 'checked' ] = false;
- dom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
+ node.state[ t ? 'selected' : 'checked' ] = false;
+ dom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
}
- //Otherwise, if the checkedState === true (i.e. the node is being checked now) and all of the node's children are checked (if it has any children),
- //check the node and style it correctly.
+ //Otherwise, if the checkedState === true (i.e. the node is being checked now) and all of the node's children are checked (if it has any children),
+ //check the node and style it correctly.
else if (checkedState && selectedChildrenIds.length === node.children.length) {
- node.state[ t ? 'selected' : 'checked' ] = checkedState;
+ node.state[ t ? 'selected' : 'checked' ] = checkedState;
selectedNodeIds.push(node.id);
dom.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
}
else {
- node.state[ t ? 'selected' : 'checked' ] = false;
+ node.state[ t ? 'selected' : 'checked' ] = false;
dom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
}
}
else {
- var selectedChildIds = this.get_checked_descendants(id);
+ selectedChildIds = this.get_checked_descendants(id);
if (node.state[ t ? 'selected' : 'checked' ]) {
selectedChildIds.push(node.id);
}
@@ -5558,18 +5675,21 @@
return selectedNodeIds;
};
/**
* Gets ids of nodes selected in branch (of tree) specified by id (does not include the node specified by id)
- * @param id
+ * @name get_checked_descendants(obj)
+ * @param {string} id the node ID
+ * @return {Array} array of IDs
+ * @plugin checkbox
*/
- this.get_checked_descendants = function(id) {
+ this.get_checked_descendants = function (id) {
var self = this;
var t = self.settings.checkbox.tie_selection;
var node = self._model.data[id];
- return node.children_d.filter(function(_id) {
+ return $.vakata.array_filter(node.children_d, function(_id) {
return self._model.data[_id].state[ t ? 'selected' : 'checked' ];
});
};
/**
@@ -5724,11 +5844,11 @@
* @return {Array}
* @plugin checkbox
*/
this.get_checked = function (full) {
if(this.settings.checkbox.tie_selection) { return this.get_selected(full); }
- return full ? $.map(this._data.checkbox.selected, $.proxy(function (i) { return this.get_node(i); }, this)) : this._data.checkbox.selected;
+ return full ? $.map(this._data.checkbox.selected, $.proxy(function (i) { return this.get_node(i); }, this)) : this._data.checkbox.selected.slice();
};
/**
* get an array of all top level checked nodes (ignoring children of checked nodes) (if tie_selection is on in the settings this function will return the same as get_top_selected)
* @name get_top_checked([full])
* @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
@@ -5811,11 +5931,11 @@
return false;
}
return res;
};
this.refresh = function (skip_loading, forget_state) {
- if(!this.settings.checkbox.tie_selection) {
+ if(this.settings.checkbox.tie_selection) {
this._data.checkbox.selected = [];
}
return parent.refresh.apply(this, arguments);
};
};
@@ -5838,11 +5958,11 @@
$.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);
+ return parent.activate_node.call(this, obj, e);
}
};
};
@@ -6039,12 +6159,13 @@
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.originalEvent.changedTouches[0].clientX) > 50 || Math.abs(ey - e.originalEvent.changedTouches[0].clientY) > 50)) {
+ if(cto && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0] && (Math.abs(ex - e.originalEvent.changedTouches[0].clientX) > 10 || Math.abs(ey - e.originalEvent.changedTouches[0].clientY) > 10)) {
clearTimeout(cto);
+ $.vakata.context.hide();
}
})
.on('touchend.vakata.jstree', function (e) {
if(cto) {
clearTimeout(cto);
@@ -6312,11 +6433,11 @@
}
if($.vakata.context._parse(data)) {
vakata_context.element.html(vakata_context.html);
}
if(vakata_context.items.length) {
- vakata_context.element.appendTo("body");
+ vakata_context.element.appendTo(document.body);
e = vakata_context.element;
x = vakata_context.position_x;
y = vakata_context.position_y;
w = e.width();
h = e.height();
@@ -6368,11 +6489,11 @@
$.vakata.context._trigger("hide");
}
}
};
$(function () {
- right_to_left = $("body").css("direction") === "rtl";
+ right_to_left = $(document.body).css("direction") === "rtl";
var to = false;
vakata_context.element = $("<ul class='vakata-context'></ul>");
vakata_context.element
.on("mouseenter", "li", function (e) {
@@ -6656,15 +6777,27 @@
lastev = false,
opento = false,
marker = $('<div id="jstree-marker"> </div>').hide(); //.appendTo('body');
$(document)
+ .on('dragover.vakata.jstree', function (e) {
+ if (elm) {
+ $.vakata.dnd._trigger('move', e, { 'helper': $(), 'element': elm, 'data': drg });
+ }
+ })
+ .on('drop.vakata.jstree', function (e) {
+ if (elm) {
+ $.vakata.dnd._trigger('stop', e, { 'helper': $(), 'element': elm, 'data': drg });
+ elm = null;
+ drg = null;
+ }
+ })
.on('dnd_start.vakata.jstree', function (e, data) {
lastmv = false;
lastev = false;
if(!data || !data.data || !data.data.jstree) { return; }
- marker.appendTo('body'); //.show();
+ marker.appendTo(document.body); //.show();
})
.on('dnd_move.vakata.jstree', function (e, data) {
var isDifferentNode = data.event.target !== lastev.target;
if(opento) {
if (!data.event || data.event.type !== 'dragover' || isDifferentNode) {
@@ -6794,11 +6927,11 @@
}
$('.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';
+ //data.event.originalEvent.dataTransfer.dropEffect = 'none';
}
marker.hide();
})
.on('dnd_scroll.vakata.jstree', function (e, data) {
if(!data || !data.data || !data.data.jstree) { return; }
@@ -6887,11 +7020,11 @@
scroll_speed : 10,
scroll_proximity : 20,
helper_left : 5,
helper_top : 10,
threshold : 5,
- threshold_touch : 50
+ threshold_touch : 10
},
_trigger : function (event_name, e, data) {
if (data === undefined) {
data = $.vakata.dnd._get();
}
@@ -7005,11 +7138,11 @@
if(
Math.abs(e.pageX - vakata_dnd.init_x) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold) ||
Math.abs(e.pageY - vakata_dnd.init_y) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold)
) {
if(vakata_dnd.helper) {
- vakata_dnd.helper.appendTo("body");
+ vakata_dnd.helper.appendTo(document.body);
vakata_dnd.helper_w = vakata_dnd.helper.outerWidth();
}
vakata_dnd.is_drag = true;
$(vakata_dnd.target).one('click.vakata', false);
/**
@@ -7752,11 +7885,17 @@
/**
* A function that will be executed prior to restoring state with one argument - the state object. Can be used to clear unwanted parts of the state.
* @name $.jstree.defaults.state.filter
* @plugin state
*/
- filter : false
+ filter : false,
+ /**
+ * Should loaded nodes be restored (setting this to true means that it is possible that the whole tree will be loaded for some users - use with caution). Defaults to `false`
+ * @name $.jstree.defaults.state.preserve_loaded
+ * @plugin state
+ */
+ preserve_loaded : false
};
$.jstree.plugins.state = function (options, parent) {
this.bind = function () {
parent.bind.call(this);
var bind = $.proxy(function () {
@@ -7782,11 +7921,15 @@
* save the state
* @name save_state()
* @plugin state
*/
this.save_state = function () {
- var st = { 'state' : this.get_state(), 'ttl' : this.settings.state.ttl, 'sec' : +(new Date()) };
+ var tm = this.get_state();
+ if (!this.settings.state.preserve_loaded) {
+ delete tm.core.loaded;
+ }
+ var st = { 'state' : tm, 'ttl' : this.settings.state.ttl, 'sec' : +(new Date()) };
$.vakata.storage.set(this.settings.state.key, JSON.stringify(st));
};
/**
* restore the state from the user's computer
* @name restore_state()
@@ -7797,10 +7940,13 @@
if(!!k) { try { k = JSON.parse(k); } catch(ex) { return false; } }
if(!!k && k.ttl && k.sec && +(new Date()) - k.sec > k.ttl) { return false; }
if(!!k && k.state) { k = k.state; }
if(!!k && $.isFunction(this.settings.state.filter)) { k = this.settings.state.filter.call(this, k); }
if(!!k) {
+ if (!this.settings.state.preserve_loaded) {
+ delete k.core.loaded;
+ }
this.element.one("set_state.jstree", function (e, data) { data.instance.trigger('restore_state', { 'state' : $.extend(true, {}, k) }); });
this.set_state(k);
return true;
}
return false;
@@ -8201,10 +8347,16 @@
* @name $.jstree.defaults.unique.case_sensitive
* @plugin unique
*/
case_sensitive : false,
/**
+ * Indicates if white space should be trimmed before the comparison. Default is `false`.
+ * @name $.jstree.defaults.unique.trim_whitespace
+ * @plugin unique
+ */
+ trim_whitespace : false,
+ /**
* A callback executed in the instance's scope when a new node is created and the name is already taken, the two arguments are the conflicting name and the counter. The default will produce results like `New node (2)`.
* @name $.jstree.defaults.unique.duplicate
* @plugin unique
*/
duplicate : function (name, counter) {
@@ -8219,20 +8371,36 @@
par = par && par.id ? par : this.get_node(par);
if(!par || !par.children) { return true; }
var n = chk === "rename_node" ? pos : obj.text,
c = [],
s = this.settings.unique.case_sensitive,
- m = this._model.data, i, j;
+ w = this.settings.unique.trim_whitespace,
+ m = this._model.data, i, j, t;
for(i = 0, j = par.children.length; i < j; i++) {
- c.push(s ? m[par.children[i]].text : m[par.children[i]].text.toLowerCase());
+ t = m[par.children[i]].text;
+ if (!s) {
+ t = t.toLowerCase();
+ }
+ if (w) {
+ t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
+ }
+ c.push(t);
}
if(!s) { n = n.toLowerCase(); }
+ if (w) { n = n.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); }
switch(chk) {
case "delete_node":
return true;
case "rename_node":
- i = ($.inArray(n, c) === -1 || (obj.text && obj.text[ s ? 'toString' : 'toLowerCase']() === n));
+ t = obj.text || '';
+ if (!s) {
+ t = t.toLowerCase();
+ }
+ if (w) {
+ t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
+ }
+ i = ($.inArray(n, c) === -1 || (obj.text && t === n));
if(!i) {
this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_01', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };
}
return i;
case "create_node":
@@ -8268,19 +8436,40 @@
pos = pos === undefined ? "last" : pos;
if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {
return parent.create_node.call(this, par, node, pos, callback, is_loaded);
}
if(!node) { node = {}; }
- var tmp, n, dpc, i, j, m = this._model.data, s = this.settings.unique.case_sensitive, cb = this.settings.unique.duplicate;
+ var tmp, n, dpc, i, j, m = this._model.data, s = this.settings.unique.case_sensitive, w = this.settings.unique.trim_whitespace, cb = this.settings.unique.duplicate, t;
n = tmp = this.get_string('New node');
dpc = [];
for(i = 0, j = par.children.length; i < j; i++) {
- dpc.push(s ? m[par.children[i]].text : m[par.children[i]].text.toLowerCase());
+ t = m[par.children[i]].text;
+ if (!s) {
+ t = t.toLowerCase();
+ }
+ if (w) {
+ t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
+ }
+ dpc.push(t);
}
i = 1;
- while($.inArray(s ? n : n.toLowerCase(), dpc) !== -1) {
+ t = n;
+ if (!s) {
+ t = t.toLowerCase();
+ }
+ if (w) {
+ t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
+ }
+ while($.inArray(t, dpc) !== -1) {
n = cb.call(this, tmp, (++i)).toString();
+ t = n;
+ if (!s) {
+ t = t.toLowerCase();
+ }
+ if (w) {
+ t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
+ }
}
node.text = n;
}
return parent.create_node.call(this, par, node, pos, callback, is_loaded);
};
@@ -8393,11 +8582,11 @@
return obj;
};
};
// include the wholerow plugin by default
// $.jstree.defaults.plugins.push("wholerow");
- if(document.registerElement && Object && Object.create) {
+ if(window.customElements && Object && Object.create) {
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function () {
var c = { core : {}, plugins : [] }, i;
for(i in $.jstree.plugins) {
if($.jstree.plugins.hasOwnProperty(i) && this.attributes[i]) {
@@ -8414,10 +8603,10 @@
}
$(this).jstree(c);
};
// proto.attributeChangedCallback = function (name, previous, value) { };
try {
- document.registerElement("vakata-jstree", { prototype: proto });
- } catch(ignore) { }
+ window.customElements.define("vakata-jstree", function() {}, { prototype: proto });
+ } catch (ignore) { }
}
}));
\ No newline at end of file