tabulator-tables 5.4.2 → 5.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/.babelrc.json +3 -3
  2. package/.editorconfig +6 -6
  3. package/.eslintignore +3 -3
  4. package/.eslintrc.js +28 -28
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +58 -58
  6. package/.github/ISSUE_TEMPLATE/documentation.md +14 -14
  7. package/.github/ISSUE_TEMPLATE/feature_request.md +24 -24
  8. package/.github/ISSUE_TEMPLATE/question.md +12 -12
  9. package/.github/workflows/bad-files-check.yml +39 -39
  10. package/.github/workflows/lint-and-test.yml +30 -30
  11. package/CODE_OF_CONDUCT.md +46 -46
  12. package/CONTRIBUTING.md +22 -22
  13. package/LICENSE +20 -20
  14. package/README.md +76 -76
  15. package/bower.json +40 -40
  16. package/build/Bundler.js +185 -185
  17. package/build/rollup.js +6 -6
  18. package/dist/css/tabulator.css +1 -5
  19. package/dist/css/tabulator.css.map +1 -1
  20. package/dist/css/tabulator.min.css +1 -1
  21. package/dist/css/tabulator.min.css.map +1 -1
  22. package/dist/css/tabulator_bootstrap3.css +1 -5
  23. package/dist/css/tabulator_bootstrap3.css.map +1 -1
  24. package/dist/css/tabulator_bootstrap3.min.css +1 -1
  25. package/dist/css/tabulator_bootstrap3.min.css.map +1 -1
  26. package/dist/css/tabulator_bootstrap4.css +1 -5
  27. package/dist/css/tabulator_bootstrap4.css.map +1 -1
  28. package/dist/css/tabulator_bootstrap4.min.css +1 -1
  29. package/dist/css/tabulator_bootstrap4.min.css.map +1 -1
  30. package/dist/css/tabulator_bootstrap5.css +1 -5
  31. package/dist/css/tabulator_bootstrap5.css.map +1 -1
  32. package/dist/css/tabulator_bootstrap5.min.css +1 -1
  33. package/dist/css/tabulator_bootstrap5.min.css.map +1 -1
  34. package/dist/css/tabulator_bulma.css +1 -5
  35. package/dist/css/tabulator_bulma.css.map +1 -1
  36. package/dist/css/tabulator_bulma.min.css +1 -1
  37. package/dist/css/tabulator_bulma.min.css.map +1 -1
  38. package/dist/css/tabulator_materialize.css +1 -5
  39. package/dist/css/tabulator_materialize.css.map +1 -1
  40. package/dist/css/tabulator_materialize.min.css +1 -1
  41. package/dist/css/tabulator_materialize.min.css.map +1 -1
  42. package/dist/css/tabulator_midnight.css +1 -5
  43. package/dist/css/tabulator_midnight.css.map +1 -1
  44. package/dist/css/tabulator_midnight.min.css +1 -1
  45. package/dist/css/tabulator_midnight.min.css.map +1 -1
  46. package/dist/css/tabulator_modern.css +1 -5
  47. package/dist/css/tabulator_modern.css.map +1 -1
  48. package/dist/css/tabulator_modern.min.css +1 -1
  49. package/dist/css/tabulator_modern.min.css.map +1 -1
  50. package/dist/css/tabulator_semanticui.css +103 -107
  51. package/dist/css/tabulator_semanticui.css.map +1 -1
  52. package/dist/css/tabulator_semanticui.min.css +1 -1
  53. package/dist/css/tabulator_semanticui.min.css.map +1 -1
  54. package/dist/css/tabulator_simple.css +1 -5
  55. package/dist/css/tabulator_simple.css.map +1 -1
  56. package/dist/css/tabulator_simple.min.css +1 -1
  57. package/dist/css/tabulator_simple.min.css.map +1 -1
  58. package/dist/css/tabulator_site.css +1 -5
  59. package/dist/css/tabulator_site.css.map +1 -1
  60. package/dist/css/tabulator_site.min.css +1 -1
  61. package/dist/css/tabulator_site.min.css.map +1 -1
  62. package/dist/js/jquery_wrapper.js +55 -55
  63. package/dist/js/tabulator.js +25847 -25653
  64. package/dist/js/tabulator.js.map +1 -1
  65. package/dist/js/tabulator.min.js +2 -2
  66. package/dist/js/tabulator.min.js.map +1 -1
  67. package/dist/js/tabulator_esm.js +25926 -25732
  68. package/dist/js/tabulator_esm.js.map +1 -1
  69. package/dist/js/tabulator_esm.min.js +2 -2
  70. package/dist/js/tabulator_esm.min.js.map +1 -1
  71. package/package.json +65 -65
  72. package/src/js/builds/esm.js +14 -14
  73. package/src/js/builds/jquery_wrapper.js +55 -55
  74. package/src/js/core/ColumnManager.js +730 -730
  75. package/src/js/core/CoreFeature.js +138 -138
  76. package/src/js/core/FooterManager.js +101 -101
  77. package/src/js/core/Module.js +141 -141
  78. package/src/js/core/RowManager.js +1112 -1082
  79. package/src/js/core/Tabulator.js +895 -893
  80. package/src/js/core/TabulatorFull.js +10 -10
  81. package/src/js/core/cell/Cell.js +295 -295
  82. package/src/js/core/cell/CellComponent.js +76 -76
  83. package/src/js/core/column/Column.js +949 -949
  84. package/src/js/core/column/ColumnComponent.js +152 -152
  85. package/src/js/core/column/defaults/options.js +17 -17
  86. package/src/js/core/defaults/options.js +65 -65
  87. package/src/js/core/modules/core.js +2 -2
  88. package/src/js/core/modules/optional.js +34 -34
  89. package/src/js/core/rendering/Renderer.js +203 -203
  90. package/src/js/core/rendering/renderers/BasicHorizontal.js +19 -19
  91. package/src/js/core/rendering/renderers/BasicVertical.js +79 -78
  92. package/src/js/core/rendering/renderers/VirtualDomHorizontal.js +577 -577
  93. package/src/js/core/rendering/renderers/VirtualDomVertical.js +579 -579
  94. package/src/js/core/row/PseudoRow.js +44 -44
  95. package/src/js/core/row/Row.js +457 -457
  96. package/src/js/core/row/RowComponent.js +93 -93
  97. package/src/js/core/tools/Alert.js +61 -61
  98. package/src/js/core/tools/ComponentFunctionBinder.js +32 -32
  99. package/src/js/core/tools/DataLoader.js +119 -119
  100. package/src/js/core/tools/DeprecationAdvisor.js +46 -46
  101. package/src/js/core/tools/ExternalEventBus.js +104 -104
  102. package/src/js/core/tools/Helpers.js +46 -46
  103. package/src/js/core/tools/InteractionMonitor.js +321 -321
  104. package/src/js/core/tools/InternalEventBus.js +161 -161
  105. package/src/js/core/tools/ModuleBinder.js +104 -104
  106. package/src/js/core/tools/OptionsList.js +44 -40
  107. package/src/js/core/tools/Popup.js +304 -304
  108. package/src/js/core/tools/TableRegistry.js +61 -61
  109. package/src/js/modules/Accessor/Accessor.js +115 -115
  110. package/src/js/modules/Ajax/Ajax.js +143 -143
  111. package/src/js/modules/Ajax/defaults/config.js +2 -2
  112. package/src/js/modules/Ajax/defaults/contentTypeFormatters.js +44 -44
  113. package/src/js/modules/Ajax/defaults/loaderPromise.js +86 -86
  114. package/src/js/modules/Ajax/defaults/urlGenerator.js +43 -43
  115. package/src/js/modules/Clipboard/Clipboard.js +279 -279
  116. package/src/js/modules/Clipboard/defaults/pasteActions.js +10 -10
  117. package/src/js/modules/Clipboard/defaults/pasteParsers.js +74 -74
  118. package/src/js/modules/ColumnCalcs/CalcComponent.js +47 -47
  119. package/src/js/modules/ColumnCalcs/ColumnCalcs.js +581 -568
  120. package/src/js/modules/ColumnCalcs/defaults/calculations.js +85 -85
  121. package/src/js/modules/Comms/Comms.js +51 -51
  122. package/src/js/modules/DataTree/DataTree.js +603 -603
  123. package/src/js/modules/Download/Download.js +148 -148
  124. package/src/js/modules/Download/defaults/downloaders/csv.js +61 -61
  125. package/src/js/modules/Download/defaults/downloaders/html.js +4 -4
  126. package/src/js/modules/Download/defaults/downloaders/json.js +33 -33
  127. package/src/js/modules/Download/defaults/downloaders/jsonLines.js +31 -31
  128. package/src/js/modules/Download/defaults/downloaders/pdf.js +111 -111
  129. package/src/js/modules/Download/defaults/downloaders/xlsx.js +98 -98
  130. package/src/js/modules/Download/defaults/downloaders.js +14 -14
  131. package/src/js/modules/Edit/Edit.js +735 -736
  132. package/src/js/modules/Edit/List.js +1037 -1033
  133. package/src/js/modules/Edit/defaults/editors/autocomplete.js +11 -11
  134. package/src/js/modules/Edit/defaults/editors/date.js +138 -110
  135. package/src/js/modules/Edit/defaults/editors/datetime.js +125 -97
  136. package/src/js/modules/Edit/defaults/editors/input.js +76 -74
  137. package/src/js/modules/Edit/defaults/editors/list.js +6 -6
  138. package/src/js/modules/Edit/defaults/editors/number.js +109 -107
  139. package/src/js/modules/Edit/defaults/editors/progress.js +126 -126
  140. package/src/js/modules/Edit/defaults/editors/range.js +80 -78
  141. package/src/js/modules/Edit/defaults/editors/select.js +9 -9
  142. package/src/js/modules/Edit/defaults/editors/star.js +145 -145
  143. package/src/js/modules/Edit/defaults/editors/textarea.js +122 -120
  144. package/src/js/modules/Edit/defaults/editors/tickCross.js +94 -96
  145. package/src/js/modules/Edit/defaults/editors/time.js +126 -98
  146. package/src/js/modules/Edit/defaults/editors.js +28 -28
  147. package/src/js/modules/Edit/inputMask.js +73 -73
  148. package/src/js/modules/Export/Export.js +623 -617
  149. package/src/js/modules/Export/ExportColumn.js +10 -10
  150. package/src/js/modules/Export/ExportRow.js +9 -9
  151. package/src/js/modules/Filter/Filter.js +892 -889
  152. package/src/js/modules/Filter/defaults/filters.js +107 -107
  153. package/src/js/modules/Format/Format.js +212 -212
  154. package/src/js/modules/Format/defaults/formatters/buttonCross.js +2 -2
  155. package/src/js/modules/Format/defaults/formatters/buttonTick.js +2 -2
  156. package/src/js/modules/Format/defaults/formatters/color.js +3 -3
  157. package/src/js/modules/Format/defaults/formatters/datetime.js +36 -36
  158. package/src/js/modules/Format/defaults/formatters/datetimediff.js +40 -40
  159. package/src/js/modules/Format/defaults/formatters/handle.js +3 -3
  160. package/src/js/modules/Format/defaults/formatters/html.js +2 -2
  161. package/src/js/modules/Format/defaults/formatters/image.js +39 -39
  162. package/src/js/modules/Format/defaults/formatters/link.js +77 -77
  163. package/src/js/modules/Format/defaults/formatters/lookup.js +9 -9
  164. package/src/js/modules/Format/defaults/formatters/money.js +36 -36
  165. package/src/js/modules/Format/defaults/formatters/plaintext.js +2 -2
  166. package/src/js/modules/Format/defaults/formatters/progress.js +132 -132
  167. package/src/js/modules/Format/defaults/formatters/responsiveCollapse.js +43 -43
  168. package/src/js/modules/Format/defaults/formatters/rowSelection.js +59 -59
  169. package/src/js/modules/Format/defaults/formatters/rownum.js +9 -9
  170. package/src/js/modules/Format/defaults/formatters/star.js +37 -37
  171. package/src/js/modules/Format/defaults/formatters/textarea.js +3 -3
  172. package/src/js/modules/Format/defaults/formatters/tickCross.js +21 -21
  173. package/src/js/modules/Format/defaults/formatters/traffic.js +46 -46
  174. package/src/js/modules/Format/defaults/formatters.js +42 -42
  175. package/src/js/modules/FrozenColumns/FrozenColumns.js +299 -299
  176. package/src/js/modules/FrozenRows/FrozenRows.js +169 -159
  177. package/src/js/modules/GroupRows/Group.js +597 -595
  178. package/src/js/modules/GroupRows/GroupComponent.js +66 -66
  179. package/src/js/modules/GroupRows/GroupRows.js +639 -623
  180. package/src/js/modules/History/History.js +171 -171
  181. package/src/js/modules/History/defaults/redoers.js +24 -24
  182. package/src/js/modules/History/defaults/undoers.js +24 -24
  183. package/src/js/modules/HtmlTableImport/HtmlTableImport.js +181 -181
  184. package/src/js/modules/Import/Import.js +193 -193
  185. package/src/js/modules/Import/defaults/importers/array.js +4 -4
  186. package/src/js/modules/Import/defaults/importers/csv.js +62 -62
  187. package/src/js/modules/Import/defaults/importers/json.js +7 -7
  188. package/src/js/modules/Import/defaults/importers.js +8 -8
  189. package/src/js/modules/Interaction/Interaction.js +325 -325
  190. package/src/js/modules/Keybindings/Keybindings.js +172 -172
  191. package/src/js/modules/Keybindings/defaults/actions.js +118 -118
  192. package/src/js/modules/Keybindings/defaults/bindings.js +12 -12
  193. package/src/js/modules/Layout/Layout.js +49 -49
  194. package/src/js/modules/Layout/defaults/modes/fitColumns.js +171 -171
  195. package/src/js/modules/Layout/defaults/modes/fitData.js +9 -9
  196. package/src/js/modules/Layout/defaults/modes/fitDataGeneral.js +9 -9
  197. package/src/js/modules/Layout/defaults/modes/fitDataStretch.js +39 -39
  198. package/src/js/modules/Layout/defaults/modes.js +11 -11
  199. package/src/js/modules/Localize/Localize.js +185 -194
  200. package/src/js/modules/Localize/defaults/langs.js +36 -36
  201. package/src/js/modules/Menu/Menu.js +302 -302
  202. package/src/js/modules/MoveColumns/MoveColumns.js +299 -299
  203. package/src/js/modules/MoveRows/MoveRows.js +635 -635
  204. package/src/js/modules/Mutator/Mutator.js +161 -161
  205. package/src/js/modules/Page/Page.js +881 -881
  206. package/src/js/modules/Page/defaults/pageCounters/pages.js +32 -32
  207. package/src/js/modules/Page/defaults/pageCounters/rows.js +39 -39
  208. package/src/js/modules/Page/defaults/pageCounters.js +7 -7
  209. package/src/js/modules/Persistence/Persistence.js +458 -458
  210. package/src/js/modules/Persistence/defaults/readers.js +29 -29
  211. package/src/js/modules/Persistence/defaults/writers.js +12 -12
  212. package/src/js/modules/Popup/Popup.js +231 -231
  213. package/src/js/modules/Print/Print.js +137 -124
  214. package/src/js/modules/ReactiveData/ReactiveData.js +408 -408
  215. package/src/js/modules/ResizeColumns/ResizeColumns.js +309 -309
  216. package/src/js/modules/ResizeRows/ResizeRows.js +111 -111
  217. package/src/js/modules/ResizeTable/ResizeTable.js +159 -159
  218. package/src/js/modules/ResponsiveLayout/ResponsiveLayout.js +345 -345
  219. package/src/js/modules/SelectRow/SelectRow.js +446 -436
  220. package/src/js/modules/Sort/Sort.js +470 -470
  221. package/src/js/modules/Sort/defaults/sorters/alphanum.js +43 -43
  222. package/src/js/modules/Sort/defaults/sorters/array.js +53 -53
  223. package/src/js/modules/Sort/defaults/sorters/boolean.js +6 -6
  224. package/src/js/modules/Sort/defaults/sorters/date.js +9 -9
  225. package/src/js/modules/Sort/defaults/sorters/datetime.js +43 -43
  226. package/src/js/modules/Sort/defaults/sorters/exists.js +6 -6
  227. package/src/js/modules/Sort/defaults/sorters/number.js +39 -39
  228. package/src/js/modules/Sort/defaults/sorters/string.js +33 -33
  229. package/src/js/modules/Sort/defaults/sorters/time.js +9 -9
  230. package/src/js/modules/Sort/defaults/sorters.js +20 -20
  231. package/src/js/modules/Tooltip/Tooltip.js +130 -130
  232. package/src/js/modules/Validate/Validate.js +305 -305
  233. package/src/js/modules/Validate/defaults/validators.js +138 -138
  234. package/src/scss/tabulator.scss +1464 -1466
  235. package/src/scss/themes/bootstrap/functions4.scss +118 -118
  236. package/src/scss/themes/bootstrap/functions5.scss +302 -302
  237. package/src/scss/themes/bootstrap/tabulator_bootstrap3.scss +284 -284
  238. package/src/scss/themes/bootstrap/tabulator_bootstrap4.scss +544 -544
  239. package/src/scss/themes/bootstrap/tabulator_bootstrap5.scss +574 -574
  240. package/src/scss/themes/bootstrap/variables3.scss +870 -870
  241. package/src/scss/themes/bootstrap/variables4.scss +930 -930
  242. package/src/scss/themes/bootstrap/variables5.scss +1641 -1641
  243. package/src/scss/themes/bulma/tabulator_bulma.scss +252 -252
  244. package/src/scss/themes/bulma/variables.scss +197 -197
  245. package/src/scss/themes/materialize/tabulator_materialize.scss +265 -265
  246. package/src/scss/themes/materialize/variables.scss +70 -70
  247. package/src/scss/themes/semanticui/tabulator_semanticui.scss +561 -561
  248. package/src/scss/themes/semanticui/variables.scss +839 -839
  249. package/src/scss/themes/semanticui/variables_table.scss +247 -247
  250. package/src/scss/themes/tabulator_midnight.scss +158 -158
  251. package/src/scss/themes/tabulator_modern.scss +231 -231
  252. package/src/scss/themes/tabulator_simple.scss +102 -102
  253. package/src/scss/themes/tabulator_site.scss +189 -189
@@ -1,890 +1,893 @@
1
- import Module from '../../core/Module.js';
2
-
3
- import defaultFilters from './defaults/filters.js';
4
-
5
- class Filter extends Module{
6
-
7
- constructor(table){
8
- super(table);
9
-
10
- this.filterList = []; //hold filter list
11
- this.headerFilters = {}; //hold column filters
12
- this.headerFilterColumns = []; //hold columns that use header filters
13
-
14
- this.prevHeaderFilterChangeCheck = "";
15
- this.prevHeaderFilterChangeCheck = "{}";
16
-
17
- this.changed = false; //has filtering changed since last render
18
- this.tableInitialized = false;
19
-
20
- this.registerTableOption("filterMode", "local"); //local or remote filtering
21
-
22
- this.registerTableOption("initialFilter", false); //initial filtering criteria
23
- this.registerTableOption("initialHeaderFilter", false); //initial header filtering criteria
24
- this.registerTableOption("headerFilterLiveFilterDelay", 300); //delay before updating column after user types in header filter
25
-
26
- this.registerColumnOption("headerFilter");
27
- this.registerColumnOption("headerFilterPlaceholder");
28
- this.registerColumnOption("headerFilterParams");
29
- this.registerColumnOption("headerFilterEmptyCheck");
30
- this.registerColumnOption("headerFilterFunc");
31
- this.registerColumnOption("headerFilterFuncParams");
32
- this.registerColumnOption("headerFilterLiveFilter");
33
-
34
- this.registerTableFunction("searchRows", this.searchRows.bind(this));
35
- this.registerTableFunction("searchData", this.searchData.bind(this));
36
-
37
- this.registerTableFunction("setFilter", this.userSetFilter.bind(this));
38
- this.registerTableFunction("refreshFilter", this.userRefreshFilter.bind(this));
39
- this.registerTableFunction("addFilter", this.userAddFilter.bind(this));
40
- this.registerTableFunction("getFilters", this.getFilters.bind(this));
41
- this.registerTableFunction("setHeaderFilterFocus", this.userSetHeaderFilterFocus.bind(this));
42
- this.registerTableFunction("getHeaderFilterValue", this.userGetHeaderFilterValue.bind(this));
43
- this.registerTableFunction("setHeaderFilterValue", this.userSetHeaderFilterValue.bind(this));
44
- this.registerTableFunction("getHeaderFilters", this.getHeaderFilters.bind(this));
45
- this.registerTableFunction("removeFilter", this.userRemoveFilter.bind(this));
46
- this.registerTableFunction("clearFilter", this.userClearFilter.bind(this));
47
- this.registerTableFunction("clearHeaderFilter", this.userClearHeaderFilter.bind(this));
48
-
49
- this.registerComponentFunction("column", "headerFilterFocus", this.setHeaderFilterFocus.bind(this));
50
- this.registerComponentFunction("column", "reloadHeaderFilter", this.reloadHeaderFilter.bind(this));
51
- this.registerComponentFunction("column", "getHeaderFilterValue", this.getHeaderFilterValue.bind(this));
52
- this.registerComponentFunction("column", "setHeaderFilterValue", this.setHeaderFilterValue.bind(this));
53
- }
54
-
55
- initialize(){
56
- this.subscribe("column-init", this.initializeColumnHeaderFilter.bind(this));
57
- this.subscribe("column-width-fit-before", this.hideHeaderFilterElements.bind(this));
58
- this.subscribe("column-width-fit-after", this.showHeaderFilterElements.bind(this));
59
- this.subscribe("table-built", this.tableBuilt.bind(this));
60
-
61
- if(this.table.options.filterMode === "remote"){
62
- this.subscribe("data-params", this.remoteFilterParams.bind(this));
63
- }
64
-
65
- this.registerDataHandler(this.filter.bind(this), 10);
66
- }
67
-
68
- tableBuilt(){
69
- if(this.table.options.initialFilter){
70
- this.setFilter(this.table.options.initialFilter);
71
- }
72
-
73
- if(this.table.options.initialHeaderFilter){
74
- this.table.options.initialHeaderFilter.forEach((item) => {
75
-
76
- var column = this.table.columnManager.findColumn(item.field);
77
-
78
- if(column){
79
- this.setHeaderFilterValue(column, item.value);
80
- }else{
81
- console.warn("Column Filter Error - No matching column found:", item.field);
82
- return false;
83
- }
84
- });
85
- }
86
-
87
- this.tableInitialized = true;
88
- }
89
-
90
- remoteFilterParams(data, config, silent, params){
91
- params.filter = this.getFilters(true, true);
92
- return params;
93
- }
94
-
95
- ///////////////////////////////////
96
- ///////// Table Functions /////////
97
- ///////////////////////////////////
98
-
99
- //set standard filters
100
- userSetFilter(field, type, value, params){
101
- this.setFilter(field, type, value, params);
102
- this.refreshFilter();
103
- }
104
-
105
- //set standard filters
106
- userRefreshFilter(){
107
- this.refreshFilter();
108
- }
109
-
110
- //add filter to array
111
- userAddFilter(field, type, value, params){
112
- this.addFilter(field, type, value, params);
113
- this.refreshFilter();
114
- }
115
-
116
- userSetHeaderFilterFocus(field){
117
- var column = this.table.columnManager.findColumn(field);
118
-
119
- if(column){
120
- this.setHeaderFilterFocus(column);
121
- }else{
122
- console.warn("Column Filter Focus Error - No matching column found:", field);
123
- return false;
124
- }
125
- }
126
-
127
- userGetHeaderFilterValue(field) {
128
- var column = this.table.columnManager.findColumn(field);
129
-
130
- if(column){
131
- return this.getHeaderFilterValue(column);
132
- }else{
133
- console.warn("Column Filter Error - No matching column found:", field);
134
- }
135
- }
136
-
137
- userSetHeaderFilterValue(field, value){
138
- var column = this.table.columnManager.findColumn(field);
139
-
140
- if(column){
141
- this.setHeaderFilterValue(column, value);
142
- }else{
143
- console.warn("Column Filter Error - No matching column found:", field);
144
- return false;
145
- }
146
- }
147
-
148
- //remove filter from array
149
- userRemoveFilter(field, type, value){
150
- this.removeFilter(field, type, value);
151
- this.refreshFilter();
152
- }
153
-
154
- //clear filters
155
- userClearFilter(all){
156
- this.clearFilter(all);
157
- this.refreshFilter();
158
- }
159
-
160
- //clear header filters
161
- userClearHeaderFilter(){
162
- this.clearHeaderFilter();
163
- this.refreshFilter();
164
- }
165
-
166
-
167
- //search for specific row components
168
- searchRows(field, type, value){
169
- return this.search("rows", field, type, value);
170
- }
171
-
172
- //search for specific data
173
- searchData(field, type, value){
174
- return this.search("data", field, type, value);
175
- }
176
-
177
- ///////////////////////////////////
178
- ///////// Internal Logic //////////
179
- ///////////////////////////////////
180
-
181
- initializeColumnHeaderFilter(column){
182
- var def = column.definition;
183
-
184
- if(def.headerFilter){
185
-
186
- if(typeof def.headerFilterPlaceholder !== "undefined" && def.field){
187
- this.module("localize").setHeaderFilterColumnPlaceholder(def.field, def.headerFilterPlaceholder);
188
- }
189
-
190
- this.initializeColumn(column);
191
- }
192
- }
193
-
194
- //initialize column header filter
195
- initializeColumn(column, value){
196
- var self = this,
197
- field = column.getField();
198
-
199
- //handle successfully value change
200
- function success(value){
201
- var filterType = (column.modules.filter.tagType == "input" && column.modules.filter.attrType == "text") || column.modules.filter.tagType == "textarea" ? "partial" : "match",
202
- type = "",
203
- filterChangeCheck = "",
204
- filterFunc;
205
-
206
- if(typeof column.modules.filter.prevSuccess === "undefined" || column.modules.filter.prevSuccess !== value){
207
-
208
- column.modules.filter.prevSuccess = value;
209
-
210
- if(!column.modules.filter.emptyFunc(value)){
211
- column.modules.filter.value = value;
212
-
213
- switch(typeof column.definition.headerFilterFunc){
214
- case "string":
215
- if(Filter.filters[column.definition.headerFilterFunc]){
216
- type = column.definition.headerFilterFunc;
217
- filterFunc = function(data){
218
- var params = column.definition.headerFilterFuncParams || {};
219
- var fieldVal = column.getFieldValue(data);
220
-
221
- params = typeof params === "function" ? params(value, fieldVal, data) : params;
222
-
223
- return Filter.filters[column.definition.headerFilterFunc](value, fieldVal, data, params);
224
- };
225
- }else{
226
- console.warn("Header Filter Error - Matching filter function not found: ", column.definition.headerFilterFunc);
227
- }
228
- break;
229
-
230
- case "function":
231
- filterFunc = function(data){
232
- var params = column.definition.headerFilterFuncParams || {};
233
- var fieldVal = column.getFieldValue(data);
234
-
235
- params = typeof params === "function" ? params(value, fieldVal, data) : params;
236
-
237
- return column.definition.headerFilterFunc(value, fieldVal, data, params);
238
- };
239
-
240
- type = filterFunc;
241
- break;
242
- }
243
-
244
- if(!filterFunc){
245
- switch(filterType){
246
- case "partial":
247
- filterFunc = function(data){
248
- var colVal = column.getFieldValue(data);
249
-
250
- if(typeof colVal !== 'undefined' && colVal !== null){
251
- return String(colVal).toLowerCase().indexOf(String(value).toLowerCase()) > -1;
252
- }else{
253
- return false;
254
- }
255
- };
256
- type = "like";
257
- break;
258
-
259
- default:
260
- filterFunc = function(data){
261
- return column.getFieldValue(data) == value;
262
- };
263
- type = "=";
264
- }
265
- }
266
-
267
- self.headerFilters[field] = {value:value, func:filterFunc, type:type};
268
- }else{
269
- delete self.headerFilters[field];
270
- }
271
-
272
- column.modules.filter.value = value;
273
-
274
- filterChangeCheck = JSON.stringify(self.headerFilters);
275
-
276
- if(self.prevHeaderFilterChangeCheck !== filterChangeCheck){
277
- self.prevHeaderFilterChangeCheck = filterChangeCheck;
278
-
279
- self.trackChanges();
280
- self.refreshFilter();
281
- }
282
- }
283
-
284
- return true;
285
- }
286
-
287
- column.modules.filter = {
288
- success:success,
289
- attrType:false,
290
- tagType:false,
291
- emptyFunc:false,
292
- };
293
-
294
- this.generateHeaderFilterElement(column);
295
- }
296
-
297
- generateHeaderFilterElement(column, initialValue, reinitialize){
298
- var self = this,
299
- success = column.modules.filter.success,
300
- field = column.getField(),
301
- filterElement, editor, editorElement, cellWrapper, typingTimer, searchTrigger, params;
302
-
303
- column.modules.filter.value = initialValue;
304
-
305
- //handle aborted edit
306
- function cancel(){}
307
-
308
- if(column.modules.filter.headerElement && column.modules.filter.headerElement.parentNode){
309
- column.contentElement.removeChild(column.modules.filter.headerElement.parentNode);
310
- }
311
-
312
- if(field){
313
-
314
- //set empty value function
315
- column.modules.filter.emptyFunc = column.definition.headerFilterEmptyCheck || function(value){
316
- return !value && value !== 0;
317
- };
318
-
319
- filterElement = document.createElement("div");
320
- filterElement.classList.add("tabulator-header-filter");
321
-
322
- //set column editor
323
- switch(typeof column.definition.headerFilter){
324
- case "string":
325
- if(self.table.modules.edit.editors[column.definition.headerFilter]){
326
- editor = self.table.modules.edit.editors[column.definition.headerFilter];
327
-
328
- if((column.definition.headerFilter === "tick" || column.definition.headerFilter === "tickCross") && !column.definition.headerFilterEmptyCheck){
329
- column.modules.filter.emptyFunc = function(value){
330
- return value !== true && value !== false;
331
- };
332
- }
333
- }else{
334
- console.warn("Filter Error - Cannot build header filter, No such editor found: ", column.definition.editor);
335
- }
336
- break;
337
-
338
- case "function":
339
- editor = column.definition.headerFilter;
340
- break;
341
-
342
- case "boolean":
343
- if(column.modules.edit && column.modules.edit.editor){
344
- editor = column.modules.edit.editor;
345
- }else{
346
- if(column.definition.formatter && self.table.modules.edit.editors[column.definition.formatter]){
347
- editor = self.table.modules.edit.editors[column.definition.formatter];
348
-
349
- if((column.definition.formatter === "tick" || column.definition.formatter === "tickCross") && !column.definition.headerFilterEmptyCheck){
350
- column.modules.filter.emptyFunc = function(value){
351
- return value !== true && value !== false;
352
- };
353
- }
354
- }else{
355
- editor = self.table.modules.edit.editors["input"];
356
- }
357
- }
358
- break;
359
- }
360
-
361
- if(editor){
362
-
363
- cellWrapper = {
364
- getValue:function(){
365
- return typeof initialValue !== "undefined" ? initialValue : "";
366
- },
367
- getField:function(){
368
- return column.definition.field;
369
- },
370
- getElement:function(){
371
- return filterElement;
372
- },
373
- getColumn:function(){
374
- return column.getComponent();
375
- },
376
- getTable:() => {
377
- return this.table;
378
- },
379
- getRow:function(){
380
- return {
381
- normalizeHeight:function(){
382
-
383
- }
384
- };
385
- }
386
- };
387
-
388
- params = column.definition.headerFilterParams || {};
389
-
390
- params = typeof params === "function" ? params.call(self.table, cellWrapper) : params;
391
-
392
- editorElement = editor.call(this.table.modules.edit, cellWrapper, function(){}, success, cancel, params);
393
-
394
- if(!editorElement){
395
- console.warn("Filter Error - Cannot add filter to " + field + " column, editor returned a value of false");
396
- return;
397
- }
398
-
399
- if(!(editorElement instanceof Node)){
400
- console.warn("Filter Error - Cannot add filter to " + field + " column, editor should return an instance of Node, the editor returned:", editorElement);
401
- return;
402
- }
403
-
404
- //set Placeholder Text
405
- self.langBind("headerFilters|columns|" + column.definition.field, function(value){
406
- editorElement.setAttribute("placeholder", typeof value !== "undefined" && value ? value : self.langText("headerFilters|default"));
407
- });
408
-
409
- //focus on element on click
410
- editorElement.addEventListener("click", function(e){
411
- e.stopPropagation();
412
- editorElement.focus();
413
- });
414
-
415
- editorElement.addEventListener("focus", (e) => {
416
- var left = this.table.columnManager.contentsElement.scrollLeft;
417
-
418
- var headerPos = this.table.rowManager.element.scrollLeft;
419
-
420
- if(left !== headerPos){
421
- this.table.rowManager.scrollHorizontal(left);
422
- this.table.columnManager.scrollHorizontal(left);
423
- }
424
- });
425
-
426
- //live update filters as user types
427
- typingTimer = false;
428
-
429
- searchTrigger = function(e){
430
- if(typingTimer){
431
- clearTimeout(typingTimer);
432
- }
433
-
434
- typingTimer = setTimeout(function(){
435
- success(editorElement.value);
436
- },self.table.options.headerFilterLiveFilterDelay);
437
- };
438
-
439
- column.modules.filter.headerElement = editorElement;
440
- column.modules.filter.attrType = editorElement.hasAttribute("type") ? editorElement.getAttribute("type").toLowerCase() : "" ;
441
- column.modules.filter.tagType = editorElement.tagName.toLowerCase();
442
-
443
- if(column.definition.headerFilterLiveFilter !== false){
444
-
445
- if (
446
- !(
447
- column.definition.headerFilter === 'autocomplete' ||
448
- column.definition.headerFilter === 'tickCross' ||
449
- ((column.definition.editor === 'autocomplete' ||
450
- column.definition.editor === 'tickCross') &&
451
- column.definition.headerFilter === true)
452
- )
453
- ) {
454
- editorElement.addEventListener("keyup", searchTrigger);
455
- editorElement.addEventListener("search", searchTrigger);
456
-
457
-
458
- //update number filtered columns on change
459
- if(column.modules.filter.attrType == "number"){
460
- editorElement.addEventListener("change", function(e){
461
- success(editorElement.value);
462
- });
463
- }
464
-
465
- //change text inputs to search inputs to allow for clearing of field
466
- if(column.modules.filter.attrType == "text" && this.table.browser !== "ie"){
467
- editorElement.setAttribute("type", "search");
468
- // editorElement.off("change blur"); //prevent blur from triggering filter and preventing selection click
469
- }
470
-
471
- }
472
-
473
- //prevent input and select elements from propagating click to column sorters etc
474
- if(column.modules.filter.tagType == "input" || column.modules.filter.tagType == "select" || column.modules.filter.tagType == "textarea"){
475
- editorElement.addEventListener("mousedown",function(e){
476
- e.stopPropagation();
477
- });
478
- }
479
- }
480
-
481
- filterElement.appendChild(editorElement);
482
-
483
- column.contentElement.appendChild(filterElement);
484
-
485
- if(!reinitialize){
486
- self.headerFilterColumns.push(column);
487
- }
488
- }
489
- }else{
490
- console.warn("Filter Error - Cannot add header filter, column has no field set:", column.definition.title);
491
- }
492
- }
493
-
494
- //hide all header filter elements (used to ensure correct column widths in "fitData" layout mode)
495
- hideHeaderFilterElements(){
496
- this.headerFilterColumns.forEach(function(column){
497
- if(column.modules.filter && column.modules.filter.headerElement){
498
- column.modules.filter.headerElement.style.display = 'none';
499
- }
500
- });
501
- }
502
-
503
- //show all header filter elements (used to ensure correct column widths in "fitData" layout mode)
504
- showHeaderFilterElements(){
505
- this.headerFilterColumns.forEach(function(column){
506
- if(column.modules.filter && column.modules.filter.headerElement){
507
- column.modules.filter.headerElement.style.display = '';
508
- }
509
- });
510
- }
511
-
512
- //programmatically set focus of header filter
513
- setHeaderFilterFocus(column){
514
- if(column.modules.filter && column.modules.filter.headerElement){
515
- column.modules.filter.headerElement.focus();
516
- }else{
517
- console.warn("Column Filter Focus Error - No header filter set on column:", column.getField());
518
- }
519
- }
520
-
521
- //programmatically get value of header filter
522
- getHeaderFilterValue(column){
523
- if(column.modules.filter && column.modules.filter.headerElement){
524
- return column.modules.filter.value;
525
- } else {
526
- console.warn("Column Filter Error - No header filter set on column:", column.getField());
527
- }
528
- }
529
-
530
- //programmatically set value of header filter
531
- setHeaderFilterValue(column, value){
532
- if (column){
533
- if(column.modules.filter && column.modules.filter.headerElement){
534
- this.generateHeaderFilterElement(column, value, true);
535
- column.modules.filter.success(value);
536
- }else{
537
- console.warn("Column Filter Error - No header filter set on column:", column.getField());
538
- }
539
- }
540
- }
541
-
542
- reloadHeaderFilter(column){
543
- if (column){
544
- if(column.modules.filter && column.modules.filter.headerElement){
545
- this.generateHeaderFilterElement(column, column.modules.filter.value, true);
546
- }else{
547
- console.warn("Column Filter Error - No header filter set on column:", column.getField());
548
- }
549
- }
550
- }
551
-
552
- refreshFilter(){
553
- if(this.tableInitialized){
554
- if(this.table.options.filterMode === "remote"){
555
- this.reloadData(null, false, false);
556
- }else{
557
- this.refreshData(true);
558
- }
559
- }
560
-
561
- //TODO - Persist left position of row manager
562
- // left = this.scrollLeft;
563
- // this.scrollHorizontal(left);
564
- }
565
-
566
- //check if the filters has changed since last use
567
- trackChanges(){
568
- this.changed = true;
569
- this.dispatch("filter-changed");
570
- }
571
-
572
- //check if the filters has changed since last use
573
- hasChanged(){
574
- var changed = this.changed;
575
- this.changed = false;
576
- return changed;
577
- }
578
-
579
- //set standard filters
580
- setFilter(field, type, value, params){
581
- this.filterList = [];
582
-
583
- if(!Array.isArray(field)){
584
- field = [{field:field, type:type, value:value, params:params}];
585
- }
586
-
587
- this.addFilter(field);
588
- }
589
-
590
- //add filter to array
591
- addFilter(field, type, value, params){
592
- var changed = false;
593
-
594
- if(!Array.isArray(field)){
595
- field = [{field:field, type:type, value:value, params:params}];
596
- }
597
-
598
- field.forEach((filter) => {
599
- filter = this.findFilter(filter);
600
-
601
- if(filter){
602
- this.filterList.push(filter);
603
- changed = true;
604
- }
605
- });
606
-
607
- if(changed){
608
- this.trackChanges();
609
- }
610
- }
611
-
612
- findFilter(filter){
613
- var column;
614
-
615
- if(Array.isArray(filter)){
616
- return this.findSubFilters(filter);
617
- }
618
-
619
- var filterFunc = false;
620
-
621
- if(typeof filter.field == "function"){
622
- filterFunc = function(data){
623
- return filter.field(data, filter.type || {});// pass params to custom filter function
624
- };
625
- }else{
626
-
627
- if(Filter.filters[filter.type]){
628
-
629
- column = this.table.columnManager.getColumnByField(filter.field);
630
-
631
- if(column){
632
- filterFunc = function(data){
633
- return Filter.filters[filter.type](filter.value, column.getFieldValue(data), data, filter.params || {});
634
- };
635
- }else{
636
- filterFunc = function(data){
637
- return Filter.filters[filter.type](filter.value, data[filter.field], data, filter.params || {});
638
- };
639
- }
640
-
641
-
642
- }else{
643
- console.warn("Filter Error - No such filter type found, ignoring: ", filter.type);
644
- }
645
- }
646
-
647
- filter.func = filterFunc;
648
-
649
- return filter.func ? filter : false;
650
- }
651
-
652
- findSubFilters(filters){
653
- var output = [];
654
-
655
- filters.forEach((filter) => {
656
- filter = this.findFilter(filter);
657
-
658
- if(filter){
659
- output.push(filter);
660
- }
661
- });
662
-
663
- return output.length ? output : false;
664
- }
665
-
666
- //get all filters
667
- getFilters(all, ajax){
668
- var output = [];
669
-
670
- if(all){
671
- output = this.getHeaderFilters();
672
- }
673
-
674
- if(ajax){
675
- output.forEach(function(item){
676
- if(typeof item.type == "function"){
677
- item.type = "function";
678
- }
679
- });
680
- }
681
-
682
- output = output.concat(this.filtersToArray(this.filterList, ajax));
683
-
684
- return output;
685
- }
686
-
687
- //filter to Object
688
- filtersToArray(filterList, ajax){
689
- var output = [];
690
-
691
- filterList.forEach((filter) => {
692
- var item;
693
-
694
- if(Array.isArray(filter)){
695
- output.push(this.filtersToArray(filter, ajax));
696
- }else{
697
- item = {field:filter.field, type:filter.type, value:filter.value};
698
-
699
- if(ajax){
700
- if(typeof item.type == "function"){
701
- item.type = "function";
702
- }
703
- }
704
-
705
- output.push(item);
706
- }
707
- });
708
-
709
- return output;
710
- }
711
-
712
- //get all filters
713
- getHeaderFilters(){
714
- var output = [];
715
-
716
- for(var key in this.headerFilters){
717
- output.push({field:key, type:this.headerFilters[key].type, value:this.headerFilters[key].value});
718
- }
719
-
720
- return output;
721
- }
722
-
723
- //remove filter from array
724
- removeFilter(field, type, value){
725
- if(!Array.isArray(field)){
726
- field = [{field:field, type:type, value:value}];
727
- }
728
-
729
- field.forEach((filter) => {
730
- var index = -1;
731
-
732
- if(typeof filter.field == "object"){
733
- index = this.filterList.findIndex((element) => {
734
- return filter === element;
735
- });
736
- }else{
737
- index = this.filterList.findIndex((element) => {
738
- return filter.field === element.field && filter.type === element.type && filter.value === element.value;
739
- });
740
- }
741
-
742
- if(index > -1){
743
- this.filterList.splice(index, 1);
744
- }else{
745
- console.warn("Filter Error - No matching filter type found, ignoring: ", filter.type);
746
- }
747
- });
748
-
749
- this.trackChanges();
750
- }
751
-
752
- //clear filters
753
- clearFilter(all){
754
- this.filterList = [];
755
-
756
- if(all){
757
- this.clearHeaderFilter();
758
- }
759
-
760
- this.trackChanges();
761
- }
762
-
763
- //clear header filters
764
- clearHeaderFilter(){
765
- this.headerFilters = {};
766
- this.prevHeaderFilterChangeCheck = "{}";
767
-
768
- this.headerFilterColumns.forEach((column) => {
769
- if(typeof column.modules.filter.value !== "undefined"){
770
- delete column.modules.filter.value;
771
- }
772
- column.modules.filter.prevSuccess = undefined;
773
- this.reloadHeaderFilter(column);
774
- });
775
-
776
- this.trackChanges();
777
- }
778
-
779
- //search data and return matching rows
780
- search (searchType, field, type, value){
781
- var activeRows = [],
782
- filterList = [];
783
-
784
- if(!Array.isArray(field)){
785
- field = [{field:field, type:type, value:value}];
786
- }
787
-
788
- field.forEach((filter) => {
789
- filter = this.findFilter(filter);
790
-
791
- if(filter){
792
- filterList.push(filter);
793
- }
794
- });
795
-
796
- this.table.rowManager.rows.forEach((row) => {
797
- var match = true;
798
-
799
- filterList.forEach((filter) => {
800
- if(!this.filterRecurse(filter, row.getData())){
801
- match = false;
802
- }
803
- });
804
-
805
- if(match){
806
- activeRows.push(searchType === "data" ? row.getData("data") : row.getComponent());
807
- }
808
-
809
- });
810
-
811
- return activeRows;
812
- }
813
-
814
- //filter row array
815
- filter(rowList, filters){
816
- var activeRows = [],
817
- activeRowComponents = [];
818
-
819
- if(this.subscribedExternal("dataFiltering")){
820
- this.dispatchExternal("dataFiltering", this.getFilters(true));
821
- }
822
-
823
- if(this.table.options.filterMode !== "remote" && (this.filterList.length || Object.keys(this.headerFilters).length)){
824
-
825
- rowList.forEach((row) => {
826
- if(this.filterRow(row)){
827
- activeRows.push(row);
828
- }
829
- });
830
-
831
- }else{
832
- activeRows = rowList.slice(0);
833
- }
834
-
835
- if(this.subscribedExternal("dataFiltered")){
836
-
837
- activeRows.forEach((row) => {
838
- activeRowComponents.push(row.getComponent());
839
- });
840
-
841
- this.dispatchExternal("dataFiltered", this.getFilters(true), activeRowComponents);
842
- }
843
-
844
- return activeRows;
845
- }
846
-
847
- //filter individual row
848
- filterRow(row, filters){
849
- var match = true,
850
- data = row.getData();
851
-
852
- this.filterList.forEach((filter) => {
853
- if(!this.filterRecurse(filter, data)){
854
- match = false;
855
- }
856
- });
857
-
858
-
859
- for(var field in this.headerFilters){
860
- if(!this.headerFilters[field].func(data)){
861
- match = false;
862
- }
863
- }
864
-
865
- return match;
866
- }
867
-
868
- filterRecurse(filter, data){
869
- var match = false;
870
-
871
- if(Array.isArray(filter)){
872
- filter.forEach((subFilter) => {
873
- if(this.filterRecurse(subFilter, data)){
874
- match = true;
875
- }
876
- });
877
- }else{
878
- match = filter.func(data);
879
- }
880
-
881
- return match;
882
- }
883
- }
884
-
885
- Filter.moduleName = "filter";
886
-
887
- //load defaults
888
- Filter.filters = defaultFilters;
889
-
1
+ import Module from '../../core/Module.js';
2
+
3
+ import defaultFilters from './defaults/filters.js';
4
+
5
+ class Filter extends Module{
6
+
7
+ constructor(table){
8
+ super(table);
9
+
10
+ this.filterList = []; //hold filter list
11
+ this.headerFilters = {}; //hold column filters
12
+ this.headerFilterColumns = []; //hold columns that use header filters
13
+
14
+ this.prevHeaderFilterChangeCheck = "";
15
+ this.prevHeaderFilterChangeCheck = "{}";
16
+
17
+ this.changed = false; //has filtering changed since last render
18
+ this.tableInitialized = false;
19
+
20
+ this.registerTableOption("filterMode", "local"); //local or remote filtering
21
+
22
+ this.registerTableOption("initialFilter", false); //initial filtering criteria
23
+ this.registerTableOption("initialHeaderFilter", false); //initial header filtering criteria
24
+ this.registerTableOption("headerFilterLiveFilterDelay", 300); //delay before updating column after user types in header filter
25
+
26
+ this.registerColumnOption("headerFilter");
27
+ this.registerColumnOption("headerFilterPlaceholder");
28
+ this.registerColumnOption("headerFilterParams");
29
+ this.registerColumnOption("headerFilterEmptyCheck");
30
+ this.registerColumnOption("headerFilterFunc");
31
+ this.registerColumnOption("headerFilterFuncParams");
32
+ this.registerColumnOption("headerFilterLiveFilter");
33
+
34
+ this.registerTableFunction("searchRows", this.searchRows.bind(this));
35
+ this.registerTableFunction("searchData", this.searchData.bind(this));
36
+
37
+ this.registerTableFunction("setFilter", this.userSetFilter.bind(this));
38
+ this.registerTableFunction("refreshFilter", this.userRefreshFilter.bind(this));
39
+ this.registerTableFunction("addFilter", this.userAddFilter.bind(this));
40
+ this.registerTableFunction("getFilters", this.getFilters.bind(this));
41
+ this.registerTableFunction("setHeaderFilterFocus", this.userSetHeaderFilterFocus.bind(this));
42
+ this.registerTableFunction("getHeaderFilterValue", this.userGetHeaderFilterValue.bind(this));
43
+ this.registerTableFunction("setHeaderFilterValue", this.userSetHeaderFilterValue.bind(this));
44
+ this.registerTableFunction("getHeaderFilters", this.getHeaderFilters.bind(this));
45
+ this.registerTableFunction("removeFilter", this.userRemoveFilter.bind(this));
46
+ this.registerTableFunction("clearFilter", this.userClearFilter.bind(this));
47
+ this.registerTableFunction("clearHeaderFilter", this.userClearHeaderFilter.bind(this));
48
+
49
+ this.registerComponentFunction("column", "headerFilterFocus", this.setHeaderFilterFocus.bind(this));
50
+ this.registerComponentFunction("column", "reloadHeaderFilter", this.reloadHeaderFilter.bind(this));
51
+ this.registerComponentFunction("column", "getHeaderFilterValue", this.getHeaderFilterValue.bind(this));
52
+ this.registerComponentFunction("column", "setHeaderFilterValue", this.setHeaderFilterValue.bind(this));
53
+ }
54
+
55
+ initialize(){
56
+ this.subscribe("column-init", this.initializeColumnHeaderFilter.bind(this));
57
+ this.subscribe("column-width-fit-before", this.hideHeaderFilterElements.bind(this));
58
+ this.subscribe("column-width-fit-after", this.showHeaderFilterElements.bind(this));
59
+ this.subscribe("table-built", this.tableBuilt.bind(this));
60
+
61
+ if(this.table.options.filterMode === "remote"){
62
+ this.subscribe("data-params", this.remoteFilterParams.bind(this));
63
+ }
64
+
65
+ this.registerDataHandler(this.filter.bind(this), 10);
66
+ }
67
+
68
+ tableBuilt(){
69
+ if(this.table.options.initialFilter){
70
+ this.setFilter(this.table.options.initialFilter);
71
+ }
72
+
73
+ if(this.table.options.initialHeaderFilter){
74
+ this.table.options.initialHeaderFilter.forEach((item) => {
75
+
76
+ var column = this.table.columnManager.findColumn(item.field);
77
+
78
+ if(column){
79
+ this.setHeaderFilterValue(column, item.value);
80
+ }else{
81
+ console.warn("Column Filter Error - No matching column found:", item.field);
82
+ return false;
83
+ }
84
+ });
85
+ }
86
+
87
+ this.tableInitialized = true;
88
+ }
89
+
90
+ remoteFilterParams(data, config, silent, params){
91
+ params.filter = this.getFilters(true, true);
92
+ return params;
93
+ }
94
+
95
+ ///////////////////////////////////
96
+ ///////// Table Functions /////////
97
+ ///////////////////////////////////
98
+
99
+ //set standard filters
100
+ userSetFilter(field, type, value, params){
101
+ this.setFilter(field, type, value, params);
102
+ this.refreshFilter();
103
+ }
104
+
105
+ //set standard filters
106
+ userRefreshFilter(){
107
+ this.refreshFilter();
108
+ }
109
+
110
+ //add filter to array
111
+ userAddFilter(field, type, value, params){
112
+ this.addFilter(field, type, value, params);
113
+ this.refreshFilter();
114
+ }
115
+
116
+ userSetHeaderFilterFocus(field){
117
+ var column = this.table.columnManager.findColumn(field);
118
+
119
+ if(column){
120
+ this.setHeaderFilterFocus(column);
121
+ }else{
122
+ console.warn("Column Filter Focus Error - No matching column found:", field);
123
+ return false;
124
+ }
125
+ }
126
+
127
+ userGetHeaderFilterValue(field) {
128
+ var column = this.table.columnManager.findColumn(field);
129
+
130
+ if(column){
131
+ return this.getHeaderFilterValue(column);
132
+ }else{
133
+ console.warn("Column Filter Error - No matching column found:", field);
134
+ }
135
+ }
136
+
137
+ userSetHeaderFilterValue(field, value){
138
+ var column = this.table.columnManager.findColumn(field);
139
+
140
+ if(column){
141
+ this.setHeaderFilterValue(column, value);
142
+ }else{
143
+ console.warn("Column Filter Error - No matching column found:", field);
144
+ return false;
145
+ }
146
+ }
147
+
148
+ //remove filter from array
149
+ userRemoveFilter(field, type, value){
150
+ this.removeFilter(field, type, value);
151
+ this.refreshFilter();
152
+ }
153
+
154
+ //clear filters
155
+ userClearFilter(all){
156
+ this.clearFilter(all);
157
+ this.refreshFilter();
158
+ }
159
+
160
+ //clear header filters
161
+ userClearHeaderFilter(){
162
+ this.clearHeaderFilter();
163
+ this.refreshFilter();
164
+ }
165
+
166
+
167
+ //search for specific row components
168
+ searchRows(field, type, value){
169
+ return this.search("rows", field, type, value);
170
+ }
171
+
172
+ //search for specific data
173
+ searchData(field, type, value){
174
+ return this.search("data", field, type, value);
175
+ }
176
+
177
+ ///////////////////////////////////
178
+ ///////// Internal Logic //////////
179
+ ///////////////////////////////////
180
+
181
+ initializeColumnHeaderFilter(column){
182
+ var def = column.definition;
183
+
184
+ if(def.headerFilter){
185
+ this.initializeColumn(column);
186
+ }
187
+ }
188
+
189
+ //initialize column header filter
190
+ initializeColumn(column, value){
191
+ var self = this,
192
+ field = column.getField();
193
+
194
+ //handle successfully value change
195
+ function success(value){
196
+ var filterType = (column.modules.filter.tagType == "input" && column.modules.filter.attrType == "text") || column.modules.filter.tagType == "textarea" ? "partial" : "match",
197
+ type = "",
198
+ filterChangeCheck = "",
199
+ filterFunc;
200
+
201
+ if(typeof column.modules.filter.prevSuccess === "undefined" || column.modules.filter.prevSuccess !== value){
202
+
203
+ column.modules.filter.prevSuccess = value;
204
+
205
+ if(!column.modules.filter.emptyFunc(value)){
206
+ column.modules.filter.value = value;
207
+
208
+ switch(typeof column.definition.headerFilterFunc){
209
+ case "string":
210
+ if(Filter.filters[column.definition.headerFilterFunc]){
211
+ type = column.definition.headerFilterFunc;
212
+ filterFunc = function(data){
213
+ var params = column.definition.headerFilterFuncParams || {};
214
+ var fieldVal = column.getFieldValue(data);
215
+
216
+ params = typeof params === "function" ? params(value, fieldVal, data) : params;
217
+
218
+ return Filter.filters[column.definition.headerFilterFunc](value, fieldVal, data, params);
219
+ };
220
+ }else{
221
+ console.warn("Header Filter Error - Matching filter function not found: ", column.definition.headerFilterFunc);
222
+ }
223
+ break;
224
+
225
+ case "function":
226
+ filterFunc = function(data){
227
+ var params = column.definition.headerFilterFuncParams || {};
228
+ var fieldVal = column.getFieldValue(data);
229
+
230
+ params = typeof params === "function" ? params(value, fieldVal, data) : params;
231
+
232
+ return column.definition.headerFilterFunc(value, fieldVal, data, params);
233
+ };
234
+
235
+ type = filterFunc;
236
+ break;
237
+ }
238
+
239
+ if(!filterFunc){
240
+ switch(filterType){
241
+ case "partial":
242
+ filterFunc = function(data){
243
+ var colVal = column.getFieldValue(data);
244
+
245
+ if(typeof colVal !== 'undefined' && colVal !== null){
246
+ return String(colVal).toLowerCase().indexOf(String(value).toLowerCase()) > -1;
247
+ }else{
248
+ return false;
249
+ }
250
+ };
251
+ type = "like";
252
+ break;
253
+
254
+ default:
255
+ filterFunc = function(data){
256
+ return column.getFieldValue(data) == value;
257
+ };
258
+ type = "=";
259
+ }
260
+ }
261
+
262
+ self.headerFilters[field] = {value:value, func:filterFunc, type:type};
263
+ }else{
264
+ delete self.headerFilters[field];
265
+ }
266
+
267
+ column.modules.filter.value = value;
268
+
269
+ filterChangeCheck = JSON.stringify(self.headerFilters);
270
+
271
+ if(self.prevHeaderFilterChangeCheck !== filterChangeCheck){
272
+ self.prevHeaderFilterChangeCheck = filterChangeCheck;
273
+
274
+ self.trackChanges();
275
+ self.refreshFilter();
276
+ }
277
+ }
278
+
279
+ return true;
280
+ }
281
+
282
+ column.modules.filter = {
283
+ success:success,
284
+ attrType:false,
285
+ tagType:false,
286
+ emptyFunc:false,
287
+ };
288
+
289
+ this.generateHeaderFilterElement(column);
290
+ }
291
+
292
+ generateHeaderFilterElement(column, initialValue, reinitialize){
293
+ var self = this,
294
+ success = column.modules.filter.success,
295
+ field = column.getField(),
296
+ filterElement, editor, editorElement, cellWrapper, typingTimer, searchTrigger, params, onRenderedCallback;
297
+
298
+ column.modules.filter.value = initialValue;
299
+
300
+ //handle aborted edit
301
+ function cancel(){}
302
+
303
+ function onRendered(callback){
304
+ onRenderedCallback = callback;
305
+ }
306
+
307
+ if(column.modules.filter.headerElement && column.modules.filter.headerElement.parentNode){
308
+ column.contentElement.removeChild(column.modules.filter.headerElement.parentNode);
309
+ }
310
+
311
+ if(field){
312
+
313
+ //set empty value function
314
+ column.modules.filter.emptyFunc = column.definition.headerFilterEmptyCheck || function(value){
315
+ return !value && value !== 0;
316
+ };
317
+
318
+ filterElement = document.createElement("div");
319
+ filterElement.classList.add("tabulator-header-filter");
320
+
321
+ //set column editor
322
+ switch(typeof column.definition.headerFilter){
323
+ case "string":
324
+ if(self.table.modules.edit.editors[column.definition.headerFilter]){
325
+ editor = self.table.modules.edit.editors[column.definition.headerFilter];
326
+
327
+ if((column.definition.headerFilter === "tick" || column.definition.headerFilter === "tickCross") && !column.definition.headerFilterEmptyCheck){
328
+ column.modules.filter.emptyFunc = function(value){
329
+ return value !== true && value !== false;
330
+ };
331
+ }
332
+ }else{
333
+ console.warn("Filter Error - Cannot build header filter, No such editor found: ", column.definition.editor);
334
+ }
335
+ break;
336
+
337
+ case "function":
338
+ editor = column.definition.headerFilter;
339
+ break;
340
+
341
+ case "boolean":
342
+ if(column.modules.edit && column.modules.edit.editor){
343
+ editor = column.modules.edit.editor;
344
+ }else{
345
+ if(column.definition.formatter && self.table.modules.edit.editors[column.definition.formatter]){
346
+ editor = self.table.modules.edit.editors[column.definition.formatter];
347
+
348
+ if((column.definition.formatter === "tick" || column.definition.formatter === "tickCross") && !column.definition.headerFilterEmptyCheck){
349
+ column.modules.filter.emptyFunc = function(value){
350
+ return value !== true && value !== false;
351
+ };
352
+ }
353
+ }else{
354
+ editor = self.table.modules.edit.editors["input"];
355
+ }
356
+ }
357
+ break;
358
+ }
359
+
360
+ if(editor){
361
+
362
+ cellWrapper = {
363
+ getValue:function(){
364
+ return typeof initialValue !== "undefined" ? initialValue : "";
365
+ },
366
+ getField:function(){
367
+ return column.definition.field;
368
+ },
369
+ getElement:function(){
370
+ return filterElement;
371
+ },
372
+ getColumn:function(){
373
+ return column.getComponent();
374
+ },
375
+ getTable:() => {
376
+ return this.table;
377
+ },
378
+ getRow:function(){
379
+ return {
380
+ normalizeHeight:function(){
381
+
382
+ }
383
+ };
384
+ }
385
+ };
386
+
387
+ params = column.definition.headerFilterParams || {};
388
+
389
+ params = typeof params === "function" ? params.call(self.table, cellWrapper) : params;
390
+
391
+ editorElement = editor.call(this.table.modules.edit, cellWrapper, onRendered, success, cancel, params);
392
+
393
+ if(!editorElement){
394
+ console.warn("Filter Error - Cannot add filter to " + field + " column, editor returned a value of false");
395
+ return;
396
+ }
397
+
398
+ if(!(editorElement instanceof Node)){
399
+ console.warn("Filter Error - Cannot add filter to " + field + " column, editor should return an instance of Node, the editor returned:", editorElement);
400
+ return;
401
+ }
402
+
403
+ //set Placeholder Text
404
+ self.langBind("headerFilters|columns|" + column.definition.field, function(value){
405
+ editorElement.setAttribute("placeholder", typeof value !== "undefined" && value ? value : (column.definition.headerFilterPlaceholder || self.langText("headerFilters|default")));
406
+ });
407
+
408
+ //focus on element on click
409
+ editorElement.addEventListener("click", function(e){
410
+ e.stopPropagation();
411
+ editorElement.focus();
412
+ });
413
+
414
+ editorElement.addEventListener("focus", (e) => {
415
+ var left = this.table.columnManager.contentsElement.scrollLeft;
416
+
417
+ var headerPos = this.table.rowManager.element.scrollLeft;
418
+
419
+ if(left !== headerPos){
420
+ this.table.rowManager.scrollHorizontal(left);
421
+ this.table.columnManager.scrollHorizontal(left);
422
+ }
423
+ });
424
+
425
+ //live update filters as user types
426
+ typingTimer = false;
427
+
428
+ searchTrigger = function(e){
429
+ if(typingTimer){
430
+ clearTimeout(typingTimer);
431
+ }
432
+
433
+ typingTimer = setTimeout(function(){
434
+ success(editorElement.value);
435
+ },self.table.options.headerFilterLiveFilterDelay);
436
+ };
437
+
438
+ column.modules.filter.headerElement = editorElement;
439
+ column.modules.filter.attrType = editorElement.hasAttribute("type") ? editorElement.getAttribute("type").toLowerCase() : "" ;
440
+ column.modules.filter.tagType = editorElement.tagName.toLowerCase();
441
+
442
+ if(column.definition.headerFilterLiveFilter !== false){
443
+
444
+ if (
445
+ !(
446
+ column.definition.headerFilter === 'autocomplete' ||
447
+ column.definition.headerFilter === 'tickCross' ||
448
+ ((column.definition.editor === 'autocomplete' ||
449
+ column.definition.editor === 'tickCross') &&
450
+ column.definition.headerFilter === true)
451
+ )
452
+ ) {
453
+ editorElement.addEventListener("keyup", searchTrigger);
454
+ editorElement.addEventListener("search", searchTrigger);
455
+
456
+
457
+ //update number filtered columns on change
458
+ if(column.modules.filter.attrType == "number"){
459
+ editorElement.addEventListener("change", function(e){
460
+ success(editorElement.value);
461
+ });
462
+ }
463
+
464
+ //change text inputs to search inputs to allow for clearing of field
465
+ if(column.modules.filter.attrType == "text" && this.table.browser !== "ie"){
466
+ editorElement.setAttribute("type", "search");
467
+ // editorElement.off("change blur"); //prevent blur from triggering filter and preventing selection click
468
+ }
469
+
470
+ }
471
+
472
+ //prevent input and select elements from propagating click to column sorters etc
473
+ if(column.modules.filter.tagType == "input" || column.modules.filter.tagType == "select" || column.modules.filter.tagType == "textarea"){
474
+ editorElement.addEventListener("mousedown",function(e){
475
+ e.stopPropagation();
476
+ });
477
+ }
478
+ }
479
+
480
+ filterElement.appendChild(editorElement);
481
+
482
+ column.contentElement.appendChild(filterElement);
483
+
484
+ if(!reinitialize){
485
+ self.headerFilterColumns.push(column);
486
+ }
487
+
488
+ if(onRenderedCallback){
489
+ onRenderedCallback();
490
+ }
491
+ }
492
+ }else{
493
+ console.warn("Filter Error - Cannot add header filter, column has no field set:", column.definition.title);
494
+ }
495
+ }
496
+
497
+ //hide all header filter elements (used to ensure correct column widths in "fitData" layout mode)
498
+ hideHeaderFilterElements(){
499
+ this.headerFilterColumns.forEach(function(column){
500
+ if(column.modules.filter && column.modules.filter.headerElement){
501
+ column.modules.filter.headerElement.style.display = 'none';
502
+ }
503
+ });
504
+ }
505
+
506
+ //show all header filter elements (used to ensure correct column widths in "fitData" layout mode)
507
+ showHeaderFilterElements(){
508
+ this.headerFilterColumns.forEach(function(column){
509
+ if(column.modules.filter && column.modules.filter.headerElement){
510
+ column.modules.filter.headerElement.style.display = '';
511
+ }
512
+ });
513
+ }
514
+
515
+ //programmatically set focus of header filter
516
+ setHeaderFilterFocus(column){
517
+ if(column.modules.filter && column.modules.filter.headerElement){
518
+ column.modules.filter.headerElement.focus();
519
+ }else{
520
+ console.warn("Column Filter Focus Error - No header filter set on column:", column.getField());
521
+ }
522
+ }
523
+
524
+ //programmatically get value of header filter
525
+ getHeaderFilterValue(column){
526
+ if(column.modules.filter && column.modules.filter.headerElement){
527
+ return column.modules.filter.value;
528
+ } else {
529
+ console.warn("Column Filter Error - No header filter set on column:", column.getField());
530
+ }
531
+ }
532
+
533
+ //programmatically set value of header filter
534
+ setHeaderFilterValue(column, value){
535
+ if (column){
536
+ if(column.modules.filter && column.modules.filter.headerElement){
537
+ this.generateHeaderFilterElement(column, value, true);
538
+ column.modules.filter.success(value);
539
+ }else{
540
+ console.warn("Column Filter Error - No header filter set on column:", column.getField());
541
+ }
542
+ }
543
+ }
544
+
545
+ reloadHeaderFilter(column){
546
+ if (column){
547
+ if(column.modules.filter && column.modules.filter.headerElement){
548
+ this.generateHeaderFilterElement(column, column.modules.filter.value, true);
549
+ }else{
550
+ console.warn("Column Filter Error - No header filter set on column:", column.getField());
551
+ }
552
+ }
553
+ }
554
+
555
+ refreshFilter(){
556
+ if(this.tableInitialized){
557
+ if(this.table.options.filterMode === "remote"){
558
+ this.reloadData(null, false, false);
559
+ }else{
560
+ this.refreshData(true);
561
+ }
562
+ }
563
+
564
+ //TODO - Persist left position of row manager
565
+ // left = this.scrollLeft;
566
+ // this.scrollHorizontal(left);
567
+ }
568
+
569
+ //check if the filters has changed since last use
570
+ trackChanges(){
571
+ this.changed = true;
572
+ this.dispatch("filter-changed");
573
+ }
574
+
575
+ //check if the filters has changed since last use
576
+ hasChanged(){
577
+ var changed = this.changed;
578
+ this.changed = false;
579
+ return changed;
580
+ }
581
+
582
+ //set standard filters
583
+ setFilter(field, type, value, params){
584
+ this.filterList = [];
585
+
586
+ if(!Array.isArray(field)){
587
+ field = [{field:field, type:type, value:value, params:params}];
588
+ }
589
+
590
+ this.addFilter(field);
591
+ }
592
+
593
+ //add filter to array
594
+ addFilter(field, type, value, params){
595
+ var changed = false;
596
+
597
+ if(!Array.isArray(field)){
598
+ field = [{field:field, type:type, value:value, params:params}];
599
+ }
600
+
601
+ field.forEach((filter) => {
602
+ filter = this.findFilter(filter);
603
+
604
+ if(filter){
605
+ this.filterList.push(filter);
606
+ changed = true;
607
+ }
608
+ });
609
+
610
+ if(changed){
611
+ this.trackChanges();
612
+ }
613
+ }
614
+
615
+ findFilter(filter){
616
+ var column;
617
+
618
+ if(Array.isArray(filter)){
619
+ return this.findSubFilters(filter);
620
+ }
621
+
622
+ var filterFunc = false;
623
+
624
+ if(typeof filter.field == "function"){
625
+ filterFunc = function(data){
626
+ return filter.field(data, filter.type || {});// pass params to custom filter function
627
+ };
628
+ }else{
629
+
630
+ if(Filter.filters[filter.type]){
631
+
632
+ column = this.table.columnManager.getColumnByField(filter.field);
633
+
634
+ if(column){
635
+ filterFunc = function(data){
636
+ return Filter.filters[filter.type](filter.value, column.getFieldValue(data), data, filter.params || {});
637
+ };
638
+ }else{
639
+ filterFunc = function(data){
640
+ return Filter.filters[filter.type](filter.value, data[filter.field], data, filter.params || {});
641
+ };
642
+ }
643
+
644
+
645
+ }else{
646
+ console.warn("Filter Error - No such filter type found, ignoring: ", filter.type);
647
+ }
648
+ }
649
+
650
+ filter.func = filterFunc;
651
+
652
+ return filter.func ? filter : false;
653
+ }
654
+
655
+ findSubFilters(filters){
656
+ var output = [];
657
+
658
+ filters.forEach((filter) => {
659
+ filter = this.findFilter(filter);
660
+
661
+ if(filter){
662
+ output.push(filter);
663
+ }
664
+ });
665
+
666
+ return output.length ? output : false;
667
+ }
668
+
669
+ //get all filters
670
+ getFilters(all, ajax){
671
+ var output = [];
672
+
673
+ if(all){
674
+ output = this.getHeaderFilters();
675
+ }
676
+
677
+ if(ajax){
678
+ output.forEach(function(item){
679
+ if(typeof item.type == "function"){
680
+ item.type = "function";
681
+ }
682
+ });
683
+ }
684
+
685
+ output = output.concat(this.filtersToArray(this.filterList, ajax));
686
+
687
+ return output;
688
+ }
689
+
690
+ //filter to Object
691
+ filtersToArray(filterList, ajax){
692
+ var output = [];
693
+
694
+ filterList.forEach((filter) => {
695
+ var item;
696
+
697
+ if(Array.isArray(filter)){
698
+ output.push(this.filtersToArray(filter, ajax));
699
+ }else{
700
+ item = {field:filter.field, type:filter.type, value:filter.value};
701
+
702
+ if(ajax){
703
+ if(typeof item.type == "function"){
704
+ item.type = "function";
705
+ }
706
+ }
707
+
708
+ output.push(item);
709
+ }
710
+ });
711
+
712
+ return output;
713
+ }
714
+
715
+ //get all filters
716
+ getHeaderFilters(){
717
+ var output = [];
718
+
719
+ for(var key in this.headerFilters){
720
+ output.push({field:key, type:this.headerFilters[key].type, value:this.headerFilters[key].value});
721
+ }
722
+
723
+ return output;
724
+ }
725
+
726
+ //remove filter from array
727
+ removeFilter(field, type, value){
728
+ if(!Array.isArray(field)){
729
+ field = [{field:field, type:type, value:value}];
730
+ }
731
+
732
+ field.forEach((filter) => {
733
+ var index = -1;
734
+
735
+ if(typeof filter.field == "object"){
736
+ index = this.filterList.findIndex((element) => {
737
+ return filter === element;
738
+ });
739
+ }else{
740
+ index = this.filterList.findIndex((element) => {
741
+ return filter.field === element.field && filter.type === element.type && filter.value === element.value;
742
+ });
743
+ }
744
+
745
+ if(index > -1){
746
+ this.filterList.splice(index, 1);
747
+ }else{
748
+ console.warn("Filter Error - No matching filter type found, ignoring: ", filter.type);
749
+ }
750
+ });
751
+
752
+ this.trackChanges();
753
+ }
754
+
755
+ //clear filters
756
+ clearFilter(all){
757
+ this.filterList = [];
758
+
759
+ if(all){
760
+ this.clearHeaderFilter();
761
+ }
762
+
763
+ this.trackChanges();
764
+ }
765
+
766
+ //clear header filters
767
+ clearHeaderFilter(){
768
+ this.headerFilters = {};
769
+ this.prevHeaderFilterChangeCheck = "{}";
770
+
771
+ this.headerFilterColumns.forEach((column) => {
772
+ if(typeof column.modules.filter.value !== "undefined"){
773
+ delete column.modules.filter.value;
774
+ }
775
+ column.modules.filter.prevSuccess = undefined;
776
+ this.reloadHeaderFilter(column);
777
+ });
778
+
779
+ this.trackChanges();
780
+ }
781
+
782
+ //search data and return matching rows
783
+ search (searchType, field, type, value){
784
+ var activeRows = [],
785
+ filterList = [];
786
+
787
+ if(!Array.isArray(field)){
788
+ field = [{field:field, type:type, value:value}];
789
+ }
790
+
791
+ field.forEach((filter) => {
792
+ filter = this.findFilter(filter);
793
+
794
+ if(filter){
795
+ filterList.push(filter);
796
+ }
797
+ });
798
+
799
+ this.table.rowManager.rows.forEach((row) => {
800
+ var match = true;
801
+
802
+ filterList.forEach((filter) => {
803
+ if(!this.filterRecurse(filter, row.getData())){
804
+ match = false;
805
+ }
806
+ });
807
+
808
+ if(match){
809
+ activeRows.push(searchType === "data" ? row.getData("data") : row.getComponent());
810
+ }
811
+
812
+ });
813
+
814
+ return activeRows;
815
+ }
816
+
817
+ //filter row array
818
+ filter(rowList, filters){
819
+ var activeRows = [],
820
+ activeRowComponents = [];
821
+
822
+ if(this.subscribedExternal("dataFiltering")){
823
+ this.dispatchExternal("dataFiltering", this.getFilters(true));
824
+ }
825
+
826
+ if(this.table.options.filterMode !== "remote" && (this.filterList.length || Object.keys(this.headerFilters).length)){
827
+
828
+ rowList.forEach((row) => {
829
+ if(this.filterRow(row)){
830
+ activeRows.push(row);
831
+ }
832
+ });
833
+
834
+ }else{
835
+ activeRows = rowList.slice(0);
836
+ }
837
+
838
+ if(this.subscribedExternal("dataFiltered")){
839
+
840
+ activeRows.forEach((row) => {
841
+ activeRowComponents.push(row.getComponent());
842
+ });
843
+
844
+ this.dispatchExternal("dataFiltered", this.getFilters(true), activeRowComponents);
845
+ }
846
+
847
+ return activeRows;
848
+ }
849
+
850
+ //filter individual row
851
+ filterRow(row, filters){
852
+ var match = true,
853
+ data = row.getData();
854
+
855
+ this.filterList.forEach((filter) => {
856
+ if(!this.filterRecurse(filter, data)){
857
+ match = false;
858
+ }
859
+ });
860
+
861
+
862
+ for(var field in this.headerFilters){
863
+ if(!this.headerFilters[field].func(data)){
864
+ match = false;
865
+ }
866
+ }
867
+
868
+ return match;
869
+ }
870
+
871
+ filterRecurse(filter, data){
872
+ var match = false;
873
+
874
+ if(Array.isArray(filter)){
875
+ filter.forEach((subFilter) => {
876
+ if(this.filterRecurse(subFilter, data)){
877
+ match = true;
878
+ }
879
+ });
880
+ }else{
881
+ match = filter.func(data);
882
+ }
883
+
884
+ return match;
885
+ }
886
+ }
887
+
888
+ Filter.moduleName = "filter";
889
+
890
+ //load defaults
891
+ Filter.filters = defaultFilters;
892
+
890
893
  export default Filter;