jquery.quicksearch.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. (function($, window, document, undefined) {
  2. $.fn.quicksearch = function (target, opt) {
  3. var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({
  4. delay: 100,
  5. selector: null,
  6. stripeRows: null,
  7. loader: null,
  8. noResults: '',
  9. matchedResultsCount: 0,
  10. bind: 'keyup',
  11. onBefore: function () {
  12. return;
  13. },
  14. onAfter: function () {
  15. return;
  16. },
  17. show: function () {
  18. this.style.display = "";
  19. },
  20. hide: function () {
  21. this.style.display = "none";
  22. },
  23. prepareQuery: function (val) {
  24. return val.toLowerCase().split(' ');
  25. },
  26. testQuery: function (query, txt, _row) {
  27. for (var i = 0; i < query.length; i += 1) {
  28. if (txt.indexOf(query[i]) === -1) {
  29. return false;
  30. }
  31. }
  32. return true;
  33. }
  34. }, opt);
  35. this.go = function () {
  36. var i = 0,
  37. numMatchedRows = 0,
  38. noresults = true,
  39. query = options.prepareQuery(val),
  40. val_empty = (val.replace(' ', '').length === 0);
  41. for (var i = 0, len = rowcache.length; i < len; i++) {
  42. if (val_empty || options.testQuery(query, cache[i], rowcache[i])) {
  43. options.show.apply(rowcache[i]);
  44. noresults = false;
  45. numMatchedRows++;
  46. } else {
  47. options.hide.apply(rowcache[i]);
  48. }
  49. }
  50. if (noresults) {
  51. this.results(false);
  52. } else {
  53. this.results(true);
  54. this.stripe();
  55. }
  56. this.matchedResultsCount = numMatchedRows;
  57. this.loader(false);
  58. options.onAfter();
  59. return this;
  60. };
  61. /*
  62. * External API so that users can perform search programatically.
  63. * */
  64. this.search = function (submittedVal) {
  65. val = submittedVal;
  66. e.trigger();
  67. };
  68. /*
  69. * External API to get the number of matched results as seen in
  70. * https://github.com/ruiz107/quicksearch/commit/f78dc440b42d95ce9caed1d087174dd4359982d6
  71. * */
  72. this.currentMatchedResults = function() {
  73. return this.matchedResultsCount;
  74. };
  75. this.stripe = function () {
  76. if (typeof options.stripeRows === "object" && options.stripeRows !== null)
  77. {
  78. var joined = options.stripeRows.join(' ');
  79. var stripeRows_length = options.stripeRows.length;
  80. jq_results.not(':hidden').each(function (i) {
  81. $(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]);
  82. });
  83. }
  84. return this;
  85. };
  86. this.strip = function (input) {
  87. return $.trim(input.toLowerCase());
  88. };
  89. this.strip_html = function (input) {
  90. var output = input.replace(new RegExp('<[^<]+\>', 'g'), "");
  91. output = $.trim(output.toLowerCase());
  92. return output;
  93. };
  94. this.results = function (bool) {
  95. if (typeof options.noResults === "string" && options.noResults !== "") {
  96. if (bool) {
  97. $(options.noResults).hide();
  98. } else {
  99. $(options.noResults).show();
  100. }
  101. }
  102. return this;
  103. };
  104. this.loader = function (bool) {
  105. if (typeof options.loader === "string" && options.loader !== "") {
  106. (bool) ? $(options.loader).show() : $(options.loader).hide();
  107. }
  108. return this;
  109. };
  110. this.cache = function () {
  111. var type = $.type(target);
  112. // Target is a string - selector for HTML elements
  113. if(type==='string')
  114. jq_results = $(target);
  115. // Target is an array of objects
  116. else if(type==='array') {
  117. jq_results=target.slice();
  118. }
  119. // Target is an object containing ...
  120. else if(type==='object') {
  121. jq_results = [];
  122. $.each(target, function(key, val){
  123. // ... arrays of objects
  124. if(val instanceof Array)
  125. $.merge(jq_results,val);
  126. // ... other objects
  127. else
  128. jq_results.push(val);
  129. });
  130. }
  131. // if (typeof options.noResults==="string" && options.noResults!=="") {
  132. // jq_results = jq_results.not(options.noResults);
  133. // }
  134. // var t = (typeof options.selector === "string") ? jq_results.find(options.selector) : $(target).not(options.noResults);
  135. cache = $.map(jq_results, function (item) {
  136. return (type==='string') ? e.strip_html(item.innerHTML) : (typeof item.searchvalue==='string') ? e.strip(item.searchvalue) : '';
  137. });
  138. rowcache = $.map(jq_results, function (item) {
  139. return item;
  140. });
  141. /*
  142. * Modified fix for sync-ing "val".
  143. * Original fix https://github.com/michaellwest/quicksearch/commit/4ace4008d079298a01f97f885ba8fa956a9703d1
  144. * */
  145. val = val || this.val() || "";
  146. return this.go();
  147. };
  148. this.trigger = function () {
  149. this.loader(true);
  150. options.onBefore();
  151. window.clearTimeout(timeout);
  152. timeout = window.setTimeout(function () {
  153. e.go();
  154. }, options.delay);
  155. return this;
  156. };
  157. this.cache();
  158. this.results(true);
  159. this.stripe();
  160. this.loader(false);
  161. return this.each(function () {
  162. /*
  163. * Changed from .bind to .on.
  164. * */
  165. $(this).on(options.bind, function () {
  166. val = $(this).val();
  167. e.trigger();
  168. });
  169. });
  170. };
  171. }(jQuery, this, document));