1 | import {Utils as _} from "../utils";
|
2 | import {IFilterParams, IDoesFilterPassParams, SerializedFilter} from "../interfaces/iFilter";
|
3 | import {
|
4 | ComparableBaseFilter,
|
5 | BaseFilter,
|
6 | IScalarFilterParams,
|
7 | FilterConditionType,
|
8 | IComparableFilterParams
|
9 | } from "./baseFilter";
|
10 | import {QuerySelector} from "../widgets/componentAnnotations";
|
11 |
|
12 | export interface SerializedTextFilter extends SerializedFilter {
|
13 | filter: string;
|
14 | type: string;
|
15 | }
|
16 |
|
17 | export interface TextComparator {
|
18 | (filter: string, gridValue: any, filterText: string): boolean;
|
19 | }
|
20 |
|
21 | export interface TextFormatter {
|
22 | (from: string): string;
|
23 | }
|
24 |
|
25 | export interface INumberFilterParams extends IScalarFilterParams {
|
26 | debounceMs?: number;
|
27 | }
|
28 |
|
29 | export interface ITextFilterParams extends IComparableFilterParams {
|
30 | textCustomComparator?: TextComparator;
|
31 | debounceMs?: number;
|
32 | caseSensitive?: boolean;
|
33 | }
|
34 |
|
35 | export class TextFilter extends ComparableBaseFilter <string, ITextFilterParams, SerializedTextFilter> {
|
36 | @QuerySelector('#filterText')
|
37 | private eFilterTextField: HTMLInputElement;
|
38 |
|
39 | @QuerySelector('#filterConditionText')
|
40 | private eFilterConditionTextField: HTMLInputElement;
|
41 |
|
42 | private filterText: string;
|
43 | private filterConditionText: string;
|
44 | private comparator: TextComparator;
|
45 | private formatter: TextFormatter;
|
46 | static DEFAULT_FORMATTER: TextFormatter = (from: string)=> {
|
47 | return from;
|
48 | };
|
49 | static DEFAULT_LOWERCASE_FORMATTER: TextFormatter = (from: string)=> {
|
50 | if (from == null) { return null; }
|
51 | return from.toString().toLowerCase();
|
52 | };
|
53 | static DEFAULT_COMPARATOR: TextComparator = (filter: string, value: any, filterText: string)=> {
|
54 | switch (filter) {
|
55 | case TextFilter.CONTAINS:
|
56 | return value.indexOf(filterText) >= 0;
|
57 | case TextFilter.NOT_CONTAINS:
|
58 | return value.indexOf(filterText) === -1;
|
59 | case TextFilter.EQUALS:
|
60 | return value === filterText;
|
61 | case TextFilter.NOT_EQUAL:
|
62 | return value != filterText;
|
63 | case TextFilter.STARTS_WITH:
|
64 | return value.indexOf(filterText) === 0;
|
65 | case TextFilter.ENDS_WITH:
|
66 | let index = value.lastIndexOf(filterText);
|
67 | return index >= 0 && index === (value.length - filterText.length);
|
68 | default:
|
69 |
|
70 | console.warn('invalid filter type ' + filter);
|
71 | return false;
|
72 | }
|
73 | };
|
74 |
|
75 | public getDefaultType(): string {
|
76 | return BaseFilter.CONTAINS;
|
77 | }
|
78 |
|
79 | public customInit(): void {
|
80 | this.comparator = this.filterParams.textCustomComparator ? this.filterParams.textCustomComparator : TextFilter.DEFAULT_COMPARATOR;
|
81 | this.formatter =
|
82 | this.filterParams.textFormatter ? this.filterParams.textFormatter :
|
83 | this.filterParams.caseSensitive == true ? TextFilter.DEFAULT_FORMATTER :
|
84 | TextFilter.DEFAULT_LOWERCASE_FORMATTER;
|
85 | super.customInit();
|
86 | }
|
87 |
|
88 | modelFromFloatingFilter(from: string): SerializedTextFilter {
|
89 | return {
|
90 | type: this.filter,
|
91 | filter: from,
|
92 | filterType: 'text'
|
93 | };
|
94 | }
|
95 |
|
96 | public getApplicableFilterTypes(): string[] {
|
97 | return [BaseFilter.EQUALS, BaseFilter.NOT_EQUAL, BaseFilter.STARTS_WITH, BaseFilter.ENDS_WITH,
|
98 | BaseFilter.CONTAINS, BaseFilter.NOT_CONTAINS];
|
99 | }
|
100 |
|
101 | public bodyTemplate(type:FilterConditionType): string {
|
102 | let translate = this.translate.bind(this);
|
103 | let fieldId = type == FilterConditionType.MAIN ? "filterText" : "filterConditionText";
|
104 | return `<div class="ag-filter-body">
|
105 | <input class="ag-filter-filter" id=${fieldId} type="text" placeholder="${translate('filterOoo', 'Filter...')}"/>
|
106 | </div>`;
|
107 | }
|
108 |
|
109 | public initialiseFilterBodyUi(type:FilterConditionType) {
|
110 | super.initialiseFilterBodyUi(type);
|
111 | this.addFilterChangedListener(type);
|
112 | this.setFilter(this.filterConditionText, FilterConditionType.CONDITION);
|
113 | this.setFilterType(this.filterCondition, FilterConditionType.CONDITION);
|
114 | }
|
115 |
|
116 | private addFilterChangedListener(type:FilterConditionType) {
|
117 | let eElement = type === FilterConditionType.MAIN ? this.eFilterTextField : this.eFilterConditionTextField;
|
118 | let debounceMs = this.getDebounceMs(this.filterParams);
|
119 | let toDebounce: () => void = _.debounce(()=>this.onFilterTextFieldChanged(type), debounceMs);
|
120 | this.addDestroyableEventListener(eElement, 'input', toDebounce);
|
121 | }
|
122 |
|
123 | public refreshFilterBodyUi(type:FilterConditionType) {
|
124 | if (this.eFilterConditionTextField){
|
125 | this.addFilterChangedListener(FilterConditionType.CONDITION);
|
126 | }
|
127 | }
|
128 |
|
129 | public afterGuiAttached() {
|
130 | this.eFilterTextField.focus();
|
131 | }
|
132 |
|
133 | public filterValues(type:FilterConditionType): string {
|
134 | return type === FilterConditionType.MAIN ? this.filterText : this.filterConditionText;
|
135 | }
|
136 |
|
137 | public individualFilterPasses (params: IDoesFilterPassParams, type:FilterConditionType): boolean {
|
138 | let filterText:string = type == FilterConditionType.MAIN ? this.filterText : this.filterConditionText;
|
139 | let filter:string = type == FilterConditionType.MAIN ? this.filter : this.filterCondition;
|
140 |
|
141 | if (!filterText) {
|
142 | return type === FilterConditionType.MAIN ? true : this.conditionValue === 'AND';
|
143 | } else {
|
144 | return this.checkIndividualFilter (params, filter, filterText);
|
145 | }
|
146 | }
|
147 |
|
148 | private checkIndividualFilter (params: IDoesFilterPassParams, filterType:string, filterText: string) {
|
149 | let value = this.filterParams.valueGetter(params.node);
|
150 | if (value == null || value === undefined) {
|
151 | return filterType === BaseFilter.NOT_EQUAL || filterType === BaseFilter.NOT_CONTAINS;
|
152 | }
|
153 | let valueFormatted: string = this.formatter(value);
|
154 | return this.comparator (filterType, valueFormatted, filterText);
|
155 | }
|
156 |
|
157 | private onFilterTextFieldChanged(type:FilterConditionType) {
|
158 | let value:string = type === FilterConditionType.MAIN ? this.eFilterTextField.value : this.eFilterConditionTextField.value;
|
159 | let current:string = type === FilterConditionType.MAIN ? this.filterText : this.filterConditionText;
|
160 |
|
161 | let filterText = _.makeNull(value);
|
162 | if (filterText && filterText.trim() === '') {
|
163 | filterText = null;
|
164 | }
|
165 |
|
166 | if (current !== filterText) {
|
167 | let newLowerCase =
|
168 | filterText && this.filterParams.caseSensitive != true ? filterText.toLowerCase() :
|
169 | filterText;
|
170 | let previousLowerCase = current && this.filterParams.caseSensitive != true ? current.toLowerCase() :
|
171 | current;
|
172 |
|
173 | if (type === FilterConditionType.MAIN){
|
174 | this.filterText = this.formatter(filterText);
|
175 |
|
176 | } else {
|
177 | this.filterConditionText = this.formatter(filterText);
|
178 | }
|
179 | if (previousLowerCase !== newLowerCase) {
|
180 | this.onFilterChanged();
|
181 | }
|
182 | }
|
183 | }
|
184 |
|
185 | public setFilter(filter: string, type:FilterConditionType): void {
|
186 | filter = _.makeNull(filter);
|
187 |
|
188 | if (type === FilterConditionType.MAIN) {
|
189 | if (filter) {
|
190 | this.filterText = this.formatter(filter);
|
191 |
|
192 | if (!this.eFilterTextField) return;
|
193 | this.eFilterTextField.value = filter;
|
194 | } else {
|
195 | this.filterText = null;
|
196 |
|
197 | if (!this.eFilterTextField) return;
|
198 | this.eFilterTextField.value = null;
|
199 | }
|
200 | } else {
|
201 | if (filter) {
|
202 | this.filterConditionText = this.formatter(filter);
|
203 |
|
204 | if (!this.eFilterConditionTextField) return;
|
205 | this.eFilterConditionTextField.value = filter;
|
206 | } else {
|
207 | this.filterConditionText = null;
|
208 |
|
209 | if (!this.eFilterConditionTextField) return;
|
210 | this.eFilterConditionTextField.value = null;
|
211 | }
|
212 | }
|
213 | }
|
214 |
|
215 | public getFilter(): string {
|
216 | return this.filterText;
|
217 | }
|
218 |
|
219 | public resetState(): void {
|
220 | this.setFilter(null, FilterConditionType.MAIN);
|
221 | this.setFilterType(this.defaultFilter, FilterConditionType.MAIN);
|
222 |
|
223 | this.setFilter(null, FilterConditionType.CONDITION);
|
224 | this.setFilterType(this.defaultFilter, FilterConditionType.CONDITION);
|
225 | }
|
226 |
|
227 | public serialize(type:FilterConditionType): SerializedTextFilter {
|
228 | let filter = type === FilterConditionType.MAIN ? this.filter : this.filterCondition;
|
229 | let filterText = type === FilterConditionType.MAIN ? this.filterText : this.filterConditionText;
|
230 | return {
|
231 | type: filter ? filter : this.defaultFilter,
|
232 | filter: filterText,
|
233 | filterType: 'text'
|
234 | };
|
235 | }
|
236 |
|
237 | public parse(model: SerializedTextFilter, type:FilterConditionType): void {
|
238 | this.setFilterType(model.type, type);
|
239 | this.setFilter(model.filter, type);
|
240 | }
|
241 |
|
242 | public setType(filterType: string, type:FilterConditionType): void {
|
243 | this.setFilterType(filterType, type);
|
244 | }
|
245 |
|
246 | }
|