PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / 1.4.7
JetBackup – Backup, Restore & Migrate v1.4.7
3.1.22.4 3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / public / js / jstree.checkbox.js
backup / public / js Last commit date
Chart.bundle.min.js 5 years ago bootstrap-switch.min.js 5 years ago bootstrap.min.js 5 years ago deactivationSurvey.js 5 years ago jquery-ui.js 5 years ago jquery.fileupload.js 5 years ago jquery.iframe-transport.js 5 years ago jquery.rateyo.js 5 years ago jstree.checkbox.js 5 years ago jstree.min.js 5 years ago jstree.types.js 5 years ago jstree.wholerow.js 5 years ago less.min.js 5 years ago main.js 5 years ago popup.js 5 years ago sgNoticeDismiss.js 5 years ago sgbackup.js 5 years ago sgcloud.js 5 years ago sgdiscount.js 5 years ago sglicense.js 5 years ago sglogin.js 5 years ago sgrequesthandler.js 5 years ago sgrequesthandler.wordpress.js 5 years ago sgschedule.js 5 years ago sgsettings.js 5 years ago
jstree.checkbox.js
955 lines
1 /**
2 * ### Checkbox plugin
3 *
4 * This plugin renders checkbox icons in front of each node, making multiple selection much easier.
5 * It also supports tri-state behavior, meaning that if a node has a few of its children checked it will be rendered as undetermined, and state will be propagated up.
6 */
7 /*globals jQuery, define, exports, require, document */
8 (function (factory) {
9 "use strict";
10 if (typeof define === 'function' && define.amd) {
11 define('jstree.checkbox', ['jquery','jstree'], factory);
12 }
13 else if(typeof exports === 'object') {
14 factory(require('jquery'), require('jstree'));
15 }
16 else {
17 factory(jQuery, jQuery.jstree);
18 }
19 }(function ($, jstree, undefined) {
20 "use strict";
21
22 if($.jstree.plugins.checkbox) { return; }
23
24 var _i = document.createElement('I');
25 _i.className = 'jstree-icon jstree-checkbox';
26 _i.setAttribute('role', 'presentation');
27 /**
28 * stores all defaults for the checkbox plugin
29 * @name $.jstree.defaults.checkbox
30 * @plugin checkbox
31 */
32 $.jstree.defaults.checkbox = {
33 /**
34 * a boolean indicating if checkboxes should be visible (can be changed at a later time using `show_checkboxes()` and `hide_checkboxes`). Defaults to `true`.
35 * @name $.jstree.defaults.checkbox.visible
36 * @plugin checkbox
37 */
38 visible : true,
39 /**
40 * a boolean indicating if checkboxes should cascade down and have an undetermined state. Defaults to `true`.
41 * @name $.jstree.defaults.checkbox.three_state
42 * @plugin checkbox
43 */
44 three_state : true,
45 /**
46 * a boolean indicating if clicking anywhere on the node should act as clicking on the checkbox. Defaults to `true`.
47 * @name $.jstree.defaults.checkbox.whole_node
48 * @plugin checkbox
49 */
50 whole_node : true,
51 /**
52 * a boolean indicating if the selected style of a node should be kept, or removed. Defaults to `true`.
53 * @name $.jstree.defaults.checkbox.keep_selected_style
54 * @plugin checkbox
55 */
56 keep_selected_style : true,
57 /**
58 * This setting controls how cascading and undetermined nodes are applied.
59 * If 'up' is in the string - cascading up is enabled, if 'down' is in the string - cascading down is enabled, if 'undetermined' is in the string - undetermined nodes will be used.
60 * If `three_state` is set to `true` this setting is automatically set to 'up+down+undetermined'. Defaults to ''.
61 * @name $.jstree.defaults.checkbox.cascade
62 * @plugin checkbox
63 */
64 cascade : '',
65 /**
66 * This setting controls if checkbox are bound to the general tree selection or to an internal array maintained by the checkbox plugin. Defaults to `true`, only set to `false` if you know exactly what you are doing.
67 * @name $.jstree.defaults.checkbox.tie_selection
68 * @plugin checkbox
69 */
70 tie_selection : true,
71
72 /**
73 * This setting controls if cascading down affects disabled checkboxes
74 * @name $.jstree.defaults.checkbox.cascade_to_disabled
75 * @plugin checkbox
76 */
77 cascade_to_disabled : true,
78
79 /**
80 * This setting controls if cascading down affects hidden checkboxes
81 * @name $.jstree.defaults.checkbox.cascade_to_hidden
82 * @plugin checkbox
83 */
84 cascade_to_hidden : true
85 };
86 $.jstree.plugins.checkbox = function (options, parent) {
87 this.bind = function () {
88 parent.bind.call(this);
89 this._data.checkbox.uto = false;
90 this._data.checkbox.selected = [];
91 if(this.settings.checkbox.three_state) {
92 this.settings.checkbox.cascade = 'up+down+undetermined';
93 }
94 this.element
95 .on("init.jstree", $.proxy(function () {
96 this._data.checkbox.visible = this.settings.checkbox.visible;
97 if(!this.settings.checkbox.keep_selected_style) {
98 this.element.addClass('jstree-checkbox-no-clicked');
99 }
100 if(this.settings.checkbox.tie_selection) {
101 this.element.addClass('jstree-checkbox-selection');
102 }
103 }, this))
104 .on("loading.jstree", $.proxy(function () {
105 this[ this._data.checkbox.visible ? 'show_checkboxes' : 'hide_checkboxes' ]();
106 }, this));
107 if(this.settings.checkbox.cascade.indexOf('undetermined') !== -1) {
108 this.element
109 .on('changed.jstree uncheck_node.jstree check_node.jstree uncheck_all.jstree check_all.jstree move_node.jstree copy_node.jstree redraw.jstree open_node.jstree', $.proxy(function () {
110 // only if undetermined is in setting
111 if(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); }
112 this._data.checkbox.uto = setTimeout($.proxy(this._undetermined, this), 50);
113 }, this));
114 }
115 if(!this.settings.checkbox.tie_selection) {
116 this.element
117 .on('model.jstree', $.proxy(function (e, data) {
118 var m = this._model.data,
119 p = m[data.parent],
120 dpc = data.nodes,
121 i, j;
122 for(i = 0, j = dpc.length; i < j; i++) {
123 m[dpc[i]].state.checked = m[dpc[i]].state.checked || (m[dpc[i]].original && m[dpc[i]].original.state && m[dpc[i]].original.state.checked);
124 if(m[dpc[i]].state.checked) {
125 this._data.checkbox.selected.push(dpc[i]);
126 }
127 }
128 }, this));
129 }
130 if(this.settings.checkbox.cascade.indexOf('up') !== -1 || this.settings.checkbox.cascade.indexOf('down') !== -1) {
131 this.element
132 .on('model.jstree', $.proxy(function (e, data) {
133 var m = this._model.data,
134 p = m[data.parent],
135 dpc = data.nodes,
136 chd = [],
137 c, i, j, k, l, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection;
138
139 if(s.indexOf('down') !== -1) {
140 // apply down
141 if(p.state[ t ? 'selected' : 'checked' ]) {
142 for(i = 0, j = dpc.length; i < j; i++) {
143 m[dpc[i]].state[ t ? 'selected' : 'checked' ] = true;
144 }
145
146 this._data[ t ? 'core' : 'checkbox' ].selected = this._data[ t ? 'core' : 'checkbox' ].selected.concat(dpc);
147 }
148 else {
149 for(i = 0, j = dpc.length; i < j; i++) {
150 if(m[dpc[i]].state[ t ? 'selected' : 'checked' ]) {
151 for(k = 0, l = m[dpc[i]].children_d.length; k < l; k++) {
152 m[m[dpc[i]].children_d[k]].state[ t ? 'selected' : 'checked' ] = true;
153 }
154 this._data[ t ? 'core' : 'checkbox' ].selected = this._data[ t ? 'core' : 'checkbox' ].selected.concat(m[dpc[i]].children_d);
155 }
156 }
157 }
158 }
159
160 if(s.indexOf('up') !== -1) {
161 // apply up
162 for(i = 0, j = p.children_d.length; i < j; i++) {
163 if(!m[p.children_d[i]].children.length) {
164 chd.push(m[p.children_d[i]].parent);
165 }
166 }
167 chd = $.vakata.array_unique(chd);
168 for(k = 0, l = chd.length; k < l; k++) {
169 p = m[chd[k]];
170 while(p && p.id !== $.jstree.root) {
171 c = 0;
172 for(i = 0, j = p.children.length; i < j; i++) {
173 c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
174 }
175 if(c === j) {
176 p.state[ t ? 'selected' : 'checked' ] = true;
177 this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
178 tmp = this.get_node(p, true);
179 if(tmp && tmp.length) {
180 tmp.attr('aria-selected', true).children('.jstree-anchor').addClass( t ? 'jstree-clicked' : 'jstree-checked');
181 }
182 }
183 else {
184 break;
185 }
186 p = this.get_node(p.parent);
187 }
188 }
189 }
190
191 this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected);
192 }, this))
193 .on(this.settings.checkbox.tie_selection ? 'select_node.jstree' : 'check_node.jstree', $.proxy(function (e, data) {
194 var self = this,
195 obj = data.node,
196 m = this._model.data,
197 par = this.get_node(obj.parent),
198 i, j, c, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection,
199 sel = {}, cur = this._data[ t ? 'core' : 'checkbox' ].selected;
200
201 for (i = 0, j = cur.length; i < j; i++) {
202 sel[cur[i]] = true;
203 }
204
205 // apply down
206 if(s.indexOf('down') !== -1) {
207 //this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected.concat(obj.children_d));
208 var selectedIds = this._cascade_new_checked_state(obj.id, true);
209 obj.children_d.concat(obj.id).forEach(function(id) {
210 if (selectedIds.indexOf(id) > -1) {
211 sel[id] = true;
212 }
213 else {
214 delete sel[id];
215 }
216 });
217 }
218
219 // apply up
220 if(s.indexOf('up') !== -1) {
221 while(par && par.id !== $.jstree.root) {
222 c = 0;
223 for(i = 0, j = par.children.length; i < j; i++) {
224 c += m[par.children[i]].state[ t ? 'selected' : 'checked' ];
225 }
226 if(c === j) {
227 par.state[ t ? 'selected' : 'checked' ] = true;
228 sel[par.id] = true;
229 //this._data[ t ? 'core' : 'checkbox' ].selected.push(par.id);
230 tmp = this.get_node(par, true);
231 if(tmp && tmp.length) {
232 tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
233 }
234 }
235 else {
236 break;
237 }
238 par = this.get_node(par.parent);
239 }
240 }
241
242 cur = [];
243 for (i in sel) {
244 if (sel.hasOwnProperty(i)) {
245 cur.push(i);
246 }
247 }
248 this._data[ t ? 'core' : 'checkbox' ].selected = cur;
249 }, this))
250 .on(this.settings.checkbox.tie_selection ? 'deselect_all.jstree' : 'uncheck_all.jstree', $.proxy(function (e, data) {
251 var obj = this.get_node($.jstree.root),
252 m = this._model.data,
253 i, j, tmp;
254 for(i = 0, j = obj.children_d.length; i < j; i++) {
255 tmp = m[obj.children_d[i]];
256 if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {
257 tmp.original.state.undetermined = false;
258 }
259 }
260 }, this))
261 .on(this.settings.checkbox.tie_selection ? 'deselect_node.jstree' : 'uncheck_node.jstree', $.proxy(function (e, data) {
262 var self = this,
263 obj = data.node,
264 dom = this.get_node(obj, true),
265 i, j, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection,
266 cur = this._data[ t ? 'core' : 'checkbox' ].selected, sel = {},
267 stillSelectedIds = [],
268 allIds = obj.children_d.concat(obj.id);
269
270 // apply down
271 if(s.indexOf('down') !== -1) {
272 var selectedIds = this._cascade_new_checked_state(obj.id, false);
273
274 cur = cur.filter(function(id) {
275 return allIds.indexOf(id) === -1 || selectedIds.indexOf(id) > -1;
276 });
277 }
278
279 // only apply up if cascade up is enabled and if this node is not selected
280 // (if all child nodes are disabled and cascade_to_disabled === false then this node will till be selected).
281 if(s.indexOf('up') !== -1 && cur.indexOf(obj.id) === -1) {
282 for(i = 0, j = obj.parents.length; i < j; i++) {
283 tmp = this._model.data[obj.parents[i]];
284 tmp.state[ t ? 'selected' : 'checked' ] = false;
285 if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {
286 tmp.original.state.undetermined = false;
287 }
288 tmp = this.get_node(obj.parents[i], true);
289 if(tmp && tmp.length) {
290 tmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
291 }
292 }
293
294 cur = cur.filter(function(id) {
295 return obj.parents.indexOf(id) === -1;
296 });
297 }
298
299 this._data[ t ? 'core' : 'checkbox' ].selected = cur;
300 }, this));
301 }
302 if(this.settings.checkbox.cascade.indexOf('up') !== -1) {
303 this.element
304 .on('delete_node.jstree', $.proxy(function (e, data) {
305 // apply up (whole handler)
306 var p = this.get_node(data.parent),
307 m = this._model.data,
308 i, j, c, tmp, t = this.settings.checkbox.tie_selection;
309 while(p && p.id !== $.jstree.root && !p.state[ t ? 'selected' : 'checked' ]) {
310 c = 0;
311 for(i = 0, j = p.children.length; i < j; i++) {
312 c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
313 }
314 if(j > 0 && c === j) {
315 p.state[ t ? 'selected' : 'checked' ] = true;
316 this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
317 tmp = this.get_node(p, true);
318 if(tmp && tmp.length) {
319 tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
320 }
321 }
322 else {
323 break;
324 }
325 p = this.get_node(p.parent);
326 }
327 }, this))
328 .on('move_node.jstree', $.proxy(function (e, data) {
329 // apply up (whole handler)
330 var is_multi = data.is_multi,
331 old_par = data.old_parent,
332 new_par = this.get_node(data.parent),
333 m = this._model.data,
334 p, c, i, j, tmp, t = this.settings.checkbox.tie_selection;
335 if(!is_multi) {
336 p = this.get_node(old_par);
337 while(p && p.id !== $.jstree.root && !p.state[ t ? 'selected' : 'checked' ]) {
338 c = 0;
339 for(i = 0, j = p.children.length; i < j; i++) {
340 c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
341 }
342 if(j > 0 && c === j) {
343 p.state[ t ? 'selected' : 'checked' ] = true;
344 this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
345 tmp = this.get_node(p, true);
346 if(tmp && tmp.length) {
347 tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
348 }
349 }
350 else {
351 break;
352 }
353 p = this.get_node(p.parent);
354 }
355 }
356 p = new_par;
357 while(p && p.id !== $.jstree.root) {
358 c = 0;
359 for(i = 0, j = p.children.length; i < j; i++) {
360 c += m[p.children[i]].state[ t ? 'selected' : 'checked' ];
361 }
362 if(c === j) {
363 if(!p.state[ t ? 'selected' : 'checked' ]) {
364 p.state[ t ? 'selected' : 'checked' ] = true;
365 this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);
366 tmp = this.get_node(p, true);
367 if(tmp && tmp.length) {
368 tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
369 }
370 }
371 }
372 else {
373 if(p.state[ t ? 'selected' : 'checked' ]) {
374 p.state[ t ? 'selected' : 'checked' ] = false;
375 this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_remove_item(this._data[ t ? 'core' : 'checkbox' ].selected, p.id);
376 tmp = this.get_node(p, true);
377 if(tmp && tmp.length) {
378 tmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
379 }
380 }
381 else {
382 break;
383 }
384 }
385 p = this.get_node(p.parent);
386 }
387 }, this));
388 }
389 };
390
391 /**
392 * set the undetermined state where and if necessary. Used internally.
393 * @private
394 * @name _undetermined()
395 * @plugin checkbox
396 */
397 this._undetermined = function () {
398 if(this.element === null) { return; }
399 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;
400 for(i = 0, j = s.length; i < j; i++) {
401 if(m[s[i]] && m[s[i]].parents) {
402 for(k = 0, l = m[s[i]].parents.length; k < l; k++) {
403 if(o[m[s[i]].parents[k]] !== undefined) {
404 break;
405 }
406 if(m[s[i]].parents[k] !== $.jstree.root) {
407 o[m[s[i]].parents[k]] = true;
408 p.push(m[s[i]].parents[k]);
409 }
410 }
411 }
412 }
413 // attempt for server side undetermined state
414 this.element.find('.jstree-closed').not(':has(.jstree-children)')
415 .each(function () {
416 var tmp = tt.get_node(this), tmp2;
417
418 if(!tmp) { return; }
419
420 if(!tmp.state.loaded) {
421 if(tmp.original && tmp.original.state && tmp.original.state.undetermined && tmp.original.state.undetermined === true) {
422 if(o[tmp.id] === undefined && tmp.id !== $.jstree.root) {
423 o[tmp.id] = true;
424 p.push(tmp.id);
425 }
426 for(k = 0, l = tmp.parents.length; k < l; k++) {
427 if(o[tmp.parents[k]] === undefined && tmp.parents[k] !== $.jstree.root) {
428 o[tmp.parents[k]] = true;
429 p.push(tmp.parents[k]);
430 }
431 }
432 }
433 }
434 else {
435 for(i = 0, j = tmp.children_d.length; i < j; i++) {
436 tmp2 = m[tmp.children_d[i]];
437 if(!tmp2.state.loaded && tmp2.original && tmp2.original.state && tmp2.original.state.undetermined && tmp2.original.state.undetermined === true) {
438 if(o[tmp2.id] === undefined && tmp2.id !== $.jstree.root) {
439 o[tmp2.id] = true;
440 p.push(tmp2.id);
441 }
442 for(k = 0, l = tmp2.parents.length; k < l; k++) {
443 if(o[tmp2.parents[k]] === undefined && tmp2.parents[k] !== $.jstree.root) {
444 o[tmp2.parents[k]] = true;
445 p.push(tmp2.parents[k]);
446 }
447 }
448 }
449 }
450 }
451 });
452
453 this.element.find('.jstree-undetermined').removeClass('jstree-undetermined');
454 for(i = 0, j = p.length; i < j; i++) {
455 if(!m[p[i]].state[ t ? 'selected' : 'checked' ]) {
456 s = this.get_node(p[i], true);
457 if(s && s.length) {
458 s.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-undetermined');
459 }
460 }
461 }
462 };
463 this.redraw_node = function(obj, deep, is_callback, force_render) {
464 obj = parent.redraw_node.apply(this, arguments);
465 if(obj) {
466 var i, j, tmp = null, icon = null;
467 for(i = 0, j = obj.childNodes.length; i < j; i++) {
468 if(obj.childNodes[i] && obj.childNodes[i].className && obj.childNodes[i].className.indexOf("jstree-anchor") !== -1) {
469 tmp = obj.childNodes[i];
470 break;
471 }
472 }
473 if(tmp) {
474 if(!this.settings.checkbox.tie_selection && this._model.data[obj.id].state.checked) { tmp.className += ' jstree-checked'; }
475 icon = _i.cloneNode(false);
476 if(this._model.data[obj.id].state.checkbox_disabled) { icon.className += ' jstree-checkbox-disabled'; }
477 tmp.insertBefore(icon, tmp.childNodes[0]);
478 }
479 }
480 if(!is_callback && this.settings.checkbox.cascade.indexOf('undetermined') !== -1) {
481 if(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); }
482 this._data.checkbox.uto = setTimeout($.proxy(this._undetermined, this), 50);
483 }
484 return obj;
485 };
486 /**
487 * show the node checkbox icons
488 * @name show_checkboxes()
489 * @plugin checkbox
490 */
491 this.show_checkboxes = function () { this._data.core.themes.checkboxes = true; this.get_container_ul().removeClass("jstree-no-checkboxes"); };
492 /**
493 * hide the node checkbox icons
494 * @name hide_checkboxes()
495 * @plugin checkbox
496 */
497 this.hide_checkboxes = function () { this._data.core.themes.checkboxes = false; this.get_container_ul().addClass("jstree-no-checkboxes"); };
498 /**
499 * toggle the node icons
500 * @name toggle_checkboxes()
501 * @plugin checkbox
502 */
503 this.toggle_checkboxes = function () { if(this._data.core.themes.checkboxes) { this.hide_checkboxes(); } else { this.show_checkboxes(); } };
504 /**
505 * checks if a node is in an undetermined state
506 * @name is_undetermined(obj)
507 * @param {mixed} obj
508 * @return {Boolean}
509 */
510 this.is_undetermined = function (obj) {
511 obj = this.get_node(obj);
512 var s = this.settings.checkbox.cascade, i, j, t = this.settings.checkbox.tie_selection, d = this._data[ t ? 'core' : 'checkbox' ].selected, m = this._model.data;
513 if(!obj || obj.state[ t ? 'selected' : 'checked' ] === true || s.indexOf('undetermined') === -1 || (s.indexOf('down') === -1 && s.indexOf('up') === -1)) {
514 return false;
515 }
516 if(!obj.state.loaded && obj.original.state.undetermined === true) {
517 return true;
518 }
519 for(i = 0, j = obj.children_d.length; i < j; i++) {
520 if($.inArray(obj.children_d[i], d) !== -1 || (!m[obj.children_d[i]].state.loaded && m[obj.children_d[i]].original.state.undetermined)) {
521 return true;
522 }
523 }
524 return false;
525 };
526 /**
527 * disable a node's checkbox
528 * @name disable_checkbox(obj)
529 * @param {mixed} obj an array can be used too
530 * @trigger disable_checkbox.jstree
531 * @plugin checkbox
532 */
533 this.disable_checkbox = function (obj) {
534 var t1, t2, dom;
535 if($.isArray(obj)) {
536 obj = obj.slice();
537 for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
538 this.disable_checkbox(obj[t1]);
539 }
540 return true;
541 }
542 obj = this.get_node(obj);
543 if(!obj || obj.id === $.jstree.root) {
544 return false;
545 }
546 dom = this.get_node(obj, true);
547 if(!obj.state.checkbox_disabled) {
548 obj.state.checkbox_disabled = true;
549 if(dom && dom.length) {
550 dom.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-checkbox-disabled');
551 }
552 /**
553 * triggered when an node's checkbox is disabled
554 * @event
555 * @name disable_checkbox.jstree
556 * @param {Object} node
557 * @plugin checkbox
558 */
559 this.trigger('disable_checkbox', { 'node' : obj });
560 }
561 };
562 /**
563 * enable a node's checkbox
564 * @name disable_checkbox(obj)
565 * @param {mixed} obj an array can be used too
566 * @trigger enable_checkbox.jstree
567 * @plugin checkbox
568 */
569 this.enable_checkbox = function (obj) {
570 var t1, t2, dom;
571 if($.isArray(obj)) {
572 obj = obj.slice();
573 for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
574 this.enable_checkbox(obj[t1]);
575 }
576 return true;
577 }
578 obj = this.get_node(obj);
579 if(!obj || obj.id === $.jstree.root) {
580 return false;
581 }
582 dom = this.get_node(obj, true);
583 if(obj.state.checkbox_disabled) {
584 obj.state.checkbox_disabled = false;
585 if(dom && dom.length) {
586 dom.children('.jstree-anchor').children('.jstree-checkbox').removeClass('jstree-checkbox-disabled');
587 }
588 /**
589 * triggered when an node's checkbox is enabled
590 * @event
591 * @name enable_checkbox.jstree
592 * @param {Object} node
593 * @plugin checkbox
594 */
595 this.trigger('enable_checkbox', { 'node' : obj });
596 }
597 };
598
599 this.activate_node = function (obj, e) {
600 if($(e.target).hasClass('jstree-checkbox-disabled')) {
601 return false;
602 }
603 if(this.settings.checkbox.tie_selection && (this.settings.checkbox.whole_node || $(e.target).hasClass('jstree-checkbox'))) {
604 e.ctrlKey = true;
605 }
606 if(this.settings.checkbox.tie_selection || (!this.settings.checkbox.whole_node && !$(e.target).hasClass('jstree-checkbox'))) {
607 return parent.activate_node.call(this, obj, e);
608 }
609 if(this.is_disabled(obj)) {
610 return false;
611 }
612 if(this.is_checked(obj)) {
613 this.uncheck_node(obj, e);
614 }
615 else {
616 this.check_node(obj, e);
617 }
618 this.trigger('activate_node', { 'node' : this.get_node(obj) });
619 };
620
621 /**
622 * Unchecks a node and all its descendants. This function does NOT affect hidden and disabled nodes (or their descendants).
623 * However if these unaffected nodes are already selected their ids will be included in the returned array.
624 * @param id
625 * @param checkedState
626 * @returns {Array} Array of all node id's (in this tree branch) that are checked.
627 */
628 this._cascade_new_checked_state = function(id, checkedState) {
629 var self = this;
630 var t = this.settings.checkbox.tie_selection;
631 var node = this._model.data[id];
632 var selectedNodeIds = [];
633 var selectedChildrenIds = [];
634
635 if (
636 (this.settings.checkbox.cascade_to_disabled || !node.state.disabled) &&
637 (this.settings.checkbox.cascade_to_hidden || !node.state.hidden)
638 ) {
639 //First try and check/uncheck the children
640 if (node.children) {
641 node.children.forEach(function(childId) {
642 var selectedChildIds = self._cascade_new_checked_state(childId, checkedState);
643 selectedNodeIds = selectedNodeIds.concat(selectedChildIds);
644 if (selectedChildIds.indexOf(childId) > -1) {
645 selectedChildrenIds.push(childId);
646 }
647 });
648 }
649
650 var dom = self.get_node(node, true);
651
652 //A node's state is undetermined if some but not all of it's children are checked/selected .
653 var undetermined = selectedChildrenIds.length > 0 && selectedChildrenIds.length < node.children.length;
654
655 if(node.original && node.original.state && node.original.state.undetermined) {
656 node.original.state.undetermined = undetermined;
657 }
658
659 //If a node is undetermined then remove selected class
660 if (undetermined) {
661 node.state[ t ? 'selected' : 'checked' ] = false;
662 dom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
663 }
664 //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),
665 //check the node and style it correctly.
666 else if (checkedState && selectedChildrenIds.length === node.children.length) {
667 node.state[ t ? 'selected' : 'checked' ] = checkedState;
668 selectedNodeIds.push(node.id);
669
670 dom.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');
671 }
672 else {
673 node.state[ t ? 'selected' : 'checked' ] = false;
674 dom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');
675 }
676 }
677 else {
678 var selectedChildIds = this.get_checked_descendants(id);
679
680 if (node.state[ t ? 'selected' : 'checked' ]) {
681 selectedChildIds.push(node.id);
682 }
683
684 selectedNodeIds = selectedNodeIds.concat(selectedChildIds);
685 }
686
687 return selectedNodeIds;
688 };
689
690 /**
691 * Gets ids of nodes selected in branch (of tree) specified by id (does not include the node specified by id)
692 * @param id
693 */
694 this.get_checked_descendants = function(id) {
695 var self = this;
696 var t = self.settings.checkbox.tie_selection;
697 var node = self._model.data[id];
698
699 return node.children_d.filter(function(_id) {
700 return self._model.data[_id].state[ t ? 'selected' : 'checked' ];
701 });
702 };
703
704 /**
705 * check a node (only if tie_selection in checkbox settings is false, otherwise select_node will be called internally)
706 * @name check_node(obj)
707 * @param {mixed} obj an array can be used to check multiple nodes
708 * @trigger check_node.jstree
709 * @plugin checkbox
710 */
711 this.check_node = function (obj, e) {
712 if(this.settings.checkbox.tie_selection) { return this.select_node(obj, false, true, e); }
713 var dom, t1, t2, th;
714 if($.isArray(obj)) {
715 obj = obj.slice();
716 for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
717 this.check_node(obj[t1], e);
718 }
719 return true;
720 }
721 obj = this.get_node(obj);
722 if(!obj || obj.id === $.jstree.root) {
723 return false;
724 }
725 dom = this.get_node(obj, true);
726 if(!obj.state.checked) {
727 obj.state.checked = true;
728 this._data.checkbox.selected.push(obj.id);
729 if(dom && dom.length) {
730 dom.children('.jstree-anchor').addClass('jstree-checked');
731 }
732 /**
733 * triggered when an node is checked (only if tie_selection in checkbox settings is false)
734 * @event
735 * @name check_node.jstree
736 * @param {Object} node
737 * @param {Array} selected the current selection
738 * @param {Object} event the event (if any) that triggered this check_node
739 * @plugin checkbox
740 */
741 this.trigger('check_node', { 'node' : obj, 'selected' : this._data.checkbox.selected, 'event' : e });
742 }
743 };
744 /**
745 * uncheck a node (only if tie_selection in checkbox settings is false, otherwise deselect_node will be called internally)
746 * @name uncheck_node(obj)
747 * @param {mixed} obj an array can be used to uncheck multiple nodes
748 * @trigger uncheck_node.jstree
749 * @plugin checkbox
750 */
751 this.uncheck_node = function (obj, e) {
752 if(this.settings.checkbox.tie_selection) { return this.deselect_node(obj, false, e); }
753 var t1, t2, dom;
754 if($.isArray(obj)) {
755 obj = obj.slice();
756 for(t1 = 0, t2 = obj.length; t1 < t2; t1++) {
757 this.uncheck_node(obj[t1], e);
758 }
759 return true;
760 }
761 obj = this.get_node(obj);
762 if(!obj || obj.id === $.jstree.root) {
763 return false;
764 }
765 dom = this.get_node(obj, true);
766 if(obj.state.checked) {
767 obj.state.checked = false;
768 this._data.checkbox.selected = $.vakata.array_remove_item(this._data.checkbox.selected, obj.id);
769 if(dom.length) {
770 dom.children('.jstree-anchor').removeClass('jstree-checked');
771 }
772 /**
773 * triggered when an node is unchecked (only if tie_selection in checkbox settings is false)
774 * @event
775 * @name uncheck_node.jstree
776 * @param {Object} node
777 * @param {Array} selected the current selection
778 * @param {Object} event the event (if any) that triggered this uncheck_node
779 * @plugin checkbox
780 */
781 this.trigger('uncheck_node', { 'node' : obj, 'selected' : this._data.checkbox.selected, 'event' : e });
782 }
783 };
784
785 /**
786 * checks all nodes in the tree (only if tie_selection in checkbox settings is false, otherwise select_all will be called internally)
787 * @name check_all()
788 * @trigger check_all.jstree, changed.jstree
789 * @plugin checkbox
790 */
791 this.check_all = function () {
792 if(this.settings.checkbox.tie_selection) { return this.select_all(); }
793 var tmp = this._data.checkbox.selected.concat([]), i, j;
794 this._data.checkbox.selected = this._model.data[$.jstree.root].children_d.concat();
795 for(i = 0, j = this._data.checkbox.selected.length; i < j; i++) {
796 if(this._model.data[this._data.checkbox.selected[i]]) {
797 this._model.data[this._data.checkbox.selected[i]].state.checked = true;
798 }
799 }
800 this.redraw(true);
801 /**
802 * triggered when all nodes are checked (only if tie_selection in checkbox settings is false)
803 * @event
804 * @name check_all.jstree
805 * @param {Array} selected the current selection
806 * @plugin checkbox
807 */
808 this.trigger('check_all', { 'selected' : this._data.checkbox.selected });
809 };
810 /**
811 * uncheck all checked nodes (only if tie_selection in checkbox settings is false, otherwise deselect_all will be called internally)
812 * @name uncheck_all()
813 * @trigger uncheck_all.jstree
814 * @plugin checkbox
815 */
816 this.uncheck_all = function () {
817 if(this.settings.checkbox.tie_selection) { return this.deselect_all(); }
818 var tmp = this._data.checkbox.selected.concat([]), i, j;
819 for(i = 0, j = this._data.checkbox.selected.length; i < j; i++) {
820 if(this._model.data[this._data.checkbox.selected[i]]) {
821 this._model.data[this._data.checkbox.selected[i]].state.checked = false;
822 }
823 }
824 this._data.checkbox.selected = [];
825 this.element.find('.jstree-checked').removeClass('jstree-checked');
826 /**
827 * triggered when all nodes are unchecked (only if tie_selection in checkbox settings is false)
828 * @event
829 * @name uncheck_all.jstree
830 * @param {Object} node the previous selection
831 * @param {Array} selected the current selection
832 * @plugin checkbox
833 */
834 this.trigger('uncheck_all', { 'selected' : this._data.checkbox.selected, 'node' : tmp });
835 };
836 /**
837 * checks if a node is checked (if tie_selection is on in the settings this function will return the same as is_selected)
838 * @name is_checked(obj)
839 * @param {mixed} obj
840 * @return {Boolean}
841 * @plugin checkbox
842 */
843 this.is_checked = function (obj) {
844 if(this.settings.checkbox.tie_selection) { return this.is_selected(obj); }
845 obj = this.get_node(obj);
846 if(!obj || obj.id === $.jstree.root) { return false; }
847 return obj.state.checked;
848 };
849 /**
850 * get an array of all checked nodes (if tie_selection is on in the settings this function will return the same as get_selected)
851 * @name get_checked([full])
852 * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
853 * @return {Array}
854 * @plugin checkbox
855 */
856 this.get_checked = function (full) {
857 if(this.settings.checkbox.tie_selection) { return this.get_selected(full); }
858 return full ? $.map(this._data.checkbox.selected, $.proxy(function (i) { return this.get_node(i); }, this)) : this._data.checkbox.selected;
859 };
860 /**
861 * 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)
862 * @name get_top_checked([full])
863 * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
864 * @return {Array}
865 * @plugin checkbox
866 */
867 this.get_top_checked = function (full) {
868 if(this.settings.checkbox.tie_selection) { return this.get_top_selected(full); }
869 var tmp = this.get_checked(true),
870 obj = {}, i, j, k, l;
871 for(i = 0, j = tmp.length; i < j; i++) {
872 obj[tmp[i].id] = tmp[i];
873 }
874 for(i = 0, j = tmp.length; i < j; i++) {
875 for(k = 0, l = tmp[i].children_d.length; k < l; k++) {
876 if(obj[tmp[i].children_d[k]]) {
877 delete obj[tmp[i].children_d[k]];
878 }
879 }
880 }
881 tmp = [];
882 for(i in obj) {
883 if(obj.hasOwnProperty(i)) {
884 tmp.push(i);
885 }
886 }
887 return full ? $.map(tmp, $.proxy(function (i) { return this.get_node(i); }, this)) : tmp;
888 };
889 /**
890 * get an array of all bottom level checked nodes (ignoring selected parents) (if tie_selection is on in the settings this function will return the same as get_bottom_selected)
891 * @name get_bottom_checked([full])
892 * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned
893 * @return {Array}
894 * @plugin checkbox
895 */
896 this.get_bottom_checked = function (full) {
897 if(this.settings.checkbox.tie_selection) { return this.get_bottom_selected(full); }
898 var tmp = this.get_checked(true),
899 obj = [], i, j;
900 for(i = 0, j = tmp.length; i < j; i++) {
901 if(!tmp[i].children.length) {
902 obj.push(tmp[i].id);
903 }
904 }
905 return full ? $.map(obj, $.proxy(function (i) { return this.get_node(i); }, this)) : obj;
906 };
907 this.load_node = function (obj, callback) {
908 var k, l, i, j, c, tmp;
909 if(!$.isArray(obj) && !this.settings.checkbox.tie_selection) {
910 tmp = this.get_node(obj);
911 if(tmp && tmp.state.loaded) {
912 for(k = 0, l = tmp.children_d.length; k < l; k++) {
913 if(this._model.data[tmp.children_d[k]].state.checked) {
914 c = true;
915 this._data.checkbox.selected = $.vakata.array_remove_item(this._data.checkbox.selected, tmp.children_d[k]);
916 }
917 }
918 }
919 }
920 return parent.load_node.apply(this, arguments);
921 };
922 this.get_state = function () {
923 var state = parent.get_state.apply(this, arguments);
924 if(this.settings.checkbox.tie_selection) { return state; }
925 state.checkbox = this._data.checkbox.selected.slice();
926 return state;
927 };
928 this.set_state = function (state, callback) {
929 var res = parent.set_state.apply(this, arguments);
930 if(res && state.checkbox) {
931 if(!this.settings.checkbox.tie_selection) {
932 this.uncheck_all();
933 var _this = this;
934 $.each(state.checkbox, function (i, v) {
935 _this.check_node(v);
936 });
937 }
938 delete state.checkbox;
939 this.set_state(state, callback);
940 return false;
941 }
942 return res;
943 };
944 this.refresh = function (skip_loading, forget_state) {
945 if(!this.settings.checkbox.tie_selection) {
946 this._data.checkbox.selected = [];
947 }
948 return parent.refresh.apply(this, arguments);
949 };
950 };
951
952 // include the checkbox plugin by default
953 // $.jstree.defaults.plugins.push("checkbox");
954 }));
955