From 046d67200ea5973ad68702b748e335da417f7561 Mon Sep 17 00:00:00 2001 From: craig w Date: Tue, 8 Nov 2016 20:58:31 -0500 Subject: [PATCH 01/11] Update to only show nodeIcon for leaf nodes --- src/js/bootstrap-treeview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index 7a82a2eeb..fcd10ec8e 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -547,7 +547,7 @@ // Add node icon - if (_this.options.showIcon) { + if (_this.options.showIcon && !node.nodes) { var classList = ['node-icon']; From 0ae4929f4edc9647d0620d584caf0dc8f7fae473 Mon Sep 17 00:00:00 2001 From: craig w Date: Thu, 17 Nov 2016 20:40:24 -0500 Subject: [PATCH 02/11] Added custom-id attribute to leaf nodes, this enables knowing the database id of a node when an event (such as selecting a node) occurs --- src/js/bootstrap-treeview.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index fcd10ec8e..2c7ce7cf5 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -518,6 +518,7 @@ .addClass(node.state.selected ? 'node-selected' : '') .addClass(node.searchResult ? 'search-result' : '') .attr('data-nodeid', node.nodeId) + .attr('data-custom-id', node.customId || '') .attr('style', _this.buildStyleOverride(node)); // Add indent/spacer to mimic tree structure From 3fea0aa73254354ad45f7d564101160f2df8cbfa Mon Sep 17 00:00:00 2001 From: craig w Date: Sun, 15 Jan 2017 00:03:25 -0500 Subject: [PATCH 03/11] Add ability to only show leaf icon, added ability to customize the expand and collapse icons --- src/js/bootstrap-treeview.js | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index 2c7ce7cf5..b7c62cc87 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -55,6 +55,7 @@ highlightSearchResults: true, showBorder: true, showIcon: true, + showLeafIconOnly: true, showCheckbox: false, showTags: false, multiSelect: false, @@ -528,28 +529,37 @@ // Add expand, collapse or empty spacer icons var classList = []; - if (node.nodes) { + if (node.nodes && node.nodes.length > 0) { classList.push('expand-icon'); if (node.state.expanded) { - classList.push(_this.options.collapseIcon); + classList.push(node.collapseIcon || _this.options.collapseIcon); } else { - classList.push(_this.options.expandIcon); + classList.push(node.expandIcon || _this.options.expandIcon); } } else { classList.push(_this.options.emptyIcon); } - treeItem - .append($(_this.template.icon) - .addClass(classList.join(' ')) - ); - + // only add the 'icon' template if it's not a leaf node + if (node.nodes && node.nodes.length > 0) { + treeItem + .append($(_this.template.icon) + .addClass(classList.join(' ')) + ); + } // Add node icon - if (_this.options.showIcon && !node.nodes) { - + var displayIcon = false; + if (_this.options.showLeafIconOnly) { + if (!node.nodes || node.nodes.length == 0) { + displayIcon = true; + } + } else if (_this.options.showIcon) { + displayIcon = true; + } + if (displayIcon) { var classList = ['node-icon']; classList.push(node.icon || _this.options.nodeIcon); From f4a243c1462e4bdac87605ae78b5203e573bc8c0 Mon Sep 17 00:00:00 2001 From: craig w Date: Sun, 22 Jan 2017 19:56:35 -0500 Subject: [PATCH 04/11] Added method for finding the node id of a tree node based on its custom id --- README.md | 9 +++++++++ src/js/bootstrap-treeview.js | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c0a724235..801ef52bd 100644 --- a/README.md +++ b/README.md @@ -513,6 +513,15 @@ $('#tree').treeview('expandNode', [ nodeId, { levels: 2, silent: true } ]); Triggers `nodeExpanded` event; pass silent to suppress events. +#### findNodeIdByCustomId(customId) + +Find the `nodeId` of a node in the tree whose `customId` matches the given customId. If no match can be +found then `undefined` is returned. + +```javascript +$('#tree').treeview('findNodeIdByCustomId', 3) +``` + #### getCollapsed() Returns an array of collapsed nodes e.g. state.expanded = false. diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index b7c62cc87..cf750a039 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -143,7 +143,9 @@ // Search methods search: $.proxy(this.search, this), - clearSearch: $.proxy(this.clearSearch, this) + clearSearch: $.proxy(this.clearSearch, this), + + findNodeIdByCustomId: $.proxy(this.findNodeIdByCustomId, this) }; }; @@ -1173,6 +1175,20 @@ this.$element.trigger('searchCleared', $.extend(true, {}, results)); }; + /** + Find the node that matches the given custom id. + @param {Number} customId - the customId property to find + @return {number} the node id + */ + Tree.prototype.findNodeIdByCustomId = function(customId) { + this.nodes.forEach(function(node) { + if (node.customId == customId) { + return node.nodeId; + { + }); + return undefined; + }; + /** Find nodes that match a given criteria @param {String} pattern - A given string to match against From 16a9247183f7d998ae5c4a36b801ccab489f07fe Mon Sep 17 00:00:00 2001 From: craig w Date: Sun, 22 Jan 2017 19:57:30 -0500 Subject: [PATCH 05/11] fixed typo --- src/js/bootstrap-treeview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index cf750a039..51bf517de 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -1184,7 +1184,7 @@ this.nodes.forEach(function(node) { if (node.customId == customId) { return node.nodeId; - { + } }); return undefined; }; From 9c3d83329d9f945f655fb14234fbb42df0702107 Mon Sep 17 00:00:00 2001 From: craig w Date: Sun, 22 Jan 2017 20:38:11 -0500 Subject: [PATCH 06/11] Updated results provided in the findNodeIdByCustomIdComplete event --- README.md | 2 ++ src/js/bootstrap-treeview.js | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 801ef52bd..6cd2c8969 100644 --- a/README.md +++ b/README.md @@ -736,6 +736,8 @@ $('#tree').on('nodeSelected', function(event, data) { ### List of Events +`findNodeIdByCustomIdComplete(event, {nodeId: , customId: })` - a node was found + `nodeChecked (event, node)` - A node is checked. `nodeCollapsed (event, node)` - A node is collapsed. diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index 51bf517de..b324868d6 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -1181,12 +1181,18 @@ @return {number} the node id */ Tree.prototype.findNodeIdByCustomId = function(customId) { - this.nodes.forEach(function(node) { - if (node.customId == customId) { - return node.nodeId; - } - }); - return undefined; + var nodeId = undefined; + for (var i = 0; i < this.nodes.length; i++) { + if (this.nodes[i].customId == customId) { + nodeId = this.nodes[i].nodeId; + break; + } + } + + this.$element.trigger('findNodeIdByCustomIdComplete', {nodeId: nodeId, customId: customId}); + + + return nodeId; }; /** From 3539c60b37682f86ac2ffb0958af4ddd9fa43649 Mon Sep 17 00:00:00 2001 From: craig w Date: Thu, 16 Mar 2017 15:32:55 -0400 Subject: [PATCH 07/11] added ability to customize handler for findNodeIdByCustomIdComplete event --- src/js/bootstrap-treeview.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index b324868d6..8ff07db5f 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -70,7 +70,8 @@ onNodeUnchecked: undefined, onNodeUnselected: undefined, onSearchComplete: undefined, - onSearchCleared: undefined + onSearchCleared: undefined, + onFindNodeIdByCustomIdComplete: undefined }; _default.options = { @@ -249,6 +250,10 @@ if (typeof (this.options.onSearchCleared) === 'function') { this.$element.on('searchCleared', this.options.onSearchCleared); } + + if (typeof (this.options.onFindNodeIdByCustomIdComplete) === 'function') { + this.$element.on('findNodeIdByCustomIdComplete', this.options.onFindNodeIdByCustomIdComplete); + } }; /* From 075f95c032337da95d0907d81b26bc785d94ec41 Mon Sep 17 00:00:00 2001 From: craig w Date: Fri, 24 Mar 2017 10:18:23 -0400 Subject: [PATCH 08/11] Added ability to find multiple nodes based on custom ids. --- README.md | 16 ++++++ src/js/bootstrap-treeview.js | 96 ++++++++++++++++++++++++++---------- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 6cd2c8969..491d769d2 100644 --- a/README.md +++ b/README.md @@ -522,6 +522,22 @@ found then `undefined` is returned. $('#tree').treeview('findNodeIdByCustomId', 3) ``` +Triggers `findNodeIdByCustomIdComplete` event. + +#### findNodesByCustomIds(customIds) + +Find nodes in the tree whose `customId` matches those given in `customIds`. The return value is +an object with two properties: + * `customIds` - the customIds given to the function + * `nodesMap` - an object that maps the customId to an array of matching tree nodes (an array is + used because its possible one custom id is represented multiple times in the tree). + +```javascript +$('#tree').treeview('findNodesByCustomIds', [3, 4, 5]) +``` + +Triggers `findNodesByCustomIdsComplete` event. + #### getCollapsed() Returns an array of collapsed nodes e.g. state.expanded = false. diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index 8ff07db5f..2f28c092e 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -71,7 +71,8 @@ onNodeUnselected: undefined, onSearchComplete: undefined, onSearchCleared: undefined, - onFindNodeIdByCustomIdComplete: undefined + onFindNodeIdByCustomIdComplete: undefined, + onFindNodesByCustomIdsComplete: undefined }; _default.options = { @@ -145,8 +146,9 @@ // Search methods search: $.proxy(this.search, this), clearSearch: $.proxy(this.clearSearch, this), - - findNodeIdByCustomId: $.proxy(this.findNodeIdByCustomId, this) + + findNodeIdByCustomId: $.proxy(this.findNodeIdByCustomId, this), + findNodesByCustomIds: $.proxy(this.findNodesByCustomIds, this), }; }; @@ -251,9 +253,13 @@ this.$element.on('searchCleared', this.options.onSearchCleared); } - if (typeof (this.options.onFindNodeIdByCustomIdComplete) === 'function') { - this.$element.on('findNodeIdByCustomIdComplete', this.options.onFindNodeIdByCustomIdComplete); - } + if (typeof (this.options.onFindNodeIdByCustomIdComplete) === 'function') { + this.$element.on('findNodeIdByCustomIdComplete', this.options.onFindNodeIdByCustomIdComplete); + } + + if (typeof (this.options.onFindNodesByCustomIdsComplete) === 'function') { + this.$element.on('findNodesByCustomIdsComplete', this.options.onFindNodesByCustomIdsComplete); + } }; /* @@ -329,7 +335,7 @@ var target = $(event.target); var node = this.findNode(target); if (!node || node.state.disabled) return; - + var classList = target.attr('class') ? target.attr('class').split(' ') : []; if ((classList.indexOf('expand-icon') !== -1)) { @@ -337,12 +343,12 @@ this.render(); } else if ((classList.indexOf('check-icon') !== -1)) { - + this.toggleCheckedState(node, _default.options); this.render(); } else { - + if (node.selectable) { this.toggleSelectedState(node, _default.options); } else { @@ -524,7 +530,7 @@ .addClass(node.state.checked ? 'node-checked' : '') .addClass(node.state.disabled ? 'node-disabled': '') .addClass(node.state.selected ? 'node-selected' : '') - .addClass(node.searchResult ? 'search-result' : '') + .addClass(node.searchResult ? 'search-result' : '') .attr('data-nodeid', node.nodeId) .attr('data-custom-id', node.customId || '') .attr('style', _this.buildStyleOverride(node)); @@ -572,7 +578,7 @@ classList.push(node.icon || _this.options.nodeIcon); if (node.state.selected) { classList.pop(); - classList.push(node.selectedIcon || _this.options.selectedIcon || + classList.push(node.selectedIcon || _this.options.selectedIcon || node.icon || _this.options.nodeIcon); } @@ -587,7 +593,7 @@ var classList = ['check-icon']; if (node.state.checked) { - classList.push(_this.options.checkedIcon); + classList.push(_this.options.checkedIcon); } else { classList.push(_this.options.uncheckedIcon); @@ -953,7 +959,7 @@ this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) { this.toggleExpandedState(node, options); }, this)); - + this.render(); }; @@ -1103,7 +1109,7 @@ $.each(identifiers, $.proxy(function (index, identifier) { callback(this.identifyNode(identifier), options); - }, this)); + }, this)); }; /* @@ -1174,31 +1180,71 @@ }); if (options.render) { - this.render(); + this.render(); } - + this.$element.trigger('searchCleared', $.extend(true, {}, results)); }; - /** - Find the node that matches the given custom id. - @param {Number} customId - the customId property to find - @return {number} the node id - */ + /** + * Find the node that matches the given custom id. + * @param {Number} customId - the customId property to find + * @return {Number} the node id + */ Tree.prototype.findNodeIdByCustomId = function(customId) { var nodeId = undefined; for (var i = 0; i < this.nodes.length; i++) { if (this.nodes[i].customId == customId) { nodeId = this.nodes[i].nodeId; - break; + break; } } - this.$element.trigger('findNodeIdByCustomIdComplete', {nodeId: nodeId, customId: customId}); - + this.$element.trigger('findNodeIdByCustomIdComplete', {nodeId: nodeId, customId: customId}); return nodeId; - }; + }; + + /** + * Find the nodes that match the given custom ids. + * + * Will fire the 'findNodesByCustomIdsComplete' event when complete. The + * event handler will receive two parameters, the event and the results. The + * results will be an object with two properties: customIds (the ids given + * when performing the find operation) and nodesMap (an object that maps the + * custom id to an array of matching tree node objects). + * + * @param {Number[]} customIds - the custom ids to search for + * @return {Object} - containing two parameters, 'customIds' and 'nodesMap'. + */ + Tree.prototype.findNodesByCustomIds = function(customIds) { + var nodesMap = {}; + var result = {customIds: customIds, nodesMap: nodesMap; + + if (customIds == undefined || customIds.length == 0) { + this.$element.trigger('findNodesByCustomIdsComplete', result); + return result; + } + + var customId = undefined; + var node = undefined; + for (var i = 0; i < customIds.length; i++ ) { + customId = customIds[i]; + for (var j = 0; j < this.nodes.length; j++) { + node = this.nodes[j]; + + if (node.customId == customId) { + var matchingNodes = nodesMap[customId] || []; + matchingNodes.push(node); + nodesMap[customId] = matchingNodes; + break; + } + } + } + + this.$element.trigger('findNodesByCustomIdsComplete', result); + return result; + }; /** Find nodes that match a given criteria From d2ff47655414fca699006c5168b9f530d8931107 Mon Sep 17 00:00:00 2001 From: craig w Date: Fri, 24 Mar 2017 10:35:27 -0400 Subject: [PATCH 09/11] updated readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 491d769d2..090e6b682 100644 --- a/README.md +++ b/README.md @@ -533,7 +533,9 @@ an object with two properties: used because its possible one custom id is represented multiple times in the tree). ```javascript -$('#tree').treeview('findNodesByCustomIds', [3, 4, 5]) +// we have to wrap the ids in an array because jQuery treats the arguments as an array +// of individual arguments and the goal is to pass an entire array +$('#tree').treeview('findNodesByCustomIds', [[3, 4, 5]]); ``` Triggers `findNodesByCustomIdsComplete` event. From 818eaaa51915698a619a028df48849250e23bcb0 Mon Sep 17 00:00:00 2001 From: craig w Date: Fri, 24 Mar 2017 10:40:11 -0400 Subject: [PATCH 10/11] added nodeIds to the results returned by findNodesByCustomIds --- README.md | 3 ++- src/js/bootstrap-treeview.js | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 090e6b682..414e8fd88 100644 --- a/README.md +++ b/README.md @@ -527,8 +527,9 @@ Triggers `findNodeIdByCustomIdComplete` event. #### findNodesByCustomIds(customIds) Find nodes in the tree whose `customId` matches those given in `customIds`. The return value is -an object with two properties: +an object with three properties: * `customIds` - the customIds given to the function + * `nodeIds` - the tree node ids of the nodes that matched * `nodesMap` - an object that maps the customId to an array of matching tree nodes (an array is used because its possible one custom id is represented multiple times in the tree). diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index 2f28c092e..90bb6b0d4 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -1210,16 +1210,17 @@ * * Will fire the 'findNodesByCustomIdsComplete' event when complete. The * event handler will receive two parameters, the event and the results. The - * results will be an object with two properties: customIds (the ids given - * when performing the find operation) and nodesMap (an object that maps the - * custom id to an array of matching tree node objects). + * results will be an object with three properties: customIds (the ids given + * when performing the find operation), nodeIds (an array of matching tree node ids), + * and nodesMap (an object that maps the custom id to an array of matching tree node objects). * * @param {Number[]} customIds - the custom ids to search for - * @return {Object} - containing two parameters, 'customIds' and 'nodesMap'. + * @return {Object} - containing three parameters, 'customIds', 'nodeIds' and 'nodesMap'. */ Tree.prototype.findNodesByCustomIds = function(customIds) { var nodesMap = {}; - var result = {customIds: customIds, nodesMap: nodesMap; + var matchingNodeIds = []; + var result = {customIds: customIds, nodeIds: matchingNodeIds, nodesMap: nodesMap}; if (customIds == undefined || customIds.length == 0) { this.$element.trigger('findNodesByCustomIdsComplete', result); @@ -1237,6 +1238,7 @@ var matchingNodes = nodesMap[customId] || []; matchingNodes.push(node); nodesMap[customId] = matchingNodes; + matchingNodeIds.push(node.nodeId); break; } } From 8779c936c8ca3b24e1d078a76946e7593cbfbd21 Mon Sep 17 00:00:00 2001 From: craig w Date: Wed, 31 May 2017 07:11:53 -0400 Subject: [PATCH 11/11] Add ability to expand a node when clicking on its label --- src/js/bootstrap-treeview.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index 90bb6b0d4..8638517c9 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -15,6 +15,9 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Additional changes made in a fork located at: + * https://github.com/mindscratch/bootstrap-treeview * ========================================================= */ ;(function ($, window, document, undefined) { @@ -351,6 +354,12 @@ if (node.selectable) { this.toggleSelectedState(node, _default.options); + + // if a node is selected and it's not expanded, then expand it + // this allows clicking on a node label to expand it + if (!node.state.expanded) { + this.toggleExpandedState(node, _default.options); + } } else { this.toggleExpandedState(node, _default.options); }