1 var Filter =
function(table){
6 this.headerFilters = {};
7 this.headerFilterColumns = [];
14 Filter.prototype.initializeColumn =
function(column, value){
16 field = column.getField(),
21 function success(value){
22 var filterType = (column.modules.filter.tagType ==
"input" && column.modules.filter.attrType ==
"text") || column.modules.filter.tagType ==
"textarea" ?
"partial" :
"match",
26 if(typeof column.modules.filter.prevSuccess ===
"undefined" || column.modules.filter.prevSuccess !== value){
28 column.modules.filter.prevSuccess = value;
30 if(!column.modules.filter.emptyFunc(value)){
31 column.modules.filter.value = value;
33 switch(typeof column.definition.headerFilterFunc){
35 if(
self.filters[column.definition.headerFilterFunc]){
36 type = column.definition.headerFilterFunc;
37 filterFunc =
function(data){
38 var params = column.definition.headerFilterFuncParams || {};
39 var fieldVal = column.getFieldValue(data);
41 params = typeof params ===
"function" ? params(value, fieldVal, data) : params;
43 return self.filters[column.definition.headerFilterFunc](value, fieldVal, data, params);
46 console.warn(
"Header Filter Error - Matching filter function not found: ", column.definition.headerFilterFunc);
51 filterFunc =
function(data){
52 var params = column.definition.headerFilterFuncParams || {};
53 var fieldVal = column.getFieldValue(data);
55 params = typeof params ===
"function" ? params(value, fieldVal, data) : params;
57 return column.definition.headerFilterFunc(value, fieldVal, data, params);
67 filterFunc =
function(data){
68 var colVal = column.getFieldValue(data);
70 if(typeof colVal !==
'undefined' && colVal !== null){
71 return String(colVal).toLowerCase().indexOf(String(value).toLowerCase()) > -1;
80 filterFunc =
function(data){
81 return column.getFieldValue(data) == value;
87 self.headerFilters[field] = {value:value, func:filterFunc, type:type};
90 delete self.headerFilters[field];
95 self.table.rowManager.filterRefresh();
101 column.modules.filter = {
108 this.generateHeaderFilterElement(column);
111 Filter.prototype.generateHeaderFilterElement =
function(column, initialValue, reinitialize){
113 success = column.modules.filter.success,
114 field = column.getField(),
115 filterElement, editor, editorElement, cellWrapper, typingTimer, searchTrigger, params;
120 if(column.modules.filter.headerElement && column.modules.filter.headerElement.parentNode){
121 column.contentElement.removeChild(column.modules.filter.headerElement.parentNode);
127 column.modules.filter.emptyFunc = column.definition.headerFilterEmptyCheck ||
function(value){
128 return !value && value !==
"0";
131 filterElement = document.createElement(
"div");
132 filterElement.classList.add(
"tabulator-header-filter");
135 switch(typeof column.definition.headerFilter){
137 if(
self.table.modules.edit.editors[column.definition.headerFilter]){
138 editor =
self.table.modules.edit.editors[column.definition.headerFilter];
140 if((column.definition.headerFilter ===
"tick" || column.definition.headerFilter ===
"tickCross") && !column.definition.headerFilterEmptyCheck){
141 column.modules.filter.emptyFunc =
function(value){
142 return value !==
true && value !==
false;
146 console.warn(
"Filter Error - Cannot build header filter, No such editor found: ", column.definition.editor);
151 editor = column.definition.headerFilter;
155 if(column.modules.edit && column.modules.edit.editor){
156 editor = column.modules.edit.editor;
158 if(column.definition.formatter &&
self.table.modules.edit.editors[column.definition.formatter]){
159 editor =
self.table.modules.edit.editors[column.definition.formatter];
161 if((column.definition.formatter ===
"tick" || column.definition.formatter ===
"tickCross") && !column.definition.headerFilterEmptyCheck){
162 column.modules.filter.emptyFunc =
function(value){
163 return value !==
true && value !==
false;
167 editor =
self.table.modules.edit.editors[
"input"];
177 return typeof initialValue !==
"undefined" ? initialValue :
"";
180 return column.definition.field;
182 getElement:
function(){
183 return filterElement;
185 getColumn:
function(){
186 return column.getComponent();
190 normalizeHeight:
function(){
197 params = column.definition.headerFilterParams || {};
199 params = typeof params ===
"function" ? params.call(
self.table) : params;
201 editorElement = editor.call(this.table.modules.edit, cellWrapper,
function(){}, success, cancel, params);
204 console.warn(
"Filter Error - Cannot add filter to " + field +
" column, editor returned a value of false");
208 if(!(editorElement instanceof Node)){
209 console.warn(
"Filter Error - Cannot add filter to " + field +
" column, editor should return an instance of Node, the editor returned:", editorElement);
215 self.table.modules.localize.bind(
"headerFilters|columns|" + column.definition.field,
function(value){
216 editorElement.setAttribute(
"placeholder", typeof value !==
"undefined" && value ? value :
self.table.modules.localize.getText(
"headerFilters|default"));
219 self.table.modules.localize.bind(
"headerFilters|default",
function(value){
220 editorElement.setAttribute(
"placeholder", typeof
self.column.definition.headerFilterPlaceholder !==
"undefined" &&
self.column.definition.headerFilterPlaceholder ?
self.column.definition.headerFilterPlaceholder : value);
225 editorElement.addEventListener(
"click",
function(e){
227 editorElement.focus();
230 editorElement.addEventListener(
"focus", (e) => {
231 var left = this.table.columnManager.element.scrollLeft;
233 if(left !== this.table.rowManager.element.scrollLeft){
234 this.table.rowManager.scrollHorizontal(left);
235 this.table.columnManager.scrollHorizontal(left);
242 searchTrigger =
function(e){
244 clearTimeout(typingTimer);
247 typingTimer = setTimeout(
function(){
248 success(editorElement.value);
249 },
self.table.options.headerFilterLiveFilterDelay);
252 column.modules.filter.headerElement = editorElement;
253 column.modules.filter.attrType = editorElement.hasAttribute(
"type") ? editorElement.getAttribute(
"type").toLowerCase() :
"" ;
254 column.modules.filter.tagType = editorElement.tagName.toLowerCase();
256 if(column.definition.headerFilterLiveFilter !==
false){
260 column.definition.headerFilter ===
'autocomplete' ||
261 column.definition.headerFilter ===
'tickCross' ||
262 ((column.definition.editor ===
'autocomplete' ||
263 column.definition.editor ===
'tickCross') &&
264 column.definition.headerFilter ===
true)
267 editorElement.addEventListener(
"keyup", searchTrigger);
268 editorElement.addEventListener(
"search", searchTrigger);
272 if(column.modules.filter.attrType ==
"number"){
273 editorElement.addEventListener(
"change",
function(e){
274 success(editorElement.value);
279 if(column.modules.filter.attrType ==
"text" &&
this.table.browser !==
"ie"){
280 editorElement.setAttribute(
"type",
"search");
287 if(column.modules.filter.tagType ==
"input" || column.modules.filter.tagType ==
"select" || column.modules.filter.tagType ==
"textarea"){
288 editorElement.addEventListener(
"mousedown",
function(e){
294 filterElement.appendChild(editorElement);
296 column.contentElement.appendChild(filterElement);
299 self.headerFilterColumns.push(column);
303 console.warn(
"Filter Error - Cannot add header filter, column has no field set:", column.definition.title);
308 Filter.prototype.hideHeaderFilterElements =
function(){
309 this.headerFilterColumns.forEach(
function(column){
310 if(column.modules.filter && column.modules.filter.headerElement){
311 column.modules.filter.headerElement.style.display =
'none';
317 Filter.prototype.showHeaderFilterElements =
function(){
318 this.headerFilterColumns.forEach(
function(column){
319 if(column.modules.filter && column.modules.filter.headerElement){
320 column.modules.filter.headerElement.style.display =
'';
327 Filter.prototype.setHeaderFilterFocus =
function(column){
328 if(column.modules.filter && column.modules.filter.headerElement){
329 column.modules.filter.headerElement.focus();
331 console.warn(
"Column Filter Focus Error - No header filter set on column:", column.getField());
336 Filter.prototype.setHeaderFilterValue =
function(column, value){
338 if(column.modules.filter && column.modules.filter.headerElement){
339 this.generateHeaderFilterElement(column, value,
true);
340 column.modules.filter.success(value);
342 console.warn(
"Column Filter Error - No header filter set on column:", column.getField());
347 Filter.prototype.reloadHeaderFilter =
function(column){
349 if(column.modules.filter && column.modules.filter.headerElement){
350 this.generateHeaderFilterElement(column, column.modules.filter.value,
true);
352 console.warn(
"Column Filter Error - No header filter set on column:", column.getField());
358 Filter.prototype.hasChanged =
function(){
359 var changed = this.changed;
360 this.changed =
false;
365 Filter.prototype.setFilter =
function(field, type, value){
368 self.filterList = [];
370 if(!Array.isArray(field)){
371 field = [{field:field, type:type, value:value}];
374 self.addFilter(field);
379 Filter.prototype.addFilter =
function(field, type, value){
382 if(!Array.isArray(field)){
383 field = [{field:field, type:type, value:value}];
386 field.forEach(
function(filter){
388 filter =
self.findFilter(filter);
391 self.filterList.push(filter);
397 if(this.table.options.persistence &&
this.table.modExists(
"persistence",
true) && this.table.modules.persistence.config.filter){
398 this.table.modules.persistence.save(
"filter");
403 Filter.prototype.findFilter =
function(filter){
407 if(Array.isArray(filter)){
408 return this.findSubFilters(filter);
412 var filterFunc =
false;
414 if(typeof filter.field ==
"function"){
415 filterFunc =
function(data){
416 return filter.field(data, filter.type || {})
420 if(
self.filters[filter.type]){
422 column =
self.table.columnManager.getColumnByField(filter.field);
425 filterFunc =
function(data){
426 return self.filters[filter.type](filter.value, column.getFieldValue(data));
429 filterFunc =
function(data){
430 return self.filters[filter.type](filter.value, data[filter.field]);
436 console.warn(
"Filter Error - No such filter type found, ignoring: ", filter.type);
441 filter.func = filterFunc;
445 return filter.func ? filter :
false;
448 Filter.prototype.findSubFilters =
function(filters){
452 filters.forEach(
function(filter){
453 filter =
self.findFilter(filter);
460 return output.length ? output :
false;
465 Filter.prototype.getFilters =
function(all, ajax){
469 output = this.getHeaderFilters();
473 output.forEach(
function(item){
474 if(typeof item.type ==
"function"){
475 item.type =
"function";
480 output = output.concat(
this.filtersToArray(
this.filterList, ajax));
486 Filter.prototype.filtersToArray =
function(filterList, ajax){
489 filterList.forEach((filter) => {
492 if(Array.isArray(filter)){
493 output.push(this.filtersToArray(filter, ajax));
495 item = {field:filter.field, type:filter.type, value:filter.value}
498 if(typeof item.type ==
"function"){
499 item.type =
"function";
511 Filter.prototype.getHeaderFilters =
function(){
515 for(var key in this.headerFilters){
516 output.push({field:key, type:this.headerFilters[key].type, value:this.headerFilters[key].value});
523 Filter.prototype.removeFilter =
function(field, type, value){
526 if(!Array.isArray(field)){
527 field = [{field:field, type:type, value:value}];
530 field.forEach(
function(filter){
533 if(typeof filter.field ==
"object"){
534 index =
self.filterList.findIndex(
function(element){
535 return filter === element;
538 index =
self.filterList.findIndex(
function(element){
539 return filter.field === element.field && filter.type === element.type && filter.value === element.value
544 self.filterList.splice(index, 1);
547 console.warn(
"Filter Error - No matching filter type found, ignoring: ", filter.type);
552 if(this.table.options.persistence &&
this.table.modExists(
"persistence",
true) && this.table.modules.persistence.config.filter){
553 this.table.modules.persistence.save(
"filter");
559 Filter.prototype.clearFilter =
function(all){
560 this.filterList = [];
563 this.clearHeaderFilter();
568 if(this.table.options.persistence &&
this.table.modExists(
"persistence",
true) && this.table.modules.persistence.config.filter){
569 this.table.modules.persistence.save(
"filter");
574 Filter.prototype.clearHeaderFilter =
function(){
577 this.headerFilters = {};
579 this.headerFilterColumns.forEach(
function(column){
580 column.modules.filter.value = null;
581 column.modules.filter.prevSuccess = undefined;
582 self.reloadHeaderFilter(column);
589 Filter.prototype.search =
function (searchType, field, type, value){
594 if(!Array.isArray(field)){
595 field = [{field:field, type:type, value:value}];
598 field.forEach(
function(filter){
599 filter =
self.findFilter(filter);
602 filterList.push(filter);
606 this.table.rowManager.rows.forEach(
function(row){
609 filterList.forEach(
function(filter){
610 if(!
self.filterRecurse(filter, row.getData())){
616 activeRows.push(searchType ===
"data" ? row.getData(
"data") : row.getComponent());
625 Filter.prototype.filter =
function(rowList, filters){
628 activeRowComponents = [];
630 if(
self.table.options.dataFiltering){
631 self.table.options.dataFiltering.call(
self.table,
self.getFilters());
634 if(!
self.table.options.ajaxFiltering && (
self.filterList.length || Object.keys(
self.headerFilters).length)){
636 rowList.forEach(
function(row){
637 if(
self.filterRow(row)){
638 activeRows.push(row);
643 activeRows = rowList.slice(0);
646 if(
self.table.options.dataFiltered){
648 activeRows.forEach(
function(row){
649 activeRowComponents.push(row.getComponent());
652 self.table.options.dataFiltered.call(
self.table,
self.getFilters(), activeRowComponents);
660 Filter.prototype.filterRow =
function(row, filters){
663 data = row.getData();
665 self.filterList.forEach(
function(filter){
666 if(!
self.filterRecurse(filter, data)){
672 for(var field in
self.headerFilters){
673 if(!
self.headerFilters[field].func(data)){
681 Filter.prototype.filterRecurse =
function(filter, data){
685 if(Array.isArray(filter)){
686 filter.forEach(
function(subFilter){
687 if(
self.filterRecurse(subFilter, data)){
692 match = filter.func(data);
701 Filter.prototype.filters ={
704 "=":
function(filterVal, rowVal, rowData, filterParams){
705 return rowVal == filterVal ?
true :
false;
709 "<":
function(filterVal, rowVal, rowData, filterParams){
710 return rowVal < filterVal ?
true :
false;
714 "<=":
function(filterVal, rowVal, rowData, filterParams){
715 return rowVal <= filterVal ?
true :
false;
719 ">":
function(filterVal, rowVal, rowData, filterParams){
720 return rowVal > filterVal ?
true :
false;
724 ">=":
function(filterVal, rowVal, rowData, filterParams){
725 return rowVal >= filterVal ?
true :
false;
729 "!=":
function(filterVal, rowVal, rowData, filterParams){
730 return rowVal != filterVal ?
true :
false;
733 "regex":
function(filterVal, rowVal, rowData, filterParams){
735 if(typeof filterVal ==
"string"){
736 filterVal =
new RegExp(filterVal);
739 return filterVal.test(rowVal);
743 "like":
function(filterVal, rowVal, rowData, filterParams){
744 if(filterVal === null || typeof filterVal ===
"undefined"){
745 return rowVal === filterVal ?
true :
false;
747 if(typeof rowVal !==
'undefined' && rowVal !== null){
748 return String(rowVal).toLowerCase().indexOf(filterVal.toLowerCase()) > -1;
757 "in":
function(filterVal, rowVal, rowData, filterParams){
758 if(Array.isArray(filterVal)){
759 return filterVal.indexOf(rowVal) > -1;
761 console.warn(
"Filter Error - filter value is not an array:", filterVal);
767 Tabulator.prototype.registerModule(
"filter", Filter);