bootstrap-table-filter-control.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /**
  2. * @author: Dennis Hernández
  3. * @webSite: http://djhvscf.github.io/Blog
  4. * @version: v1.0.0
  5. */
  6. !function ($) {
  7. 'use strict';
  8. var sprintf = $.fn.bootstrapTable.utils.sprintf;
  9. var addOptionToSelectControl = function (selectControl, value, text) {
  10. selectControl = $(selectControl.get(selectControl.length - 1));
  11. if (existsOptionInSelectControl(selectControl, value)) {
  12. selectControl.append($("<option></option>")
  13. .attr("value", value)
  14. .text($('<div />').html(text).text()));
  15. // Sort it. Not overly efficient to do this here
  16. var $opts = selectControl.find('option:gt(0)');
  17. $opts.sort(function (a, b) {
  18. a = $(a).text().toLowerCase();
  19. b = $(b).text().toLowerCase();
  20. if ($.isNumeric(a) && $.isNumeric(b)) {
  21. // Convert numerical values from string to float.
  22. a = parseFloat(a);
  23. b = parseFloat(b);
  24. }
  25. return a > b ? 1 : a < b ? -1 : 0;
  26. });
  27. selectControl.find('option:gt(0)').remove();
  28. selectControl.append($opts);
  29. }
  30. };
  31. var existsOptionInSelectControl = function (selectControl, value) {
  32. var options = selectControl.get(selectControl.length - 1).options;
  33. for (var i = 0; i < options.length; i++) {
  34. if (options[i].value === value.toString()) {
  35. //The value is nor valid to add
  36. return false;
  37. }
  38. }
  39. //If we get here, the value is valid to add
  40. return true;
  41. };
  42. var fixHeaderCSS = function (that) {
  43. that.$tableHeader.css('height', '77px');
  44. };
  45. var getCurrentHeader = function (that) {
  46. var header = that.$header;
  47. if (that.options.height) {
  48. header = that.$tableHeader;
  49. }
  50. return header;
  51. };
  52. var getCurrentSearchControls = function (that) {
  53. var searchControls = 'select, input';
  54. if (that.options.height) {
  55. searchControls = 'table select, table input';
  56. }
  57. return searchControls;
  58. };
  59. var copyValues = function (that) {
  60. var header = getCurrentHeader(that),
  61. searchControls = getCurrentSearchControls(that);
  62. that.options.values = [];
  63. header.find(searchControls).each(function () {
  64. that.options.values.push(
  65. {
  66. field: $(this).parent().parent().parent().data('field'),
  67. value: $(this).val()
  68. });
  69. });
  70. };
  71. var setValues = function(that) {
  72. var field = null,
  73. result = [],
  74. header = getCurrentHeader(that),
  75. searchControls = getCurrentSearchControls(that);
  76. if (that.options.values.length > 0) {
  77. header.find(searchControls).each(function (index, ele) {
  78. field = $(this).parent().parent().parent().data('field');
  79. result = $.grep(that.options.values, function (valueObj) {
  80. return valueObj.field === field;
  81. });
  82. if (result.length > 0) {
  83. $(this).val(result[0].value);
  84. }
  85. });
  86. }
  87. };
  88. var createControls = function (that, header) {
  89. var addedFilterControl = false,
  90. isVisible,
  91. html,
  92. timeoutId = 0;
  93. $.each(that.columns, function (i, column) {
  94. isVisible = 'hidden';
  95. html = [];
  96. if (!column.visible) {
  97. return;
  98. }
  99. if (!column.filterControl) {
  100. html.push('<div style="height: 34px;"></div>');
  101. } else {
  102. html.push('<div style="margin: 0px 2px 2px 2px;" class="filterControl">');
  103. if (column.filterControl && column.searchable) {
  104. addedFilterControl = true;
  105. isVisible = 'visible'
  106. }
  107. switch (column.filterControl.toLowerCase()) {
  108. case 'input' :
  109. html.push(sprintf('<input type="text" class="form-control" style="width: 100%; visibility: %s">', isVisible));
  110. break;
  111. case 'select':
  112. html.push(sprintf('<select class="%s form-control" style="width: 100%; visibility: %s"></select>',
  113. column.field, isVisible))
  114. break;
  115. case 'datepicker':
  116. html.push(sprintf('<input type="text" class="date-filter-control %s form-control" style="width: 100%; visibility: %s">',
  117. column.field, isVisible));
  118. break;
  119. }
  120. }
  121. $.each(header.children().children(), function (i, tr) {
  122. tr = $(tr);
  123. if (tr.data('field') === column.field) {
  124. tr.find('.fht-cell').append(html.join(''));
  125. return false;
  126. }
  127. });
  128. if (column.filterData !== undefined && column.filterData.toLowerCase() !== 'column') {
  129. var filterDataType = column.filterData.substring(0, 3);
  130. var filterDataSource = column.filterData.substring(4, column.filterData.length);
  131. var selectControl = $('.' + column.field);
  132. addOptionToSelectControl(selectControl, '', '');
  133. switch (filterDataType) {
  134. case 'url':
  135. $.ajax({
  136. url: filterDataSource,
  137. dataType: 'json',
  138. success: function (data) {
  139. $.each(data, function (key, value) {
  140. addOptionToSelectControl(selectControl, key, value);
  141. });
  142. }
  143. });
  144. break;
  145. case 'var':
  146. var variableValues = window[filterDataSource];
  147. for (var key in variableValues) {
  148. addOptionToSelectControl(selectControl, key, variableValues[key]);
  149. }
  150. break;
  151. }
  152. }
  153. });
  154. if (addedFilterControl) {
  155. header.off('keyup', 'input').on('keyup', 'input', function (event) {
  156. clearTimeout(timeoutId);
  157. timeoutId = setTimeout(function () {
  158. that.onColumnSearch(event);
  159. }, that.options.searchTimeOut);
  160. });
  161. header.off('change', 'select').on('change', 'select', function (event) {
  162. clearTimeout(timeoutId);
  163. timeoutId = setTimeout(function () {
  164. that.onColumnSearch(event);
  165. }, that.options.searchTimeOut);
  166. });
  167. header.off('mouseup', 'input').on('mouseup', 'input', function (event) {
  168. var $input = $(this),
  169. oldValue = $input.val();
  170. if (oldValue === "") {
  171. return;
  172. }
  173. setTimeout(function(){
  174. var newValue = $input.val();
  175. if (newValue === "") {
  176. clearTimeout(timeoutId);
  177. timeoutId = setTimeout(function () {
  178. that.onColumnSearch(event);
  179. }, that.options.searchTimeOut);
  180. }
  181. }, 1);
  182. });
  183. if (header.find('.date-filter-control').length > 0) {
  184. $.each(that.columns, function (i, column) {
  185. if (column.filterControl !== undefined && column.filterControl.toLowerCase() === 'datepicker') {
  186. header.find('.date-filter-control.' + column.field).datepicker(column.filterDatepickerOptions)
  187. .on('changeDate', function (e) {
  188. //Fired the keyup event
  189. $(e.currentTarget).keyup();
  190. });
  191. }
  192. });
  193. }
  194. } else {
  195. header.find('.filterControl').hide();
  196. }
  197. };
  198. $.extend($.fn.bootstrapTable.defaults, {
  199. filterControl: false,
  200. onColumnSearch: function (field, text) {
  201. return false;
  202. },
  203. filterShowClear: false,
  204. //internal variables
  205. values: []
  206. });
  207. $.extend($.fn.bootstrapTable.COLUMN_DEFAULTS, {
  208. filterControl: undefined,
  209. filterData: undefined,
  210. filterDatepickerOptions: undefined,
  211. filterStrictSearch: false
  212. });
  213. $.extend($.fn.bootstrapTable.Constructor.EVENTS, {
  214. 'column-search.bs.table': 'onColumnSearch'
  215. });
  216. var BootstrapTable = $.fn.bootstrapTable.Constructor,
  217. _init = BootstrapTable.prototype.init,
  218. _initToolbar = BootstrapTable.prototype.initToolbar,
  219. _initHeader = BootstrapTable.prototype.initHeader,
  220. _initBody = BootstrapTable.prototype.initBody,
  221. _initSearch = BootstrapTable.prototype.initSearch;
  222. BootstrapTable.prototype.init = function () {
  223. //Make sure that the filtercontrol option is set
  224. if (this.options.filterControl) {
  225. var that = this;
  226. //Make sure that the internal variables are set correctly
  227. this.options.values = [];
  228. this.$el.on('reset-view.bs.table', function () {
  229. //Create controls on $tableHeader if the height is set
  230. if (!that.options.height) {
  231. return;
  232. }
  233. //Avoid recreate the controls
  234. if (that.$tableHeader.find('select').length > 0 || that.$tableHeader.find('input').length > 0) {
  235. return;
  236. }
  237. createControls(that, that.$tableHeader);
  238. }).on('post-header.bs.table', function () {
  239. setValues(that);
  240. }).on('post-body.bs.table', function () {
  241. if (that.options.height) {
  242. fixHeaderCSS(that);
  243. }
  244. }).on('column-switch.bs.table', function(field, checked) {
  245. setValues(that);
  246. });
  247. }
  248. _init.apply(this, Array.prototype.slice.apply(arguments));
  249. };
  250. BootstrapTable.prototype.initToolbar = function () {
  251. if ((!this.showToolbar) && (this.options.filterControl)) {
  252. this.showToolbar = this.options.filterControl;
  253. }
  254. _initToolbar.apply(this, Array.prototype.slice.apply(arguments));
  255. if (this.options.filterControl && this.options.filterShowClear) {
  256. var $btnGroup = this.$toolbar.find('>.btn-group'),
  257. $btnClear = $btnGroup.find('div.export');
  258. if (!$btnClear.length) {
  259. $btnClear = $([
  260. '<button class="btn btn-default " ' +
  261. 'type="button">',
  262. '<i class="glyphicon glyphicon-trash icon-share"></i> ',
  263. '</button>',
  264. '</ul>'].join('')).appendTo($btnGroup);
  265. $btnClear.off('click').on('click', $.proxy(this.clearFilterControl, this));
  266. }
  267. }
  268. };
  269. BootstrapTable.prototype.initHeader = function () {
  270. _initHeader.apply(this, Array.prototype.slice.apply(arguments));
  271. if (!this.options.filterControl) {
  272. return;
  273. }
  274. createControls(this, this.$header);
  275. };
  276. BootstrapTable.prototype.initBody = function () {
  277. _initBody.apply(this, Array.prototype.slice.apply(arguments));
  278. var that = this,
  279. data = this.options.data,
  280. pageTo = this.pageTo < this.options.data.length ? this.options.data.length : this.pageTo;
  281. for (var i = this.pageFrom - 1; i < pageTo; i++) {
  282. var item = data[i];
  283. $.each(this.header.fields, function (j, field) {
  284. var value = item[field],
  285. column = that.columns[$.fn.bootstrapTable.utils.getFieldIndex(that.columns, field)];
  286. value = $.fn.bootstrapTable.utils.calculateObjectValue(that.header, that.header.formatters[j], [value, item, i], value);
  287. if ((!column.checkbox) || (!column.radio)) {
  288. if (column.filterControl !== undefined && column.filterControl.toLowerCase() === 'select' && column.searchable) {
  289. if (column.filterData === undefined || column.filterData.toLowerCase() === 'column') {
  290. var selectControl = $('.' + column.field);
  291. if (selectControl !== undefined && selectControl.length > 0) {
  292. if (selectControl.get(selectControl.length - 1).options.length === 0) {
  293. //Added the default option
  294. addOptionToSelectControl(selectControl, '', '');
  295. }
  296. //Added a new value
  297. addOptionToSelectControl(selectControl, value, value);
  298. }
  299. }
  300. }
  301. }
  302. });
  303. }
  304. };
  305. BootstrapTable.prototype.initSearch = function () {
  306. _initSearch.apply(this, Array.prototype.slice.apply(arguments));
  307. var that = this;
  308. var fp = $.isEmptyObject(this.filterColumnsPartial) ? null : this.filterColumnsPartial;
  309. //Check partial column filter
  310. this.data = fp ? $.grep(this.data, function (item, i) {
  311. for (var key in fp) {
  312. var thisColumn = that.columns[$.fn.bootstrapTable.utils.getFieldIndex(that.columns, key)];
  313. var fval = fp[key].toLowerCase();
  314. var value = item[key];
  315. value = $.fn.bootstrapTable.utils.calculateObjectValue(that.header,
  316. that.header.formatters[$.inArray(key, that.header.fields)],
  317. [value, item, i], value);
  318. if(thisColumn.filterStrictSearch){
  319. if (!($.inArray(key, that.header.fields) !== -1 &&
  320. (typeof value === 'string' || typeof value === 'number') &&
  321. value.toString().toLowerCase() === fval.toString().toLowerCase())) {
  322. return false;
  323. }
  324. }
  325. else{
  326. if (!($.inArray(key, that.header.fields) !== -1 &&
  327. (typeof value === 'string' || typeof value === 'number') &&
  328. (value + '').toLowerCase().indexOf(fval) !== -1)) {
  329. return false;
  330. }
  331. };
  332. }
  333. return true;
  334. }) : this.data;
  335. };
  336. BootstrapTable.prototype.onColumnSearch = function (event) {
  337. copyValues(this);
  338. var text = $.trim($(event.currentTarget).val());
  339. var $field = $(event.currentTarget).parent().parent().parent().data('field')
  340. if ($.isEmptyObject(this.filterColumnsPartial)) {
  341. this.filterColumnsPartial = {};
  342. }
  343. if (text) {
  344. this.filterColumnsPartial[$field] = text;
  345. } else {
  346. delete this.filterColumnsPartial[$field];
  347. }
  348. this.options.pageNumber = 1;
  349. this.onSearch(event);
  350. this.updatePagination();
  351. this.trigger('column-search', $field, text);
  352. };
  353. BootstrapTable.prototype.clearFilterControl = function () {
  354. if (this.options.filterControl && this.options.filterShowClear) {
  355. $.each(this.options.values, function (i, item) {
  356. item.value = '';
  357. });
  358. setValues(this);
  359. var controls = getCurrentHeader(this).find(getCurrentSearchControls(this)),
  360. timeoutId = 0;
  361. if (controls.length > 0) {
  362. this.filterColumnsPartial = {};
  363. clearTimeout(timeoutId);
  364. timeoutId = setTimeout(function () {
  365. $(controls[0]).trigger(controls[0].tagName === 'INPUT' ? 'keyup' : 'change');
  366. }, this.options.searchTimeOut);
  367. }
  368. }
  369. };
  370. }(jQuery);