From ef86a8fa20d65329f655aa4eca8d7306cfc62744 Mon Sep 17 00:00:00 2001 From: jonmiles Date: Tue, 14 Apr 2015 21:59:29 +0100 Subject: [PATCH] Updated search method to optionally reveal results. #65 - New option `{revealResults: true|false}`, true by default - Updated revealNode to accept an array of nodes. - Updated searchable tree example --- README.md | 5 +++-- dist/bootstrap-treeview.min.js | 2 +- public/index.html | 11 ++++++++-- public/js/bootstrap-treeview.js | 37 ++++++++++++++++++++++++++------- src/js/bootstrap-treeview.js | 37 ++++++++++++++++++++++++++------- tests/lib/bootstrap-treeview.js | 37 ++++++++++++++++++++++++++------- 6 files changed, 100 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 6959475c4..f648af012 100644 --- a/README.md +++ b/README.md @@ -494,8 +494,9 @@ Returns an array of matching nodes. ```javascript $('#tree').treeview('search', [ 'Parent', { - ignoreCase: true, - exactMatch: false + ignoreCase: true, // case insensitive + exactMatch: false, // like or equals + revealResults: false, // reveal matching nodes }]); ``` diff --git a/dist/bootstrap-treeview.min.js b/dist/bootstrap-treeview.min.js index 9ea22f8ae..99ff350c5 100644 --- a/dist/bootstrap-treeview.min.js +++ b/dist/bootstrap-treeview.min.js @@ -1 +1 @@ -!function(a,b,c,d){"use strict";var e="treeview",f={};f.settings={injectStyle:!0,levels:2,expandIcon:"glyphicon glyphicon-plus",collapseIcon:"glyphicon glyphicon-minus",emptyIcon:"glyphicon",nodeIcon:"glyphicon glyphicon-stop",color:d,backColor:d,borderColor:d,onhoverColor:"#F5F5F5",selectedColor:"#FFFFFF",selectedBackColor:"#428bca",searchResultColor:"#D9534F",searchResultBackColor:d,enableLinks:!1,highlightSelected:!0,highlightSearchResults:!0,showBorder:!0,showTags:!1,multiSelect:!1,onNodeCollapsed:d,onNodeExpanded:d,onNodeSelected:d,onNodeUnselected:d,onSearchComplete:d,onSearchCleared:d},f.options={silent:!1,ignoreChildren:!1},f.searchOptions={ignoreCase:!0,exactMatch:!1};var g=function(b,c){return this.$element=a(b),this.elementId=b.id,this.styleId=this.elementId+"-style",this.init(c),{options:this.options,init:a.proxy(this.init,this),remove:a.proxy(this.remove,this),getNode:a.proxy(this.getNode,this),getParent:a.proxy(this.getParent,this),getSiblings:a.proxy(this.getSiblings,this),getSelected:a.proxy(this.getSelected,this),getUnselected:a.proxy(this.getUnselected,this),getExpanded:a.proxy(this.getExpanded,this),getCollapsed:a.proxy(this.getCollapsed,this),selectNode:a.proxy(this.selectNode,this),unselectNode:a.proxy(this.unselectNode,this),toggleNodeSelected:a.proxy(this.toggleNodeSelected,this),collapseAll:a.proxy(this.collapseAll,this),collapseNode:a.proxy(this.collapseNode,this),expandAll:a.proxy(this.expandAll,this),expandNode:a.proxy(this.expandNode,this),toggleNodeExpanded:a.proxy(this.toggleNodeExpanded,this),revealNode:a.proxy(this.revealNode,this),search:a.proxy(this.search,this),clearSearch:a.proxy(this.clearSearch,this)}};g.prototype.init=function(b){this.tree=[],this.nodes=[],b.data&&("string"==typeof b.data&&(b.data=a.parseJSON(b.data)),this.tree=a.extend(!0,[],b.data),delete b.data),this.options=a.extend({},f.settings,b),this.destroy(),this.subscribeEvents(),this.setInitialStates({nodes:this.tree},0),this.render()},g.prototype.remove=function(){this.destroy(),a.removeData(this,e),a("#"+this.styleId).remove()},g.prototype.destroy=function(){this.initialized&&(this.$wrapper.remove(),this.$wrapper=null,this.unsubscribeEvents(),this.initialized=!1)},g.prototype.unsubscribeEvents=function(){this.$element.off("click"),"function"==typeof this.options.onNodeCollapsed&&this.$element.off("nodeCollapsed"),"function"==typeof this.options.onNodeExpanded&&this.$element.off("nodeExpanded"),"function"==typeof this.options.onNodeSelected&&this.$element.off("nodeSelected"),"function"==typeof this.options.onNodeUnselected&&this.$element.off("nodeUnselected"),"function"==typeof this.options.onSearchComplete&&this.$element.off("searchComplete"),"function"==typeof this.options.onSearchCleared&&this.$element.off("searchCleared")},g.prototype.subscribeEvents=function(){this.unsubscribeEvents(),this.$element.on("click",a.proxy(this.clickHandler,this)),"function"==typeof this.options.onNodeCollapsed&&this.$element.on("nodeCollapsed",this.options.onNodeCollapsed),"function"==typeof this.options.onNodeExpanded&&this.$element.on("nodeExpanded",this.options.onNodeExpanded),"function"==typeof this.options.onNodeSelected&&this.$element.on("nodeSelected",this.options.onNodeSelected),"function"==typeof this.options.onNodeUnselected&&this.$element.on("nodeUnselected",this.options.onNodeUnselected),"function"==typeof this.options.onSearchComplete&&this.$element.on("searchComplete",this.options.onSearchComplete),"function"==typeof this.options.onSearchCleared&&this.$element.on("searchCleared",this.options.onSearchCleared)},g.prototype.setInitialStates=function(b,c){if(b.nodes){c+=1;var d=b,e=this;a.each(b.nodes,function(a,b){b.nodeId=e.nodes.length,b.parentId=d.nodeId,b.hasOwnProperty("selectable")||(b.selectable=!0),b.state=b.state||{},b.state.hasOwnProperty("expanded")||(b.state.expanded=c0?!0:!1),b.state.hasOwnProperty("selected")||(b.state.selected=!1),e.nodes.push(b),b.nodes&&e.setInitialStates(b,c)})}},g.prototype.clickHandler=function(b){this.options.enableLinks||b.preventDefault();var c=a(b.target),d=c.attr("class")?c.attr("class").split(" "):[],e=this.findNode(c);-1!=d.indexOf("click-expand")||-1!=d.indexOf("click-collapse")?this.toggleExpandedState(e,f.options):e&&(e.selectable?this.toggleSelectedState(e,f.options):this.toggleExpandedState(e,f.options))},g.prototype.findNode=function(a){var b=a.closest("li.list-group-item").attr("data-nodeid"),c=this.nodes[b];return c||console.log("Error: node does not exist"),c},g.prototype.toggleExpandedState=function(a,b){a&&(this.setExpandedState(a,!a.state.expanded,b),this.render())},g.prototype.setExpandedState=function(b,c,d){c!==b.state.expanded&&(c&&b.nodes?(b.state.expanded=!0,d.silent||this.$element.trigger("nodeExpanded",a.extend(!0,{},b))):c||(b.state.expanded=!1,d.silent||this.$element.trigger("nodeCollapsed",a.extend(!0,{},b)),b.nodes&&!d.ignoreChildren&&a.each(b.nodes,a.proxy(function(a,b){this.setExpandedState(b,!1,d)},this))))},g.prototype.toggleSelectedState=function(a,b){a&&(this.setSelectedState(a,!a.state.selected,b),this.render())},g.prototype.setSelectedState=function(b,c,d){c!==b.state.selected&&(c?(this.options.multiSelect||a.each(this.findNodes("true","g","state.selected"),a.proxy(function(a,b){this.setSelectedState(b,!1,d)},this)),b.state.selected=!0,d.silent||this.$element.trigger("nodeSelected",a.extend(!0,{},b))):(b.state.selected=!1,d.silent||this.$element.trigger("nodeUnselected",a.extend(!0,{},b))))},g.prototype.render=function(){this.initialized||(this.$element.addClass(e),this.$wrapper=a(this.template.list),this.injectStyle(),this.initialized=!0),this.$element.empty().append(this.$wrapper.empty()),this.buildTree(this.tree,0)},g.prototype.buildTree=function(b,c){if(b){c+=1;var d=this;a.each(b,function(b,e){for(var f=a(d.template.item).addClass("node-"+d.elementId).addClass(e.state.selected?"node-selected":"").addClass(e.searchResult?"search-result":"").attr("data-nodeid",e.nodeId).attr("style",d.buildStyleOverride(e)),g=0;c-1>g;g++)f.append(d.template.indent);return f.append(e.nodes?e.state.expanded?a(d.template.expandCollapseIcon).addClass("click-collapse").addClass(d.options.collapseIcon):a(d.template.expandCollapseIcon).addClass("click-expand").addClass(d.options.expandIcon):a(d.template.expandCollapseIcon).addClass(d.options.emptyIcon)),f.append(a(d.template.icon).addClass(e.icon?e.icon:d.options.nodeIcon)),f.append(d.options.enableLinks?a(d.template.link).attr("href",e.href).append(e.text):e.text),d.options.showTags&&e.tags&&a.each(e.tags,function(b,c){f.append(a(d.template.badge).append(c))}),d.$wrapper.append(f),e.nodes&&e.state.expanded?d.buildTree(e.nodes,c):void 0})}},g.prototype.buildStyleOverride=function(a){var b=a.color,c=a.backColor;return this.options.highlightSelected&&a.state.selected&&(this.options.selectedColor&&(b=this.options.selectedColor),this.options.selectedBackColor&&(c=this.options.selectedBackColor)),this.options.highlightSearchResults&&a.searchResult&&(this.options.searchResultColor&&(b=this.options.searchResultColor),this.options.searchResultBackColor&&(c=this.options.searchResultBackColor)),"color:"+b+";background-color:"+c+";"},g.prototype.injectStyle=function(){this.options.injectStyle&&!c.getElementById(this.styleId)&&a('").appendTo("head")},g.prototype.buildStyle=function(){var a=".node-"+this.elementId+"{";return this.options.color&&(a+="color:"+this.options.color+";"),this.options.backColor&&(a+="background-color:"+this.options.backColor+";"),this.options.showBorder?this.options.borderColor&&(a+="border:1px solid "+this.options.borderColor+";"):a+="border:none;",a+="}",this.options.onhoverColor&&(a+=".node-"+this.elementId+":hover{background-color:"+this.options.onhoverColor+";}"),this.css+a},g.prototype.template={list:'',item:'
  • ',indent:'',expandCollapseIcon:'',icon:'',link:'',badge:''},g.prototype.css=".treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.expand-collapse{width:1rem;height:1rem}.treeview span.icon{margin-left:10px;margin-right:5px}",g.prototype.getNode=function(a){return this.nodes[a]},g.prototype.getParent=function(a){var b=this.identifyNode(a);return this.nodes[b.parentId]},g.prototype.getSiblings=function(a){var b=this.identifyNode(a),c=this.getParent(b),d=c?c.nodes:this.tree;return d.filter(function(a){return a.nodeId!==b.nodeId})},g.prototype.getSelected=function(){return this.findNodes("true","g","state.selected")},g.prototype.getUnselected=function(){return this.findNodes("false","g","state.selected")},g.prototype.getExpanded=function(){return this.findNodes("true","g","state.expanded")},g.prototype.getCollapsed=function(){return this.findNodes("false","g","state.expanded")},g.prototype.selectNode=function(b,c){c=a.extend({},f.options,c),this.setSelectedState(this.identifyNode(b),!0,c),this.render()},g.prototype.unselectNode=function(b,c){c=a.extend({},f.options,c),this.setSelectedState(this.identifyNode(b),!1,c),this.render()},g.prototype.toggleNodeSelected=function(b,c){c=a.extend({},f.options,c),this.toggleSelectedState(this.identifyNode(b),c)},g.prototype.collapseAll=function(b){b=a.extend({},f.options,b),a.each(this.findNodes("true","g","state.expanded"),a.proxy(function(a,c){this.setExpandedState(c,!1,b)},this)),this.render()},g.prototype.collapseNode=function(b,c){c=a.extend({},f.options,c),this.setExpandedState(this.identifyNode(b),!1,c),this.render()},g.prototype.expandAll=function(b){b=a.extend({},f.options,b),b&&b.levels?this.expandLevels(this.tree,b.levels,b):a.each(this.nodes,a.proxy(function(a,c){this.setExpandedState(c,!0,b)},this)),this.render()},g.prototype.expandNode=function(b,c){c=a.extend({},f.options,c);var d=this.identifyNode(b);this.setExpandedState(d,!0,c),d.nodes&&c&&c.levels&&this.expandLevels(d.nodes,c.levels-1,c),this.render()},g.prototype.expandLevels=function(b,c,d){d=a.extend({},f.options,d),a.each(b,a.proxy(function(a,b){this.setExpandedState(b,c>0?!0:!1,d),b.nodes&&this.expandLevels(b.nodes,c-1,d)},this))},g.prototype.revealNode=function(b,c){c=a.extend({},f.options,c);for(var d=this.getParent(b);d;)this.setExpandedState(d,!0,c),d=this.getParent(d);this.render()},g.prototype.toggleNodeExpanded=function(b,c){c=a.extend({},f.options,c),this.toggleExpandedState(this.identifyNode(b),c)},g.prototype.identifyNode=function(a){return"number"==typeof a?this.nodes[a]:a},g.prototype.search=function(b,c){c=a.extend({},f.searchOptions,c),this.clearSearch();var d=[];if(b&&b.length>0){c.exactMatch&&(b="^"+b+"$");var e="g";c.ignoreCase&&(e+="i"),d=this.findNodes(b,e),a.each(d,function(a,b){b.searchResult=!0}),this.render()}return this.$element.trigger("searchComplete",a.extend(!0,{},d)),d},g.prototype.clearSearch=function(){var b=a.each(this.findNodes("true","g","searchResult"),function(a,b){b.searchResult=!1});this.render(),this.$element.trigger("searchCleared",a.extend(!0,{},b))},g.prototype.findNodes=function(b,c,d){c=c||"g",d=d||"text";var e=this;return a.grep(this.nodes,function(a){var f=e.getNodeValue(a,d);return"string"==typeof f?f.match(new RegExp(b,c)):void 0})},g.prototype.getNodeValue=function(a,b){var c=b.indexOf(".");if(c>0){var e=a[b.substring(0,c)],f=b.substring(c+1,b.length);return this.getNodeValue(e,f)}return a.hasOwnProperty(b)?a[b].toString():d};var h=function(a){b.console&&b.console.error(a)};a.fn[e]=function(b,c){var d;return this.each(function(){var f=a.data(this,e);"string"==typeof b?f?a.isFunction(f[b])&&"_"!==b.charAt(0)?(c instanceof Array||(c=[c]),d=f[b].apply(f,c)):h("No such method : "+b):h("Not initialized, can not call method : "+b):"boolean"==typeof b?d=f:a.data(this,e,new g(this,a.extend(!0,{},b)))}),d||this}}(jQuery,window,document); \ No newline at end of file +!function(a,b,c,d){"use strict";var e="treeview",f={};f.settings={injectStyle:!0,levels:2,expandIcon:"glyphicon glyphicon-plus",collapseIcon:"glyphicon glyphicon-minus",emptyIcon:"glyphicon",nodeIcon:"glyphicon glyphicon-stop",color:d,backColor:d,borderColor:d,onhoverColor:"#F5F5F5",selectedColor:"#FFFFFF",selectedBackColor:"#428bca",searchResultColor:"#D9534F",searchResultBackColor:d,enableLinks:!1,highlightSelected:!0,highlightSearchResults:!0,showBorder:!0,showTags:!1,multiSelect:!1,onNodeCollapsed:d,onNodeExpanded:d,onNodeSelected:d,onNodeUnselected:d,onSearchComplete:d,onSearchCleared:d},f.options={silent:!1,ignoreChildren:!1},f.searchOptions={ignoreCase:!0,exactMatch:!1,revealResults:!0};var g=function(b,c){return this.$element=a(b),this.elementId=b.id,this.styleId=this.elementId+"-style",this.init(c),{options:this.options,init:a.proxy(this.init,this),remove:a.proxy(this.remove,this),getNode:a.proxy(this.getNode,this),getParent:a.proxy(this.getParent,this),getSiblings:a.proxy(this.getSiblings,this),getSelected:a.proxy(this.getSelected,this),getUnselected:a.proxy(this.getUnselected,this),getExpanded:a.proxy(this.getExpanded,this),getCollapsed:a.proxy(this.getCollapsed,this),selectNode:a.proxy(this.selectNode,this),unselectNode:a.proxy(this.unselectNode,this),toggleNodeSelected:a.proxy(this.toggleNodeSelected,this),collapseAll:a.proxy(this.collapseAll,this),collapseNode:a.proxy(this.collapseNode,this),expandAll:a.proxy(this.expandAll,this),expandNode:a.proxy(this.expandNode,this),toggleNodeExpanded:a.proxy(this.toggleNodeExpanded,this),revealNode:a.proxy(this.revealNode,this),search:a.proxy(this.search,this),clearSearch:a.proxy(this.clearSearch,this)}};g.prototype.init=function(b){this.tree=[],this.nodes=[],b.data&&("string"==typeof b.data&&(b.data=a.parseJSON(b.data)),this.tree=a.extend(!0,[],b.data),delete b.data),this.options=a.extend({},f.settings,b),this.destroy(),this.subscribeEvents(),this.setInitialStates({nodes:this.tree},0),this.render()},g.prototype.remove=function(){this.destroy(),a.removeData(this,e),a("#"+this.styleId).remove()},g.prototype.destroy=function(){this.initialized&&(this.$wrapper.remove(),this.$wrapper=null,this.unsubscribeEvents(),this.initialized=!1)},g.prototype.unsubscribeEvents=function(){this.$element.off("click"),"function"==typeof this.options.onNodeCollapsed&&this.$element.off("nodeCollapsed"),"function"==typeof this.options.onNodeExpanded&&this.$element.off("nodeExpanded"),"function"==typeof this.options.onNodeSelected&&this.$element.off("nodeSelected"),"function"==typeof this.options.onNodeUnselected&&this.$element.off("nodeUnselected"),"function"==typeof this.options.onSearchComplete&&this.$element.off("searchComplete"),"function"==typeof this.options.onSearchCleared&&this.$element.off("searchCleared")},g.prototype.subscribeEvents=function(){this.unsubscribeEvents(),this.$element.on("click",a.proxy(this.clickHandler,this)),"function"==typeof this.options.onNodeCollapsed&&this.$element.on("nodeCollapsed",this.options.onNodeCollapsed),"function"==typeof this.options.onNodeExpanded&&this.$element.on("nodeExpanded",this.options.onNodeExpanded),"function"==typeof this.options.onNodeSelected&&this.$element.on("nodeSelected",this.options.onNodeSelected),"function"==typeof this.options.onNodeUnselected&&this.$element.on("nodeUnselected",this.options.onNodeUnselected),"function"==typeof this.options.onSearchComplete&&this.$element.on("searchComplete",this.options.onSearchComplete),"function"==typeof this.options.onSearchCleared&&this.$element.on("searchCleared",this.options.onSearchCleared)},g.prototype.setInitialStates=function(b,c){if(b.nodes){c+=1;var d=b,e=this;a.each(b.nodes,function(a,b){b.nodeId=e.nodes.length,b.parentId=d.nodeId,b.hasOwnProperty("selectable")||(b.selectable=!0),b.state=b.state||{},b.state.hasOwnProperty("expanded")||(b.state.expanded=c0?!0:!1),b.state.hasOwnProperty("selected")||(b.state.selected=!1),e.nodes.push(b),b.nodes&&e.setInitialStates(b,c)})}},g.prototype.clickHandler=function(b){this.options.enableLinks||b.preventDefault();var c=a(b.target),d=c.attr("class")?c.attr("class").split(" "):[],e=this.findNode(c);-1!=d.indexOf("click-expand")||-1!=d.indexOf("click-collapse")?this.toggleExpandedState(e,f.options):e&&(e.selectable?this.toggleSelectedState(e,f.options):this.toggleExpandedState(e,f.options))},g.prototype.findNode=function(a){var b=a.closest("li.list-group-item").attr("data-nodeid"),c=this.nodes[b];return c||console.log("Error: node does not exist"),c},g.prototype.toggleExpandedState=function(a,b){a&&(this.setExpandedState(a,!a.state.expanded,b),this.render())},g.prototype.setExpandedState=function(b,c,d){c!==b.state.expanded&&(c&&b.nodes?(b.state.expanded=!0,d.silent||this.$element.trigger("nodeExpanded",a.extend(!0,{},b))):c||(b.state.expanded=!1,d.silent||this.$element.trigger("nodeCollapsed",a.extend(!0,{},b)),b.nodes&&!d.ignoreChildren&&a.each(b.nodes,a.proxy(function(a,b){this.setExpandedState(b,!1,d)},this))))},g.prototype.toggleSelectedState=function(a,b){a&&(this.setSelectedState(a,!a.state.selected,b),this.render())},g.prototype.setSelectedState=function(b,c,d){c!==b.state.selected&&(c?(this.options.multiSelect||a.each(this.findNodes("true","g","state.selected"),a.proxy(function(a,b){this.setSelectedState(b,!1,d)},this)),b.state.selected=!0,d.silent||this.$element.trigger("nodeSelected",a.extend(!0,{},b))):(b.state.selected=!1,d.silent||this.$element.trigger("nodeUnselected",a.extend(!0,{},b))))},g.prototype.render=function(){this.initialized||(this.$element.addClass(e),this.$wrapper=a(this.template.list),this.injectStyle(),this.initialized=!0),this.$element.empty().append(this.$wrapper.empty()),this.buildTree(this.tree,0)},g.prototype.buildTree=function(b,c){if(b){c+=1;var d=this;a.each(b,function(b,e){for(var f=a(d.template.item).addClass("node-"+d.elementId).addClass(e.state.selected?"node-selected":"").addClass(e.searchResult?"search-result":"").attr("data-nodeid",e.nodeId).attr("style",d.buildStyleOverride(e)),g=0;c-1>g;g++)f.append(d.template.indent);return f.append(e.nodes?e.state.expanded?a(d.template.expandCollapseIcon).addClass("click-collapse").addClass(d.options.collapseIcon):a(d.template.expandCollapseIcon).addClass("click-expand").addClass(d.options.expandIcon):a(d.template.expandCollapseIcon).addClass(d.options.emptyIcon)),f.append(a(d.template.icon).addClass(e.icon?e.icon:d.options.nodeIcon)),f.append(d.options.enableLinks?a(d.template.link).attr("href",e.href).append(e.text):e.text),d.options.showTags&&e.tags&&a.each(e.tags,function(b,c){f.append(a(d.template.badge).append(c))}),d.$wrapper.append(f),e.nodes&&e.state.expanded?d.buildTree(e.nodes,c):void 0})}},g.prototype.buildStyleOverride=function(a){var b=a.color,c=a.backColor;return this.options.highlightSelected&&a.state.selected&&(this.options.selectedColor&&(b=this.options.selectedColor),this.options.selectedBackColor&&(c=this.options.selectedBackColor)),this.options.highlightSearchResults&&a.searchResult&&(this.options.searchResultColor&&(b=this.options.searchResultColor),this.options.searchResultBackColor&&(c=this.options.searchResultBackColor)),"color:"+b+";background-color:"+c+";"},g.prototype.injectStyle=function(){this.options.injectStyle&&!c.getElementById(this.styleId)&&a('").appendTo("head")},g.prototype.buildStyle=function(){var a=".node-"+this.elementId+"{";return this.options.color&&(a+="color:"+this.options.color+";"),this.options.backColor&&(a+="background-color:"+this.options.backColor+";"),this.options.showBorder?this.options.borderColor&&(a+="border:1px solid "+this.options.borderColor+";"):a+="border:none;",a+="}",this.options.onhoverColor&&(a+=".node-"+this.elementId+":hover{background-color:"+this.options.onhoverColor+";}"),this.css+a},g.prototype.template={list:'
      ',item:'
    • ',indent:'',expandCollapseIcon:'',icon:'',link:'',badge:''},g.prototype.css=".treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.expand-collapse{width:1rem;height:1rem}.treeview span.icon{margin-left:10px;margin-right:5px}",g.prototype.getNode=function(a){return this.nodes[a]},g.prototype.getParent=function(a){var b=this.identifyNode(a);return this.nodes[b.parentId]},g.prototype.getSiblings=function(a){var b=this.identifyNode(a),c=this.getParent(b),d=c?c.nodes:this.tree;return d.filter(function(a){return a.nodeId!==b.nodeId})},g.prototype.getSelected=function(){return this.findNodes("true","g","state.selected")},g.prototype.getUnselected=function(){return this.findNodes("false","g","state.selected")},g.prototype.getExpanded=function(){return this.findNodes("true","g","state.expanded")},g.prototype.getCollapsed=function(){return this.findNodes("false","g","state.expanded")},g.prototype.selectNode=function(b,c){c=a.extend({},f.options,c),this.setSelectedState(this.identifyNode(b),!0,c),this.render()},g.prototype.unselectNode=function(b,c){c=a.extend({},f.options,c),this.setSelectedState(this.identifyNode(b),!1,c),this.render()},g.prototype.toggleNodeSelected=function(b,c){c=a.extend({},f.options,c),this.toggleSelectedState(this.identifyNode(b),c)},g.prototype.collapseAll=function(b){b=a.extend({},f.options,b),a.each(this.findNodes("true","g","state.expanded"),a.proxy(function(a,c){this.setExpandedState(c,!1,b)},this)),this.render()},g.prototype.collapseNode=function(b,c){c=a.extend({},f.options,c),this.setExpandedState(this.identifyNode(b),!1,c),this.render()},g.prototype.expandAll=function(b){b=a.extend({},f.options,b),b&&b.levels?this.expandLevels(this.tree,b.levels,b):a.each(this.nodes,a.proxy(function(a,c){this.setExpandedState(c,!0,b)},this)),this.render()},g.prototype.expandNode=function(b,c){c=a.extend({},f.options,c);var d=this.identifyNode(b);this.setExpandedState(d,!0,c),d.nodes&&c&&c.levels&&this.expandLevels(d.nodes,c.levels-1,c),this.render()},g.prototype.expandLevels=function(b,c,d){d=a.extend({},f.options,d),a.each(b,a.proxy(function(a,b){this.setExpandedState(b,c>0?!0:!1,d),b.nodes&&this.expandLevels(b.nodes,c-1,d)},this))},g.prototype.revealNode=function(b,c){c=a.extend({},f.options,c),b instanceof Array||(b=[b]),a.each(b,a.proxy(function(a,b){for(var d=this.getParent(b);d;)this.setExpandedState(d,!0,c),d=this.getParent(d)},this)),this.render()},g.prototype.toggleNodeExpanded=function(b,c){c=a.extend({},f.options,c),this.toggleExpandedState(this.identifyNode(b),c)},g.prototype.identifyNode=function(a){return"number"==typeof a?this.nodes[a]:a},g.prototype.search=function(b,c){c=a.extend({},f.searchOptions,c),this.clearSearch();var d=[];if(b&&b.length>0){c.exactMatch&&(b="^"+b+"$");var e="g";c.ignoreCase&&(e+="i"),d=this.findNodes(b,e),a.each(d,function(a,b){b.searchResult=!0}),c.revealResults?this.revealNode(d):this.render()}return this.$element.trigger("searchComplete",a.extend(!0,{},d)),d},g.prototype.clearSearch=function(){var b=a.each(this.findNodes("true","g","searchResult"),function(a,b){b.searchResult=!1});this.render(),this.$element.trigger("searchCleared",a.extend(!0,{},b))},g.prototype.findNodes=function(b,c,d){c=c||"g",d=d||"text";var e=this;return a.grep(this.nodes,function(a){var f=e.getNodeValue(a,d);return"string"==typeof f?f.match(new RegExp(b,c)):void 0})},g.prototype.getNodeValue=function(a,b){var c=b.indexOf(".");if(c>0){var e=a[b.substring(0,c)],f=b.substring(c+1,b.length);return this.getNodeValue(e,f)}return a.hasOwnProperty(b)?a[b].toString():d};var h=function(a){b.console&&b.console.error(a)};a.fn[e]=function(b,c){var d;return this.each(function(){var f=a.data(this,e);"string"==typeof b?f?a.isFunction(f[b])&&"_"!==b.charAt(0)?(c instanceof Array||(c=[c]),d=f[b].apply(f,c)):h("No such method : "+b):h("Not initialized, can not call method : "+b):"boolean"==typeof b?d=f:a.data(this,e,new g(this,a.extend(!0,{},b)))}),d||this}}(jQuery,window,document); \ No newline at end of file diff --git a/public/index.html b/public/index.html index ce893774d..fc58bd165 100644 --- a/public/index.html +++ b/public/index.html @@ -85,6 +85,12 @@

      Input

      Exact Match +
      + +
      @@ -421,7 +427,7 @@

      enableLinks: true, data: defaultData }); - + var $searchableTree = $('#treeview-searchable').treeview({ @@ -432,7 +438,8 @@

      var pattern = $('#input-search').val(); var options = { ignoreCase: $('#chk-ignore-case').is(':checked'), - exactMatch: $('#chk-exact-match').is(':checked') + exactMatch: $('#chk-exact-match').is(':checked'), + revealResults: $('#chk-reveal-results').is(':checked') }; var results = $searchableTree.treeview('search', [ pattern, options ]); diff --git a/public/js/bootstrap-treeview.js b/public/js/bootstrap-treeview.js index c1d7f8532..6b5416f4f 100644 --- a/public/js/bootstrap-treeview.js +++ b/public/js/bootstrap-treeview.js @@ -70,7 +70,8 @@ _default.searchOptions = { ignoreCase: true, - exactMatch: false + exactMatch: false, + revealResults: true }; var Tree = function (element, options) { @@ -739,17 +740,26 @@ /** Reveals a given tree node, expanding the tree from node to root. - @param {Object|Number} identifier - A valid node or node id + @param {Object|Number|Array} identifier - A valid node, node id or array of node identifiers @param {optional Object} options */ Tree.prototype.revealNode = function (identifier, options) { options = $.extend({}, _default.options, options); - var parentNode = this.getParent(identifier); - while (parentNode) { - this.setExpandedState(parentNode, true, options); - parentNode = this.getParent(parentNode); - }; + if (!(identifier instanceof Array)) { + identifier = [identifier]; + } + + // Iterate nodes + $.each(identifier, $.proxy(function (index, identifier) { + + // Traverse the tree expanding parents from node to root + var parentNode = this.getParent(identifier); + while (parentNode) { + this.setExpandedState(parentNode, true, options); + parentNode = this.getParent(parentNode); + }; + }, this)); this.render(); }; @@ -795,11 +805,22 @@ } results = this.findNodes(pattern, modifier); + + // Add searchResult property to all matching nodes + // This will be used to apply custom styles + // and when identifying result to be cleared $.each(results, function (index, node) { node.searchResult = true; }) - this.render(); + // If revealResults, then render is triggered from revealNode + // otherwise we just call render. + if (options.revealResults) { + this.revealNode(results); + } + else { + this.render(); + } } this.$element.trigger('searchComplete', $.extend(true, {}, results)); diff --git a/src/js/bootstrap-treeview.js b/src/js/bootstrap-treeview.js index c1d7f8532..6b5416f4f 100644 --- a/src/js/bootstrap-treeview.js +++ b/src/js/bootstrap-treeview.js @@ -70,7 +70,8 @@ _default.searchOptions = { ignoreCase: true, - exactMatch: false + exactMatch: false, + revealResults: true }; var Tree = function (element, options) { @@ -739,17 +740,26 @@ /** Reveals a given tree node, expanding the tree from node to root. - @param {Object|Number} identifier - A valid node or node id + @param {Object|Number|Array} identifier - A valid node, node id or array of node identifiers @param {optional Object} options */ Tree.prototype.revealNode = function (identifier, options) { options = $.extend({}, _default.options, options); - var parentNode = this.getParent(identifier); - while (parentNode) { - this.setExpandedState(parentNode, true, options); - parentNode = this.getParent(parentNode); - }; + if (!(identifier instanceof Array)) { + identifier = [identifier]; + } + + // Iterate nodes + $.each(identifier, $.proxy(function (index, identifier) { + + // Traverse the tree expanding parents from node to root + var parentNode = this.getParent(identifier); + while (parentNode) { + this.setExpandedState(parentNode, true, options); + parentNode = this.getParent(parentNode); + }; + }, this)); this.render(); }; @@ -795,11 +805,22 @@ } results = this.findNodes(pattern, modifier); + + // Add searchResult property to all matching nodes + // This will be used to apply custom styles + // and when identifying result to be cleared $.each(results, function (index, node) { node.searchResult = true; }) - this.render(); + // If revealResults, then render is triggered from revealNode + // otherwise we just call render. + if (options.revealResults) { + this.revealNode(results); + } + else { + this.render(); + } } this.$element.trigger('searchComplete', $.extend(true, {}, results)); diff --git a/tests/lib/bootstrap-treeview.js b/tests/lib/bootstrap-treeview.js index c1d7f8532..6b5416f4f 100644 --- a/tests/lib/bootstrap-treeview.js +++ b/tests/lib/bootstrap-treeview.js @@ -70,7 +70,8 @@ _default.searchOptions = { ignoreCase: true, - exactMatch: false + exactMatch: false, + revealResults: true }; var Tree = function (element, options) { @@ -739,17 +740,26 @@ /** Reveals a given tree node, expanding the tree from node to root. - @param {Object|Number} identifier - A valid node or node id + @param {Object|Number|Array} identifier - A valid node, node id or array of node identifiers @param {optional Object} options */ Tree.prototype.revealNode = function (identifier, options) { options = $.extend({}, _default.options, options); - var parentNode = this.getParent(identifier); - while (parentNode) { - this.setExpandedState(parentNode, true, options); - parentNode = this.getParent(parentNode); - }; + if (!(identifier instanceof Array)) { + identifier = [identifier]; + } + + // Iterate nodes + $.each(identifier, $.proxy(function (index, identifier) { + + // Traverse the tree expanding parents from node to root + var parentNode = this.getParent(identifier); + while (parentNode) { + this.setExpandedState(parentNode, true, options); + parentNode = this.getParent(parentNode); + }; + }, this)); this.render(); }; @@ -795,11 +805,22 @@ } results = this.findNodes(pattern, modifier); + + // Add searchResult property to all matching nodes + // This will be used to apply custom styles + // and when identifying result to be cleared $.each(results, function (index, node) { node.searchResult = true; }) - this.render(); + // If revealResults, then render is triggered from revealNode + // otherwise we just call render. + if (options.revealResults) { + this.revealNode(results); + } + else { + this.render(); + } } this.$element.trigger('searchComplete', $.extend(true, {}, results));