blob: 8579d8e73c41603c2e3241cac182dff4f08ead26 [file] [log] [blame]
Timoney, Daniel (dt5972)324ee362017-02-15 10:37:53 -05001/*
2 * jQuery treegrid Plugin 0.2.0
3 * https://github.com/maxazan/jquery-treegrid
4 *
5 * Copyright 2013, Pomazan Max
6 * Licensed under the MIT licenses.
7 */
8(function($) {
9
10 var methods = {
11 /**
12 * Initialize tree
13 *
14 * @param {Object} options
15 * @returns {Object[]}
16 */
17 initTree: function(options) {
18 var settings = $.extend({}, this.treegrid.defaults, options);
19 return this.each(function() {
20 var $this = $(this);
21 $this.treegrid('setTreeContainer', $(this));
22 $this.treegrid('setSettings', settings);
23 settings.getRootNodes.apply(this, [$(this)]).treegrid('initNode', settings);
24 $this.treegrid('getRootNodes').treegrid('render');
25 });
26 },
27 /**
28 * Initialize node
29 *
30 * @param {Object} settings
31 * @returns {Object[]}
32 */
33 initNode: function(settings) {
34 return this.each(function() {
35 var $this = $(this);
36 $this.treegrid('setTreeContainer', settings.getTreeGridContainer.apply(this));
37 $this.treegrid('getChildNodes').treegrid('initNode', settings);
38 $this.treegrid('initExpander').treegrid('initIndent').treegrid('initEvents').treegrid('initState').treegrid('initChangeEvent').treegrid("initSettingsEvents");
39 });
40 },
41 initChangeEvent: function() {
42 var $this = $(this);
43 //Save state on change
44 $this.on("change", function() {
45 var $this = $(this);
46 $this.treegrid('render');
47 if ($this.treegrid('getSetting', 'saveState')) {
48 $this.treegrid('saveState');
49 }
50 });
51 return $this;
52 },
53 /**
54 * Initialize node events
55 *
56 * @returns {Node}
57 */
58 initEvents: function() {
59 var $this = $(this);
60 //Default behavior on collapse
61 $this.on("collapse", function() {
62 var $this = $(this);
63 $this.removeClass('treegrid-expanded');
64 $this.addClass('treegrid-collapsed');
65 });
66 //Default behavior on expand
67 $this.on("expand", function() {
68 var $this = $(this);
69 $this.removeClass('treegrid-collapsed');
70 $this.addClass('treegrid-expanded');
71 });
72
73 return $this;
74 },
75 /**
76 * Initialize events from settings
77 *
78 * @returns {Node}
79 */
80 initSettingsEvents: function() {
81 var $this = $(this);
82 //Save state on change
83 $this.on("change", function() {
84 var $this = $(this);
85 if (typeof($this.treegrid('getSetting', 'onChange')) === "function") {
86 $this.treegrid('getSetting', 'onChange').apply($this);
87 }
88 });
89 //Default behavior on collapse
90 $this.on("collapse", function() {
91 var $this = $(this);
92 if (typeof($this.treegrid('getSetting', 'onCollapse')) === "function") {
93 $this.treegrid('getSetting', 'onCollapse').apply($this);
94 }
95 });
96 //Default behavior on expand
97 $this.on("expand", function() {
98 var $this = $(this);
99 if (typeof($this.treegrid('getSetting', 'onExpand')) === "function") {
100 $this.treegrid('getSetting', 'onExpand').apply($this);
101 }
102
103 });
104
105 return $this;
106 },
107 /**
108 * Initialize expander for node
109 *
110 * @returns {Node}
111 */
112 initExpander: function() {
113 var $this = $(this);
114 var cell = $this.find('td').get($this.treegrid('getSetting', 'treeColumn'));
115 var tpl = $this.treegrid('getSetting', 'expanderTemplate');
116 var expander = $this.treegrid('getSetting', 'getExpander').apply(this);
117 if (expander) {
118 expander.remove();
119 }
120 $(tpl).prependTo(cell).click(function() {
121 $($(this).closest('tr')).treegrid('toggle');
122 });
123 return $this;
124 },
125 /**
126 * Initialize indent for node
127 *
128 * @returns {Node}
129 */
130 initIndent: function() {
131 var $this = $(this);
132 $this.find('.treegrid-indent').remove();
133 var tpl = $this.treegrid('getSetting', 'indentTemplate');
134 var expander = $this.find('.treegrid-expander');
135 var depth = $this.treegrid('getDepth');
136 for (var i = 0; i < depth; i++) {
137 $(tpl).insertBefore(expander);
138 }
139 return $this;
140 },
141 /**
142 * Initialise state of node
143 *
144 * @returns {Node}
145 */
146 initState: function() {
147 var $this = $(this);
148 if ($this.treegrid('getSetting', 'saveState') && !$this.treegrid('isFirstInit')) {
149 $this.treegrid('restoreState');
150 } else {
151 if ($this.treegrid('getSetting', 'initialState') === "expanded") {
152 $this.treegrid('expand');
153 } else {
154 $this.treegrid('collapse');
155 }
156 }
157 return $this;
158 },
159 /**
160 * Return true if this tree was never been initialised
161 *
162 * @returns {Boolean}
163 */
164 isFirstInit: function() {
165 var tree = $(this).treegrid('getTreeContainer');
166 if (tree.data('first_init') === undefined) {
167 tree.data('first_init', $.cookie(tree.treegrid('getSetting', 'saveStateName')) === undefined);
168 }
169 return tree.data('first_init');
170 },
171 /**
172 * Save state of current node
173 *
174 * @returns {Node}
175 */
176 saveState: function() {
177 var $this = $(this);
178 if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') {
179
180 var stateArrayString = $.cookie($this.treegrid('getSetting', 'saveStateName')) || '';
181 var stateArray = (stateArrayString === '' ? [] : stateArrayString.split(','));
182 var nodeId = $this.treegrid('getNodeId');
183
184 if ($this.treegrid('isExpanded')) {
185 if ($.inArray(nodeId, stateArray) === -1) {
186 stateArray.push(nodeId);
187 }
188 } else if ($this.treegrid('isCollapsed')) {
189 if ($.inArray(nodeId, stateArray) !== -1) {
190 stateArray.splice($.inArray(nodeId, stateArray), 1);
191 }
192 }
193 $.cookie($this.treegrid('getSetting', 'saveStateName'), stateArray.join(','));
194 }
195 return $this;
196 },
197 /**
198 * Restore state of current node.
199 *
200 * @returns {Node}
201 */
202 restoreState: function() {
203 var $this = $(this);
204 if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') {
205 var stateArray = $.cookie($this.treegrid('getSetting', 'saveStateName')).split(',');
206 if ($.inArray($this.treegrid('getNodeId'), stateArray) !== -1) {
207 $this.treegrid('expand');
208 } else {
209 $this.treegrid('collapse');
210 }
211
212 }
213 return $this;
214 },
215 /**
216 * Method return setting by name
217 *
218 * @param {type} name
219 * @returns {unresolved}
220 */
221 getSetting: function(name) {
222 if (!$(this).treegrid('getTreeContainer')) {
223 return null;
224 }
225 return $(this).treegrid('getTreeContainer').data('settings')[name];
226 },
227 /**
228 * Add new settings
229 *
230 * @param {Object} settings
231 */
232 setSettings: function(settings) {
233 $(this).treegrid('getTreeContainer').data('settings', settings);
234 },
235 /**
236 * Return tree container
237 *
238 * @returns {HtmlElement}
239 */
240 getTreeContainer: function() {
241 return $(this).data('treegrid');
242 },
243 /**
244 * Set tree container
245 *
246 * @param {HtmlE;ement} container
247 */
248 setTreeContainer: function(container) {
249 return $(this).data('treegrid', container);
250 },
251 /**
252 * Method return all root nodes of tree.
253 *
254 * Start init all child nodes from it.
255 *
256 * @returns {Array}
257 */
258 getRootNodes: function() {
259 return $(this).treegrid('getSetting', 'getRootNodes').apply(this, [$(this).treegrid('getTreeContainer')]);
260 },
261 /**
262 * Method return all nodes of tree.
263 *
264 * @returns {Array}
265 */
266 getAllNodes: function() {
267 return $(this).treegrid('getSetting', 'getAllNodes').apply(this, [$(this).treegrid('getTreeContainer')]);
268 },
269 /**
270 * Mthod return true if element is Node
271 *
272 * @returns {String}
273 */
274 isNode: function() {
275 return $(this).treegrid('getNodeId') !== null;
276 },
277 /**
278 * Mthod return id of node
279 *
280 * @returns {String}
281 */
282 getNodeId: function() {
283 if ($(this).treegrid('getSetting', 'getNodeId') === null) {
284 return null;
285 } else {
286 return $(this).treegrid('getSetting', 'getNodeId').apply(this);
287 }
288 },
289 /**
290 * Method return parent id of node or null if root node
291 *
292 * @returns {String}
293 */
294 getParentNodeId: function() {
295 return $(this).treegrid('getSetting', 'getParentNodeId').apply(this);
296 },
297 /**
298 * Method return parent node or null if root node
299 *
300 * @returns {Object[]}
301 */
302 getParentNode: function() {
303 if ($(this).treegrid('getParentNodeId') === null) {
304 return null;
305 } else {
306 return $(this).treegrid('getSetting', 'getNodeById').apply(this, [$(this).treegrid('getParentNodeId'), $(this).treegrid('getTreeContainer')]);
307 }
308 },
309 /**
310 * Method return array of child nodes or null if node is leaf
311 *
312 * @returns {Object[]}
313 */
314 getChildNodes: function() {
315 return $(this).treegrid('getSetting', 'getChildNodes').apply(this, [$(this).treegrid('getNodeId'), $(this).treegrid('getTreeContainer')]);
316 },
317 /**
318 * Method return depth of tree.
319 *
320 * This method is needs for calculate indent
321 *
322 * @returns {Number}
323 */
324 getDepth: function() {
325 if ($(this).treegrid('getParentNode') === null) {
326 return 0;
327 }
328 return $(this).treegrid('getParentNode').treegrid('getDepth') + 1;
329 },
330 /**
331 * Method return true if node is root
332 *
333 * @returns {Boolean}
334 */
335 isRoot: function() {
336 return $(this).treegrid('getDepth') === 0;
337 },
338 /**
339 * Method return true if node has no child nodes
340 *
341 * @returns {Boolean}
342 */
343 isLeaf: function() {
344 return $(this).treegrid('getChildNodes').length === 0;
345 },
346 /**
347 * Method return true if node last in branch
348 *
349 * @returns {Boolean}
350 */
351 isLast: function() {
352 if ($(this).treegrid('isNode')) {
353 var parentNode = $(this).treegrid('getParentNode');
354 if (parentNode === null) {
355 if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').last().treegrid('getNodeId')) {
356 return true;
357 }
358 } else {
359 if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').last().treegrid('getNodeId')) {
360 return true;
361 }
362 }
363 }
364 return false;
365 },
366 /**
367 * Method return true if node first in branch
368 *
369 * @returns {Boolean}
370 */
371 isFirst: function() {
372 if ($(this).treegrid('isNode')) {
373 var parentNode = $(this).treegrid('getParentNode');
374 if (parentNode === null) {
375 if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').first().treegrid('getNodeId')) {
376 return true;
377 }
378 } else {
379 if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').first().treegrid('getNodeId')) {
380 return true;
381 }
382 }
383 }
384 return false;
385 },
386 /**
387 * Return true if node expanded
388 *
389 * @returns {Boolean}
390 */
391 isExpanded: function() {
392 return $(this).hasClass('treegrid-expanded');
393 },
394 /**
395 * Return true if node collapsed
396 *
397 * @returns {Boolean}
398 */
399 isCollapsed: function() {
400 return $(this).hasClass('treegrid-collapsed');
401 },
402 /**
403 * Return true if at least one of parent node is collapsed
404 *
405 * @returns {Boolean}
406 */
407 isOneOfParentsCollapsed: function() {
408 var $this = $(this);
409 if ($this.treegrid('isRoot')) {
410 return false;
411 } else {
412 if ($this.treegrid('getParentNode').treegrid('isCollapsed')) {
413 return true;
414 } else {
415 return $this.treegrid('getParentNode').treegrid('isOneOfParentsCollapsed');
416 }
417 }
418 },
419 /**
420 * Expand node
421 *
422 * @returns {Node}
423 */
424 expand: function() {
425 if (!this.treegrid('isLeaf') && !this.treegrid("isExpanded")) {
426 this.trigger("expand");
427 this.trigger("change");
428 return this;
429 }
430 return this;
431 },
432 /**
433 * Expand all nodes
434 *
435 * @returns {Node}
436 */
437 expandAll: function() {
438 var $this = $(this);
439 $this.treegrid('getRootNodes').treegrid('expandRecursive');
440 return $this;
441 },
442 /**
443 * Expand current node and all child nodes begin from current
444 *
445 * @returns {Node}
446 */
447 expandRecursive: function() {
448 return $(this).each(function() {
449 var $this = $(this);
450 $this.treegrid('expand');
451 if (!$this.treegrid('isLeaf')) {
452 $this.treegrid('getChildNodes').treegrid('expandRecursive');
453 }
454 });
455 },
456 /**
457 * Collapse node
458 *
459 * @returns {Node}
460 */
461 collapse: function() {
462 return $(this).each(function() {
463 var $this = $(this);
464 if (!$this.treegrid('isLeaf') && !$this.treegrid("isCollapsed")) {
465 $this.trigger("collapse");
466 $this.trigger("change");
467 }
468 });
469 },
470 /**
471 * Collapse all nodes
472 *
473 * @returns {Node}
474 */
475 collapseAll: function() {
476 var $this = $(this);
477 $this.treegrid('getRootNodes').treegrid('collapseRecursive');
478 return $this;
479 },
480 /**
481 * Collapse current node and all child nodes begin from current
482 *
483 * @returns {Node}
484 */
485 collapseRecursive: function() {
486 return $(this).each(function() {
487 var $this = $(this);
488 $this.treegrid('collapse');
489 if (!$this.treegrid('isLeaf')) {
490 $this.treegrid('getChildNodes').treegrid('collapseRecursive');
491 }
492 });
493 },
494 /**
495 * Expand if collapsed, Collapse if expanded
496 *
497 * @returns {Node}
498 */
499 toggle: function() {
500 var $this = $(this);
501 if ($this.treegrid('isExpanded')) {
502 $this.treegrid('collapse');
503 } else {
504 $this.treegrid('expand');
505 }
506 return $this;
507 },
508 /**
509 * Rendering node
510 *
511 * @returns {Node}
512 */
513 render: function() {
514 return $(this).each(function() {
515 var $this = $(this);
516 //if parent colapsed we hidden
517 if ($this.treegrid('isOneOfParentsCollapsed')) {
518 $this.hide();
519 } else {
520 $this.show();
521 }
522 if (!$this.treegrid('isLeaf')) {
523 $this.treegrid('renderExpander');
524 $this.treegrid('getChildNodes').treegrid('render');
525 }
526 });
527 },
528 /**
529 * Rendering expander depends on node state
530 *
531 * @returns {Node}
532 */
533 renderExpander: function() {
534 return $(this).each(function() {
535 var $this = $(this);
536 var expander = $this.treegrid('getSetting', 'getExpander').apply(this);
537 if (expander) {
538
539 if (!$this.treegrid('isCollapsed')) {
540 expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
541 expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass'));
542 } else {
543 expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass'));
544 expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
545 }
546 } else {
547 $this.treegrid('initExpander');
548 $this.treegrid('renderExpander');
549 }
550 });
551 }
552 };
553 $.fn.treegrid = function(method) {
554 if (methods[method]) {
555 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
556 } else if (typeof method === 'object' || !method) {
557 return methods.initTree.apply(this, arguments);
558 } else {
559 $.error('Method with name ' + method + ' does not exists for jQuery.treegrid');
560 }
561 };
562 /**
563 * Plugin's default options
564 */
565 $.fn.treegrid.defaults = {
566 initialState: 'expanded',
567 saveState: false,
568 saveStateMethod: 'cookie',
569 saveStateName: 'tree-grid-state',
570 expanderTemplate: '<span class="treegrid-expander"></span>',
571 indentTemplate: '<span class="treegrid-indent"></span>',
572 expanderExpandedClass: 'treegrid-expander-expanded',
573 expanderCollapsedClass: 'treegrid-expander-collapsed',
574 treeColumn: 0,
575 getExpander: function() {
576 return $(this).find('.treegrid-expander');
577 },
578 getNodeId: function() {
579 var template = /treegrid-([A-Za-z0-9_-]+)/;
580 if (template.test($(this).attr('class'))) {
581 return template.exec($(this).attr('class'))[1];
582 }
583 return null;
584 },
585 getParentNodeId: function() {
586 var template = /treegrid-parent-([A-Za-z0-9_-]+)/;
587 if (template.test($(this).attr('class'))) {
588 return template.exec($(this).attr('class'))[1];
589 }
590 return null;
591 },
592 getNodeById: function(id, treegridContainer) {
593 var templateClass = "treegrid-" + id;
594 return treegridContainer.find('tr.' + templateClass);
595 },
596 getChildNodes: function(id, treegridContainer) {
597 var templateClass = "treegrid-parent-" + id;
598 return treegridContainer.find('tr.' + templateClass);
599 },
600 getTreeGridContainer: function() {
601 return $(this).closest('table');
602 },
603 getRootNodes: function(treegridContainer) {
604 var result = $.grep(treegridContainer.find('tr'), function(element) {
605 var classNames = $(element).attr('class');
606 var templateClass = /treegrid-([A-Za-z0-9_-]+)/;
607 var templateParentClass = /treegrid-parent-([A-Za-z0-9_-]+)/;
608 return templateClass.test(classNames) && !templateParentClass.test(classNames);
609 });
610 return $(result);
611 },
612 getAllNodes: function(treegridContainer) {
613 var result = $.grep(treegridContainer.find('tr'), function(element) {
614 var classNames = $(element).attr('class');
615 var templateClass = /treegrid-([A-Za-z0-9_-]+)/;
616 return templateClass.test(classNames);
617 });
618 return $(result);
619 },
620 //Events
621 onCollapse: null,
622 onExpand: null,
623 onChange: null
624
625 };
626})(jQuery);