fuzzysearch.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * email: bigablecat@hotmail.com
  3. * Date: 2018-04-14
  4. */
  5. /**
  6. * @param zTreeId the ztree id used to get the ztree object
  7. * @param searchField selector of your input for fuzzy search
  8. * @param isHighLight whether highlight the match words, default true
  9. * @param isExpand whether to expand the node, default false
  10. *
  11. * @returns
  12. */
  13. function fuzzySearch(zTreeId, searchField, isHighLight, isExpand){
  14. var zTreeObj = $.fn.zTree.getZTreeObj(zTreeId);//get the ztree object by ztree id
  15. if(!zTreeObj){
  16. alert("fail to get ztree object");
  17. }
  18. var nameKey = zTreeObj.setting.data.key.name; //get the key of the node name
  19. isHighLight = isHighLight===false?false:true;//default true, only use false to disable highlight
  20. isExpand = isExpand?true:false; // not to expand in default
  21. zTreeObj.setting.view.nameIsHTML = isHighLight; //allow use html in node name for highlight use
  22. var metaChar = '[\\[\\]\\\\\^\\$\\.\\|\\?\\*\\+\\(\\)]'; //js meta characters
  23. var rexMeta = new RegExp(metaChar, 'gi');//regular expression to match meta characters
  24. // keywords filter function
  25. function ztreeFilter(zTreeObj,_keywords,callBackFunc) {
  26. if(!_keywords){
  27. _keywords =''; //default blank for _keywords
  28. }
  29. // function to find the matching node
  30. function filterFunc(node) {
  31. if(node && node.oldname && node.oldname.length>0){
  32. node[nameKey] = node.oldname; //recover oldname of the node if exist
  33. }
  34. zTreeObj.updateNode(node); //update node to for modifications take effect
  35. if (_keywords.length == 0) {
  36. //return true to show all nodes if the keyword is blank
  37. zTreeObj.showNode(node);
  38. zTreeObj.expandNode(node,isExpand);
  39. return true;
  40. }
  41. //transform node name and keywords to lowercase
  42. if (node[nameKey] && node[nameKey].toLowerCase().indexOf(_keywords.toLowerCase())!=-1) {
  43. if(isHighLight){ //highlight process
  44. //a new variable 'newKeywords' created to store the keywords information
  45. //keep the parameter '_keywords' as initial and it will be used in next node
  46. //process the meta characters in _keywords thus the RegExp can be correctly used in str.replace
  47. var newKeywords = _keywords.replace(rexMeta,function(matchStr){
  48. //add escape character before meta characters
  49. return '\\' + matchStr;
  50. });
  51. node.oldname = node[nameKey]; //store the old name
  52. var rexGlobal = new RegExp(newKeywords, 'gi');//'g' for global,'i' for ignore case
  53. //use replace(RegExp,replacement) since replace(/substr/g,replacement) cannot be used here
  54. node[nameKey] = node.oldname.replace(rexGlobal, function(originalText){
  55. //highlight the matching words in node name
  56. var highLightText =
  57. '<span style="color: whitesmoke;background-color: darkred;">'
  58. + originalText
  59. +'</span>';
  60. return highLightText;
  61. });
  62. zTreeObj.updateNode(node); //update node for modifications take effect
  63. }
  64. zTreeObj.showNode(node);//show node with matching keywords
  65. return true; //return true and show this node
  66. }
  67. zTreeObj.hideNode(node); // hide node that not matched
  68. return false; //return false for node not matched
  69. }
  70. var nodesShow = zTreeObj.getNodesByFilter(filterFunc); //get all nodes that would be shown
  71. processShowNodes(nodesShow, _keywords);//nodes should be reprocessed to show correctly
  72. }
  73. /**
  74. * reprocess of nodes before showing
  75. */
  76. function processShowNodes(nodesShow,_keywords){
  77. if(nodesShow && nodesShow.length>0){
  78. //process the ancient nodes if _keywords is not blank
  79. if(_keywords.length>0){
  80. $.each(nodesShow, function(n,obj){
  81. var pathOfOne = obj.getPath();//get all the ancient nodes including current node
  82. if(pathOfOne && pathOfOne.length>0){
  83. //i < pathOfOne.length-1 process every node in path except self
  84. for(var i=0;i<pathOfOne.length-1;i++){
  85. zTreeObj.showNode(pathOfOne[i]); //show node
  86. zTreeObj.expandNode(pathOfOne[i],true); //expand node
  87. }
  88. }
  89. });
  90. }else{ //show all nodes when _keywords is blank and expand the root nodes
  91. var rootNodes = zTreeObj.getNodesByParam('level','0');//get all root nodes
  92. $.each(rootNodes,function(n,obj){
  93. zTreeObj.expandNode(obj,true); //expand all root nodes
  94. });
  95. }
  96. }
  97. }
  98. //listen to change in input element
  99. $(searchField).bind('input propertychange', function() {
  100. var _keywords = $(this).val();
  101. searchNodeLazy(_keywords); //call lazy load
  102. });
  103. var timeoutId = null;
  104. var lastKeyword = '';
  105. // excute lazy load once after input change, the last pending task will be cancled
  106. function searchNodeLazy(_keywords) {
  107. if (timeoutId) {
  108. //clear pending task
  109. clearTimeout(timeoutId);
  110. }
  111. timeoutId = setTimeout(function() {
  112. if (lastKeyword === _keywords) {
  113. return;
  114. }
  115. ztreeFilter(zTreeObj,_keywords); //lazy load ztreeFilter function
  116. // $(searchField).focus();//focus input field again after filtering
  117. lastKeyword = _keywords;
  118. }, 500);
  119. }
  120. }