2 * jQuery treegrid Plugin 0.3.0
3 * https://github.com/maxazan/jquery-treegrid
5 * Copyright 2013, Pomazan Max
6 * Licensed under the MIT licenses.
14 * @param {Object} options
17 initTree: function(options) {
18 var settings = $.extend({}, this.treegrid.defaults, options);
19 return this.each(function() {
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');
30 * @param {Object} settings
33 initNode: function(settings) {
34 return this.each(function() {
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");
41 initChangeEvent: function() {
43 //Save state on change
44 $this.on("change", function() {
46 $this.treegrid('render');
47 if ($this.treegrid('getSetting', 'saveState')) {
48 $this.treegrid('saveState');
54 * Initialize node events
58 initEvents: function() {
60 //Default behavior on collapse
61 $this.on("collapse", function() {
63 $this.removeClass('treegrid-expanded');
64 $this.addClass('treegrid-collapsed');
66 //Default behavior on expand
67 $this.on("expand", function() {
69 $this.removeClass('treegrid-collapsed');
70 $this.addClass('treegrid-expanded');
76 * Initialize events from settings
80 initSettingsEvents: function() {
82 //Save state on change
83 $this.on("change", function() {
85 if (typeof($this.treegrid('getSetting', 'onChange')) === "function") {
86 $this.treegrid('getSetting', 'onChange').apply($this);
89 //Default behavior on collapse
90 $this.on("collapse", function() {
92 if (typeof($this.treegrid('getSetting', 'onCollapse')) === "function") {
93 $this.treegrid('getSetting', 'onCollapse').apply($this);
96 //Default behavior on expand
97 $this.on("expand", function() {
99 if (typeof($this.treegrid('getSetting', 'onExpand')) === "function") {
100 $this.treegrid('getSetting', 'onExpand').apply($this);
108 * Initialize expander for node
112 initExpander: function() {
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);
120 $(tpl).prependTo(cell).click(function() {
121 $($(this).closest('tr')).treegrid('toggle');
126 * Initialize indent for node
130 initIndent: function() {
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);
142 * Initialise state of node
146 initState: function() {
148 if ($this.treegrid('getSetting', 'saveState') && !$this.treegrid('isFirstInit')) {
149 $this.treegrid('restoreState');
151 if ($this.treegrid('getSetting', 'initialState') === "expanded") {
152 $this.treegrid('expand');
154 $this.treegrid('collapse');
160 * Return true if this tree was never been initialised
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);
169 return tree.data('first_init');
172 * Save state of current node
176 saveState: function() {
178 if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') {
180 var stateArrayString = $.cookie($this.treegrid('getSetting', 'saveStateName')) || '';
181 var stateArray = (stateArrayString === '' ? [] : stateArrayString.split(','));
182 var nodeId = $this.treegrid('getNodeId');
184 if ($this.treegrid('isExpanded')) {
185 if ($.inArray(nodeId, stateArray) === -1) {
186 stateArray.push(nodeId);
188 } else if ($this.treegrid('isCollapsed')) {
189 if ($.inArray(nodeId, stateArray) !== -1) {
190 stateArray.splice($.inArray(nodeId, stateArray), 1);
193 $.cookie($this.treegrid('getSetting', 'saveStateName'), stateArray.join(','));
198 * Restore state of current node.
202 restoreState: function() {
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');
209 $this.treegrid('collapse');
216 * Method return setting by name
219 * @returns {unresolved}
221 getSetting: function(name) {
222 if (!$(this).treegrid('getTreeContainer')) {
225 return $(this).treegrid('getTreeContainer').data('settings')[name];
230 * @param {Object} settings
232 setSettings: function(settings) {
233 $(this).treegrid('getTreeContainer').data('settings', settings);
236 * Return tree container
238 * @returns {HtmlElement}
240 getTreeContainer: function() {
241 return $(this).data('treegrid');
246 * @param {HtmlE;ement} container
248 setTreeContainer: function(container) {
249 return $(this).data('treegrid', container);
252 * Method return all root nodes of tree.
254 * Start init all child nodes from it.
258 getRootNodes: function() {
259 return $(this).treegrid('getSetting', 'getRootNodes').apply(this, [$(this).treegrid('getTreeContainer')]);
262 * Method return all nodes of tree.
266 getAllNodes: function() {
267 return $(this).treegrid('getSetting', 'getAllNodes').apply(this, [$(this).treegrid('getTreeContainer')]);
270 * Mthod return true if element is Node
275 return $(this).treegrid('getNodeId') !== null;
278 * Mthod return id of node
282 getNodeId: function() {
283 if ($(this).treegrid('getSetting', 'getNodeId') === null) {
286 return $(this).treegrid('getSetting', 'getNodeId').apply(this);
290 * Method return parent id of node or null if root node
294 getParentNodeId: function() {
295 return $(this).treegrid('getSetting', 'getParentNodeId').apply(this);
298 * Method return parent node or null if root node
300 * @returns {Object[]}
302 getParentNode: function() {
303 if ($(this).treegrid('getParentNodeId') === null) {
306 return $(this).treegrid('getSetting', 'getNodeById').apply(this, [$(this).treegrid('getParentNodeId'), $(this).treegrid('getTreeContainer')]);
310 * Method return array of child nodes or null if node is leaf
312 * @returns {Object[]}
314 getChildNodes: function() {
315 return $(this).treegrid('getSetting', 'getChildNodes').apply(this, [$(this).treegrid('getNodeId'), $(this).treegrid('getTreeContainer')]);
318 * Method return depth of tree.
320 * This method is needs for calculate indent
324 getDepth: function() {
325 if ($(this).treegrid('getParentNode') === null) {
328 return $(this).treegrid('getParentNode').treegrid('getDepth') + 1;
331 * Method return true if node is root
336 return $(this).treegrid('getDepth') === 0;
339 * Method return true if node has no child nodes
344 return $(this).treegrid('getChildNodes').length === 0;
347 * Method return true if node last in branch
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')) {
359 if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').last().treegrid('getNodeId')) {
367 * Method return true if node first in branch
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')) {
379 if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').first().treegrid('getNodeId')) {
387 * Return true if node expanded
391 isExpanded: function() {
392 return $(this).hasClass('treegrid-expanded');
395 * Return true if node collapsed
399 isCollapsed: function() {
400 return $(this).hasClass('treegrid-collapsed');
403 * Return true if at least one of parent node is collapsed
407 isOneOfParentsCollapsed: function() {
409 if ($this.treegrid('isRoot')) {
412 if ($this.treegrid('getParentNode').treegrid('isCollapsed')) {
415 return $this.treegrid('getParentNode').treegrid('isOneOfParentsCollapsed');
425 if (!this.treegrid('isLeaf') && !this.treegrid("isExpanded")) {
426 this.trigger("expand");
427 this.trigger("change");
437 expandAll: function() {
439 $this.treegrid('getRootNodes').treegrid('expandRecursive');
443 * Expand current node and all child nodes begin from current
447 expandRecursive: function() {
448 return $(this).each(function() {
450 $this.treegrid('expand');
451 if (!$this.treegrid('isLeaf')) {
452 $this.treegrid('getChildNodes').treegrid('expandRecursive');
461 collapse: function() {
462 return $(this).each(function() {
464 if (!$this.treegrid('isLeaf') && !$this.treegrid("isCollapsed")) {
465 $this.trigger("collapse");
466 $this.trigger("change");
475 collapseAll: function() {
477 $this.treegrid('getRootNodes').treegrid('collapseRecursive');
481 * Collapse current node and all child nodes begin from current
485 collapseRecursive: function() {
486 return $(this).each(function() {
488 $this.treegrid('collapse');
489 if (!$this.treegrid('isLeaf')) {
490 $this.treegrid('getChildNodes').treegrid('collapseRecursive');
495 * Expand if collapsed, Collapse if expanded
501 if ($this.treegrid('isExpanded')) {
502 $this.treegrid('collapse');
504 $this.treegrid('expand');
514 return $(this).each(function() {
516 //if parent colapsed we hidden
517 if ($this.treegrid('isOneOfParentsCollapsed')) {
522 if (!$this.treegrid('isLeaf')) {
523 $this.treegrid('renderExpander');
524 $this.treegrid('getChildNodes').treegrid('render');
529 * Rendering expander depends on node state
533 renderExpander: function() {
534 return $(this).each(function() {
536 var expander = $this.treegrid('getSetting', 'getExpander').apply(this);
539 if (!$this.treegrid('isCollapsed')) {
540 expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
541 expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass'));
543 expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass'));
544 expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
547 $this.treegrid('initExpander');
548 $this.treegrid('renderExpander');
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);
559 $.error('Method with name ' + method + ' does not exists for jQuery.treegrid');
563 * Plugin's default options
565 $.fn.treegrid.defaults = {
566 initialState: 'expanded',
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',
575 getExpander: function() {
576 return $(this).find('.treegrid-expander');
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];
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];
592 getNodeById: function(id, treegridContainer) {
593 var templateClass = "treegrid-" + id;
594 return treegridContainer.find('tr.' + templateClass);
596 getChildNodes: function(id, treegridContainer) {
597 var templateClass = "treegrid-parent-" + id;
598 return treegridContainer.find('tr.' + templateClass);
600 getTreeGridContainer: function() {
601 return $(this).closest('table');
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);
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);