otsdaq_utilities  v2_05_02_indev
filter.js
1 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
2 
3 /* Tabulator v4.5.3 (c) Oliver Folkerd */
4 
5 var Filter = function Filter(table) {
6 
7  this.table = table; //hold Tabulator object
8 
9  this.filterList = []; //hold filter list
10  this.headerFilters = {}; //hold column filters
11  this.headerFilterColumns = []; //hold columns that use header filters
12 
13  this.changed = false; //has filtering changed since last render
14 };
15 
16 //initialize column header filter
17 Filter.prototype.initializeColumn = function (column, value) {
18  var self = this,
19  field = column.getField(),
20  params;
21 
22  //handle successfull value change
23  function success(value) {
24  var filterType = column.modules.filter.tagType == "input" && column.modules.filter.attrType == "text" || column.modules.filter.tagType == "textarea" ? "partial" : "match",
25  type = "",
26  filterFunc;
27 
28  if (typeof column.modules.filter.prevSuccess === "undefined" || column.modules.filter.prevSuccess !== value) {
29 
30  column.modules.filter.prevSuccess = value;
31 
32  if (!column.modules.filter.emptyFunc(value)) {
33  column.modules.filter.value = value;
34 
35  switch (_typeof(column.definition.headerFilterFunc)) {
36  case "string":
37  if (self.filters[column.definition.headerFilterFunc]) {
38  type = column.definition.headerFilterFunc;
39  filterFunc = function filterFunc(data) {
40  var params = column.definition.headerFilterFuncParams || {};
41  var fieldVal = column.getFieldValue(data);
42 
43  params = typeof params === "function" ? params(value, fieldVal, data) : params;
44 
45  return self.filters[column.definition.headerFilterFunc](value, fieldVal, data, params);
46  };
47  } else {
48  console.warn("Header Filter Error - Matching filter function not found: ", column.definition.headerFilterFunc);
49  }
50  break;
51 
52  case "function":
53  filterFunc = function filterFunc(data) {
54  var params = column.definition.headerFilterFuncParams || {};
55  var fieldVal = column.getFieldValue(data);
56 
57  params = typeof params === "function" ? params(value, fieldVal, data) : params;
58 
59  return column.definition.headerFilterFunc(value, fieldVal, data, params);
60  };
61 
62  type = filterFunc;
63  break;
64  }
65 
66  if (!filterFunc) {
67  switch (filterType) {
68  case "partial":
69  filterFunc = function filterFunc(data) {
70  var colVal = column.getFieldValue(data);
71 
72  if (typeof colVal !== 'undefined' && colVal !== null) {
73  return String(colVal).toLowerCase().indexOf(String(value).toLowerCase()) > -1;
74  } else {
75  return false;
76  }
77  };
78  type = "like";
79  break;
80 
81  default:
82  filterFunc = function filterFunc(data) {
83  return column.getFieldValue(data) == value;
84  };
85  type = "=";
86  }
87  }
88 
89  self.headerFilters[field] = { value: value, func: filterFunc, type: type };
90  } else {
91  delete self.headerFilters[field];
92  }
93 
94  self.changed = true;
95 
96  self.table.rowManager.filterRefresh();
97  }
98 
99  return true;
100  }
101 
102  column.modules.filter = {
103  success: success,
104  attrType: false,
105  tagType: false,
106  emptyFunc: false
107  };
108 
109  this.generateHeaderFilterElement(column);
110 };
111 
112 Filter.prototype.generateHeaderFilterElement = function (column, initialValue, reinitialize) {
113  var _this = this;
114 
115  var self = this,
116  success = column.modules.filter.success,
117  field = column.getField(),
118  filterElement,
119  editor,
120  editorElement,
121  cellWrapper,
122  typingTimer,
123  searchTrigger,
124  params;
125 
126  //handle aborted edit
127  function cancel() {}
128 
129  if (column.modules.filter.headerElement && column.modules.filter.headerElement.parentNode) {
130  column.contentElement.removeChild(column.modules.filter.headerElement.parentNode);
131  }
132 
133  if (field) {
134 
135  //set empty value function
136  column.modules.filter.emptyFunc = column.definition.headerFilterEmptyCheck || function (value) {
137  return !value && value !== "0";
138  };
139 
140  filterElement = document.createElement("div");
141  filterElement.classList.add("tabulator-header-filter");
142 
143  //set column editor
144  switch (_typeof(column.definition.headerFilter)) {
145  case "string":
146  if (self.table.modules.edit.editors[column.definition.headerFilter]) {
147  editor = self.table.modules.edit.editors[column.definition.headerFilter];
148 
149  if ((column.definition.headerFilter === "tick" || column.definition.headerFilter === "tickCross") && !column.definition.headerFilterEmptyCheck) {
150  column.modules.filter.emptyFunc = function (value) {
151  return value !== true && value !== false;
152  };
153  }
154  } else {
155  console.warn("Filter Error - Cannot build header filter, No such editor found: ", column.definition.editor);
156  }
157  break;
158 
159  case "function":
160  editor = column.definition.headerFilter;
161  break;
162 
163  case "boolean":
164  if (column.modules.edit && column.modules.edit.editor) {
165  editor = column.modules.edit.editor;
166  } else {
167  if (column.definition.formatter && self.table.modules.edit.editors[column.definition.formatter]) {
168  editor = self.table.modules.edit.editors[column.definition.formatter];
169 
170  if ((column.definition.formatter === "tick" || column.definition.formatter === "tickCross") && !column.definition.headerFilterEmptyCheck) {
171  column.modules.filter.emptyFunc = function (value) {
172  return value !== true && value !== false;
173  };
174  }
175  } else {
176  editor = self.table.modules.edit.editors["input"];
177  }
178  }
179  break;
180  }
181 
182  if (editor) {
183 
184  cellWrapper = {
185  getValue: function getValue() {
186  return typeof initialValue !== "undefined" ? initialValue : "";
187  },
188  getField: function getField() {
189  return column.definition.field;
190  },
191  getElement: function getElement() {
192  return filterElement;
193  },
194  getColumn: function getColumn() {
195  return column.getComponent();
196  },
197  getRow: function getRow() {
198  return {
199  normalizeHeight: function normalizeHeight() {}
200  };
201  }
202  };
203 
204  params = column.definition.headerFilterParams || {};
205 
206  params = typeof params === "function" ? params.call(self.table) : params;
207 
208  editorElement = editor.call(this.table.modules.edit, cellWrapper, function () {}, success, cancel, params);
209 
210  if (!editorElement) {
211  console.warn("Filter Error - Cannot add filter to " + field + " column, editor returned a value of false");
212  return;
213  }
214 
215  if (!(editorElement instanceof Node)) {
216  console.warn("Filter Error - Cannot add filter to " + field + " column, editor should return an instance of Node, the editor returned:", editorElement);
217  return;
218  }
219 
220  //set Placeholder Text
221  if (field) {
222  self.table.modules.localize.bind("headerFilters|columns|" + column.definition.field, function (value) {
223  editorElement.setAttribute("placeholder", typeof value !== "undefined" && value ? value : self.table.modules.localize.getText("headerFilters|default"));
224  });
225  } else {
226  self.table.modules.localize.bind("headerFilters|default", function (value) {
227  editorElement.setAttribute("placeholder", typeof self.column.definition.headerFilterPlaceholder !== "undefined" && self.column.definition.headerFilterPlaceholder ? self.column.definition.headerFilterPlaceholder : value);
228  });
229  }
230 
231  //focus on element on click
232  editorElement.addEventListener("click", function (e) {
233  e.stopPropagation();
234  editorElement.focus();
235  });
236 
237  editorElement.addEventListener("focus", function (e) {
238  var left = _this.table.columnManager.element.scrollLeft;
239 
240  if (left !== _this.table.rowManager.element.scrollLeft) {
241  _this.table.rowManager.scrollHorizontal(left);
242  _this.table.columnManager.scrollHorizontal(left);
243  }
244  });
245 
246  //live update filters as user types
247  typingTimer = false;
248 
249  searchTrigger = function searchTrigger(e) {
250  if (typingTimer) {
251  clearTimeout(typingTimer);
252  }
253 
254  typingTimer = setTimeout(function () {
255  success(editorElement.value);
256  }, 300);
257  };
258 
259  column.modules.filter.headerElement = editorElement;
260  column.modules.filter.attrType = editorElement.hasAttribute("type") ? editorElement.getAttribute("type").toLowerCase() : "";
261  column.modules.filter.tagType = editorElement.tagName.toLowerCase();
262 
263  if (column.definition.headerFilterLiveFilter !== false) {
264 
265  if (!(column.definition.headerFilter === 'autocomplete' || column.definition.headerFilter === 'tickCross' || (column.definition.editor === 'autocomplete' || column.definition.editor === 'tickCross') && column.definition.headerFilter === true)) {
266  editorElement.addEventListener("keyup", searchTrigger);
267  editorElement.addEventListener("search", searchTrigger);
268 
269  //update number filtered columns on change
270  if (column.modules.filter.attrType == "number") {
271  editorElement.addEventListener("change", function (e) {
272  success(editorElement.value);
273  });
274  }
275 
276  //change text inputs to search inputs to allow for clearing of field
277  if (column.modules.filter.attrType == "text" && this.table.browser !== "ie") {
278  editorElement.setAttribute("type", "search");
279  // editorElement.off("change blur"); //prevent blur from triggering filter and preventing selection click
280  }
281  }
282 
283  //prevent input and select elements from propegating click to column sorters etc
284  if (column.modules.filter.tagType == "input" || column.modules.filter.tagType == "select" || column.modules.filter.tagType == "textarea") {
285  editorElement.addEventListener("mousedown", function (e) {
286  e.stopPropagation();
287  });
288  }
289  }
290 
291  filterElement.appendChild(editorElement);
292 
293  column.contentElement.appendChild(filterElement);
294 
295  if (!reinitialize) {
296  self.headerFilterColumns.push(column);
297  }
298  }
299  } else {
300  console.warn("Filter Error - Cannot add header filter, column has no field set:", column.definition.title);
301  }
302 };
303 
304 //hide all header filter elements (used to ensure correct column widths in "fitData" layout mode)
305 Filter.prototype.hideHeaderFilterElements = function () {
306  this.headerFilterColumns.forEach(function (column) {
307  if (column.modules.filter && column.modules.filter.headerElement) {
308  column.modules.filter.headerElement.style.display = 'none';
309  }
310  });
311 };
312 
313 //show all header filter elements (used to ensure correct column widths in "fitData" layout mode)
314 Filter.prototype.showHeaderFilterElements = function () {
315  this.headerFilterColumns.forEach(function (column) {
316  if (column.modules.filter && column.modules.filter.headerElement) {
317  column.modules.filter.headerElement.style.display = '';
318  }
319  });
320 };
321 
322 //programatically set value of header filter
323 Filter.prototype.setHeaderFilterFocus = function (column) {
324  if (column.modules.filter && column.modules.filter.headerElement) {
325  column.modules.filter.headerElement.focus();
326  } else {
327  console.warn("Column Filter Focus Error - No header filter set on column:", column.getField());
328  }
329 };
330 
331 //programatically set value of header filter
332 Filter.prototype.setHeaderFilterValue = function (column, value) {
333  if (column) {
334  if (column.modules.filter && column.modules.filter.headerElement) {
335  this.generateHeaderFilterElement(column, value, true);
336  column.modules.filter.success(value);
337  } else {
338  console.warn("Column Filter Error - No header filter set on column:", column.getField());
339  }
340  }
341 };
342 
343 Filter.prototype.reloadHeaderFilter = function (column) {
344  if (column) {
345  if (column.modules.filter && column.modules.filter.headerElement) {
346  this.generateHeaderFilterElement(column, column.modules.filter.value, true);
347  } else {
348  console.warn("Column Filter Error - No header filter set on column:", column.getField());
349  }
350  }
351 };
352 
353 //check if the filters has changed since last use
354 Filter.prototype.hasChanged = function () {
355  var changed = this.changed;
356  this.changed = false;
357  return changed;
358 };
359 
360 //set standard filters
361 Filter.prototype.setFilter = function (field, type, value) {
362  var self = this;
363 
364  self.filterList = [];
365 
366  if (!Array.isArray(field)) {
367  field = [{ field: field, type: type, value: value }];
368  }
369 
370  self.addFilter(field);
371 };
372 
373 //add filter to array
374 Filter.prototype.addFilter = function (field, type, value) {
375  var self = this;
376 
377  if (!Array.isArray(field)) {
378  field = [{ field: field, type: type, value: value }];
379  }
380 
381  field.forEach(function (filter) {
382 
383  filter = self.findFilter(filter);
384 
385  if (filter) {
386  self.filterList.push(filter);
387 
388  self.changed = true;
389  }
390  });
391 
392  if (this.table.options.persistence && this.table.modExists("persistence", true) && this.table.modules.persistence.config.filter) {
393  this.table.modules.persistence.save("filter");
394  }
395 };
396 
397 Filter.prototype.findFilter = function (filter) {
398  var self = this,
399  column;
400 
401  if (Array.isArray(filter)) {
402  return this.findSubFilters(filter);
403  }
404 
405  var filterFunc = false;
406 
407  if (typeof filter.field == "function") {
408  filterFunc = function filterFunc(data) {
409  return filter.field(data, filter.type || {}); // pass params to custom filter function
410  };
411  } else {
412 
413  if (self.filters[filter.type]) {
414 
415  column = self.table.columnManager.getColumnByField(filter.field);
416 
417  if (column) {
418  filterFunc = function filterFunc(data) {
419  return self.filters[filter.type](filter.value, column.getFieldValue(data));
420  };
421  } else {
422  filterFunc = function filterFunc(data) {
423  return self.filters[filter.type](filter.value, data[filter.field]);
424  };
425  }
426  } else {
427  console.warn("Filter Error - No such filter type found, ignoring: ", filter.type);
428  }
429  }
430 
431  filter.func = filterFunc;
432 
433  return filter.func ? filter : false;
434 };
435 
436 Filter.prototype.findSubFilters = function (filters) {
437  var self = this,
438  output = [];
439 
440  filters.forEach(function (filter) {
441  filter = self.findFilter(filter);
442 
443  if (filter) {
444  output.push(filter);
445  }
446  });
447 
448  return output.length ? output : false;
449 };
450 
451 //get all filters
452 Filter.prototype.getFilters = function (all, ajax) {
453  var output = [];
454 
455  if (all) {
456  output = this.getHeaderFilters();
457  }
458 
459  if (ajax) {
460  output.forEach(function (item) {
461  if (typeof item.type == "function") {
462  item.type = "function";
463  }
464  });
465  }
466 
467  output = output.concat(this.filtersToArray(this.filterList, ajax));
468 
469  return output;
470 };
471 
472 //filter to Object
473 Filter.prototype.filtersToArray = function (filterList, ajax) {
474  var _this2 = this;
475 
476  var output = [];
477 
478  filterList.forEach(function (filter) {
479  var item;
480 
481  if (Array.isArray(filter)) {
482  output.push(_this2.filtersToArray(filter, ajax));
483  } else {
484  item = { field: filter.field, type: filter.type, value: filter.value };
485 
486  if (ajax) {
487  if (typeof item.type == "function") {
488  item.type = "function";
489  }
490  }
491 
492  output.push(item);
493  }
494  });
495 
496  return output;
497 };
498 
499 //get all filters
500 Filter.prototype.getHeaderFilters = function () {
501  var self = this,
502  output = [];
503 
504  for (var key in this.headerFilters) {
505  output.push({ field: key, type: this.headerFilters[key].type, value: this.headerFilters[key].value });
506  }
507 
508  return output;
509 };
510 
511 //remove filter from array
512 Filter.prototype.removeFilter = function (field, type, value) {
513  var self = this;
514 
515  if (!Array.isArray(field)) {
516  field = [{ field: field, type: type, value: value }];
517  }
518 
519  field.forEach(function (filter) {
520  var index = -1;
521 
522  if (_typeof(filter.field) == "object") {
523  index = self.filterList.findIndex(function (element) {
524  return filter === element;
525  });
526  } else {
527  index = self.filterList.findIndex(function (element) {
528  return filter.field === element.field && filter.type === element.type && filter.value === element.value;
529  });
530  }
531 
532  if (index > -1) {
533  self.filterList.splice(index, 1);
534  self.changed = true;
535  } else {
536  console.warn("Filter Error - No matching filter type found, ignoring: ", filter.type);
537  }
538  });
539 
540  if (this.table.options.persistence && this.table.modExists("persistence", true) && this.table.modules.persistence.config.filter) {
541  this.table.modules.persistence.save("filter");
542  }
543 };
544 
545 //clear filters
546 Filter.prototype.clearFilter = function (all) {
547  this.filterList = [];
548 
549  if (all) {
550  this.clearHeaderFilter();
551  }
552 
553  this.changed = true;
554 
555  if (this.table.options.persistence && this.table.modExists("persistence", true) && this.table.modules.persistence.config.filter) {
556  this.table.modules.persistence.save("filter");
557  }
558 };
559 
560 //clear header filters
561 Filter.prototype.clearHeaderFilter = function () {
562  var self = this;
563 
564  this.headerFilters = {};
565 
566  this.headerFilterColumns.forEach(function (column) {
567  column.modules.filter.value = null;
568  column.modules.filter.prevSuccess = undefined;
569  self.reloadHeaderFilter(column);
570  });
571 
572  this.changed = true;
573 };
574 
575 //search data and return matching rows
576 Filter.prototype.search = function (searchType, field, type, value) {
577  var self = this,
578  activeRows = [],
579  filterList = [];
580 
581  if (!Array.isArray(field)) {
582  field = [{ field: field, type: type, value: value }];
583  }
584 
585  field.forEach(function (filter) {
586  filter = self.findFilter(filter);
587 
588  if (filter) {
589  filterList.push(filter);
590  }
591  });
592 
593  this.table.rowManager.rows.forEach(function (row) {
594  var match = true;
595 
596  filterList.forEach(function (filter) {
597  if (!self.filterRecurse(filter, row.getData())) {
598  match = false;
599  }
600  });
601 
602  if (match) {
603  activeRows.push(searchType === "data" ? row.getData("data") : row.getComponent());
604  }
605  });
606 
607  return activeRows;
608 };
609 
610 //filter row array
611 Filter.prototype.filter = function (rowList, filters) {
612  var self = this,
613  activeRows = [],
614  activeRowComponents = [];
615 
616  if (self.table.options.dataFiltering) {
617  self.table.options.dataFiltering.call(self.table, self.getFilters());
618  }
619 
620  if (!self.table.options.ajaxFiltering && (self.filterList.length || Object.keys(self.headerFilters).length)) {
621 
622  rowList.forEach(function (row) {
623  if (self.filterRow(row)) {
624  activeRows.push(row);
625  }
626  });
627  } else {
628  activeRows = rowList.slice(0);
629  }
630 
631  if (self.table.options.dataFiltered) {
632 
633  activeRows.forEach(function (row) {
634  activeRowComponents.push(row.getComponent());
635  });
636 
637  self.table.options.dataFiltered.call(self.table, self.getFilters(), activeRowComponents);
638  }
639 
640  return activeRows;
641 };
642 
643 //filter individual row
644 Filter.prototype.filterRow = function (row, filters) {
645  var self = this,
646  match = true,
647  data = row.getData();
648 
649  self.filterList.forEach(function (filter) {
650  if (!self.filterRecurse(filter, data)) {
651  match = false;
652  }
653  });
654 
655  for (var field in self.headerFilters) {
656  if (!self.headerFilters[field].func(data)) {
657  match = false;
658  }
659  }
660 
661  return match;
662 };
663 
664 Filter.prototype.filterRecurse = function (filter, data) {
665  var self = this,
666  match = false;
667 
668  if (Array.isArray(filter)) {
669  filter.forEach(function (subFilter) {
670  if (self.filterRecurse(subFilter, data)) {
671  match = true;
672  }
673  });
674  } else {
675  match = filter.func(data);
676  }
677 
678  return match;
679 };
680 
681 //list of available filters
682 Filter.prototype.filters = {
683 
684  //equal to
685  "=": function _(filterVal, rowVal, rowData, filterParams) {
686  return rowVal == filterVal ? true : false;
687  },
688 
689  //less than
690  "<": function _(filterVal, rowVal, rowData, filterParams) {
691  return rowVal < filterVal ? true : false;
692  },
693 
694  //less than or equal to
695  "<=": function _(filterVal, rowVal, rowData, filterParams) {
696  return rowVal <= filterVal ? true : false;
697  },
698 
699  //greater than
700  ">": function _(filterVal, rowVal, rowData, filterParams) {
701  return rowVal > filterVal ? true : false;
702  },
703 
704  //greater than or equal to
705  ">=": function _(filterVal, rowVal, rowData, filterParams) {
706  return rowVal >= filterVal ? true : false;
707  },
708 
709  //not equal to
710  "!=": function _(filterVal, rowVal, rowData, filterParams) {
711  return rowVal != filterVal ? true : false;
712  },
713 
714  "regex": function regex(filterVal, rowVal, rowData, filterParams) {
715 
716  if (typeof filterVal == "string") {
717  filterVal = new RegExp(filterVal);
718  }
719 
720  return filterVal.test(rowVal);
721  },
722 
723  //contains the string
724  "like": function like(filterVal, rowVal, rowData, filterParams) {
725  if (filterVal === null || typeof filterVal === "undefined") {
726  return rowVal === filterVal ? true : false;
727  } else {
728  if (typeof rowVal !== 'undefined' && rowVal !== null) {
729  return String(rowVal).toLowerCase().indexOf(filterVal.toLowerCase()) > -1;
730  } else {
731  return false;
732  }
733  }
734  },
735 
736  //in array
737  "in": function _in(filterVal, rowVal, rowData, filterParams) {
738  if (Array.isArray(filterVal)) {
739  return filterVal.indexOf(rowVal) > -1;
740  } else {
741  console.warn("Filter Error - filter value is not an array:", filterVal);
742  return false;
743  }
744  }
745 };
746 
747 Tabulator.prototype.registerModule("filter", Filter);