1 | import {Feature} from '../feature';
|
2 | import {isUndef, EMPTY_FN} from '../types';
|
3 | import {createElm, removeElm} from '../dom';
|
4 | import {addEvt, cancelEvt, stopEvt, targetEvt, removeEvt} from '../event';
|
5 | import {INPUT, NONE, CHECKLIST, MULTIPLE} from '../const';
|
6 | import {root} from '../root';
|
7 | import {defaultsStr, defaultsBool, defaultsArr, defaultsFn} from '../settings';
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | export class PopupFilter extends Feature {
|
16 |
|
17 | |
18 |
|
19 |
|
20 |
|
21 | constructor(tf) {
|
22 | super(tf, PopupFilter);
|
23 |
|
24 |
|
25 | let f = this.config.popup_filters || {};
|
26 |
|
27 | |
28 |
|
29 |
|
30 |
|
31 | this.closeOnFiltering = defaultsBool(f.close_on_filtering, true);
|
32 |
|
33 | |
34 |
|
35 |
|
36 |
|
37 | this.iconPath = defaultsStr(f.image, tf.themesPath + 'icn_filter.gif');
|
38 |
|
39 | |
40 |
|
41 |
|
42 |
|
43 | this.activeIconPath = defaultsStr(f.image_active,
|
44 | tf.themesPath + 'icn_filterActive.gif');
|
45 |
|
46 | |
47 |
|
48 |
|
49 |
|
50 | this.iconHtml = defaultsStr(f.image_html,
|
51 | '<img src="' + this.iconPath + '" alt="Column filter" />');
|
52 |
|
53 | |
54 |
|
55 |
|
56 |
|
57 | this.placeholderCssClass = defaultsStr(f.placeholder_css_class,
|
58 | 'popUpPlaceholder');
|
59 |
|
60 | |
61 |
|
62 |
|
63 |
|
64 | this.containerCssClass = defaultsStr(f.div_css_class, 'popUpFilter');
|
65 |
|
66 | |
67 |
|
68 |
|
69 |
|
70 |
|
71 | this.adjustToContainer = defaultsBool(f.adjust_to_container, true);
|
72 |
|
73 | |
74 |
|
75 |
|
76 |
|
77 | this.onBeforeOpen = defaultsFn(f.on_before_popup_filter_open, EMPTY_FN);
|
78 |
|
79 | |
80 |
|
81 |
|
82 |
|
83 | this.onAfterOpen = defaultsFn(f.on_after_popup_filter_open, EMPTY_FN);
|
84 |
|
85 | |
86 |
|
87 |
|
88 |
|
89 | this.onBeforeClose = defaultsFn(f.on_before_popup_filter_close,
|
90 | EMPTY_FN);
|
91 |
|
92 | |
93 |
|
94 |
|
95 |
|
96 | this.onAfterClose = defaultsFn(f.on_after_popup_filter_close, EMPTY_FN);
|
97 |
|
98 | |
99 |
|
100 |
|
101 |
|
102 |
|
103 | this.fltSpans = [];
|
104 |
|
105 | |
106 |
|
107 |
|
108 |
|
109 |
|
110 | this.fltIcons = [];
|
111 |
|
112 | |
113 |
|
114 |
|
115 |
|
116 |
|
117 | this.filtersCache = null;
|
118 |
|
119 | |
120 |
|
121 |
|
122 |
|
123 |
|
124 | this.fltElms = defaultsArr(this.filtersCache, []);
|
125 |
|
126 | |
127 |
|
128 |
|
129 |
|
130 |
|
131 | this.prfxDiv = 'popup_';
|
132 |
|
133 | |
134 |
|
135 |
|
136 |
|
137 |
|
138 | this.activeFilterIdx = -1;
|
139 | }
|
140 |
|
141 | |
142 |
|
143 |
|
144 |
|
145 | onClick(evt) {
|
146 | let elm = targetEvt(evt).parentNode;
|
147 | let colIndex = parseInt(elm.getAttribute('ci'), 10);
|
148 |
|
149 | this.closeAll(colIndex);
|
150 | this.toggle(colIndex);
|
151 |
|
152 | if (this.adjustToContainer) {
|
153 | let cont = this.fltElms[colIndex],
|
154 | header = this.tf.getHeaderElement(colIndex),
|
155 | headerWidth = header.clientWidth * 0.95;
|
156 | cont.style.width = parseInt(headerWidth, 10) + 'px';
|
157 | }
|
158 | cancelEvt(evt);
|
159 | stopEvt(evt);
|
160 | }
|
161 |
|
162 | |
163 |
|
164 |
|
165 |
|
166 | onMouseup(evt) {
|
167 | if (this.activeFilterIdx === -1) {
|
168 | return;
|
169 | }
|
170 | let targetElm = targetEvt(evt);
|
171 | let activeFlt = this.fltElms[this.activeFilterIdx];
|
172 | let icon = this.fltIcons[this.activeFilterIdx];
|
173 |
|
174 | if (icon === targetElm) {
|
175 | return;
|
176 | }
|
177 |
|
178 | while (targetElm && targetElm !== activeFlt) {
|
179 | targetElm = targetElm.parentNode;
|
180 | }
|
181 |
|
182 | if (targetElm !== activeFlt) {
|
183 | this.close(this.activeFilterIdx);
|
184 | }
|
185 |
|
186 | return;
|
187 | }
|
188 |
|
189 | |
190 |
|
191 |
|
192 | init() {
|
193 | if (this.initialized) {
|
194 | return;
|
195 | }
|
196 |
|
197 | let tf = this.tf;
|
198 |
|
199 |
|
200 | tf.externalFltIds = [''];
|
201 |
|
202 |
|
203 | tf.filtersRowIndex = 0;
|
204 |
|
205 |
|
206 |
|
207 |
|
208 | if (tf.headersRow <= 1 && isNaN(tf.config().headers_row_index)) {
|
209 | tf.headersRow = 0;
|
210 | }
|
211 |
|
212 |
|
213 |
|
214 |
|
215 | if (tf.gridLayout) {
|
216 | tf.headersRow--;
|
217 | this.buildIcons();
|
218 | }
|
219 |
|
220 |
|
221 | this.emitter.on(['before-filtering'], () => this.setIconsState());
|
222 | this.emitter.on(['after-filtering'], () => this.closeAll());
|
223 | this.emitter.on(['cell-processed'],
|
224 | (tf, cellIndex) => this.changeState(cellIndex, true));
|
225 | this.emitter.on(['filters-row-inserted'], () => this.buildIcons());
|
226 | this.emitter.on(['before-filter-init'],
|
227 | (tf, colIndex) => this.build(colIndex));
|
228 |
|
229 |
|
230 | this.initialized = true;
|
231 | }
|
232 |
|
233 | |
234 |
|
235 |
|
236 | reset() {
|
237 | this.enable();
|
238 | this.init();
|
239 | this.buildIcons();
|
240 | this.buildAll();
|
241 | }
|
242 |
|
243 | |
244 |
|
245 |
|
246 | buildIcons() {
|
247 | let tf = this.tf;
|
248 |
|
249 |
|
250 |
|
251 | tf.headersRow++;
|
252 |
|
253 | tf.eachCol(
|
254 | (i) => {
|
255 | let icon = createElm('span', ['ci', i]);
|
256 | icon.innerHTML = this.iconHtml;
|
257 | let header = tf.getHeaderElement(i);
|
258 | header.appendChild(icon);
|
259 | addEvt(icon, 'click', (evt) => this.onClick(evt));
|
260 | this.fltSpans[i] = icon;
|
261 | this.fltIcons[i] = icon.firstChild;
|
262 | },
|
263 |
|
264 | (i) => tf.getFilterType(i) === NONE
|
265 | );
|
266 | }
|
267 |
|
268 | |
269 |
|
270 |
|
271 | buildAll() {
|
272 | for (let i = 0; i < this.filtersCache.length; i++) {
|
273 | this.build(i, this.filtersCache[i]);
|
274 | }
|
275 | }
|
276 |
|
277 | |
278 |
|
279 |
|
280 |
|
281 |
|
282 | build(colIndex, div) {
|
283 | let tf = this.tf;
|
284 | let contId = `${this.prfxDiv}${tf.id}_${colIndex}`;
|
285 | let placeholder = createElm('div', ['class', this.placeholderCssClass]);
|
286 | let cont = div ||
|
287 | createElm('div', ['id', contId], ['class', this.containerCssClass]);
|
288 | tf.externalFltIds[colIndex] = cont.id;
|
289 | placeholder.appendChild(cont);
|
290 |
|
291 | let header = tf.getHeaderElement(colIndex);
|
292 | header.insertBefore(placeholder, header.firstChild);
|
293 | addEvt(cont, 'click', (evt) => stopEvt(evt));
|
294 | this.fltElms[colIndex] = cont;
|
295 | }
|
296 |
|
297 | |
298 |
|
299 |
|
300 |
|
301 | toggle(colIndex) {
|
302 | if (!this.isOpen(colIndex)) {
|
303 | this.open(colIndex);
|
304 | } else {
|
305 | this.close(colIndex);
|
306 | }
|
307 | }
|
308 |
|
309 | |
310 |
|
311 |
|
312 |
|
313 | open(colIndex) {
|
314 | let tf = this.tf,
|
315 | container = this.fltElms[colIndex];
|
316 |
|
317 | this.onBeforeOpen(this, container, colIndex);
|
318 |
|
319 | container.style.display = 'block';
|
320 | this.activeFilterIdx = colIndex;
|
321 | addEvt(root, 'mouseup', (evt) => this.onMouseup(evt));
|
322 |
|
323 | if (tf.getFilterType(colIndex) === INPUT) {
|
324 | let flt = tf.getFilterElement(colIndex);
|
325 | if (flt) {
|
326 | flt.focus();
|
327 | }
|
328 | }
|
329 |
|
330 | this.onAfterOpen(this, container, colIndex);
|
331 | }
|
332 |
|
333 | |
334 |
|
335 |
|
336 |
|
337 | close(colIndex) {
|
338 | let container = this.fltElms[colIndex];
|
339 |
|
340 | this.onBeforeClose(this, container, colIndex);
|
341 |
|
342 | container.style.display = NONE;
|
343 | if (this.activeFilterIdx === colIndex) {
|
344 | this.activeFilterIdx = -1;
|
345 | }
|
346 | removeEvt(root, 'mouseup', (evt) => this.onMouseup(evt));
|
347 |
|
348 | this.onAfterClose(this, container, colIndex);
|
349 | }
|
350 |
|
351 | |
352 |
|
353 |
|
354 |
|
355 |
|
356 | isOpen(colIndex) {
|
357 | return this.fltElms[colIndex].style.display === 'block';
|
358 | }
|
359 |
|
360 | |
361 |
|
362 |
|
363 |
|
364 | closeAll(exceptIdx) {
|
365 |
|
366 |
|
367 | if (isUndef(exceptIdx) && !this.closeOnFiltering) {
|
368 | return;
|
369 | }
|
370 | for (let i = 0; i < this.fltElms.length; i++) {
|
371 | if (i === exceptIdx) {
|
372 | continue;
|
373 | }
|
374 | let fltType = this.tf.getFilterType(i);
|
375 | let isMultipleFilter =
|
376 | (fltType === CHECKLIST || fltType === MULTIPLE);
|
377 |
|
378 |
|
379 |
|
380 | if (!isMultipleFilter || !isUndef(exceptIdx)) {
|
381 | this.close(i);
|
382 | }
|
383 | }
|
384 | }
|
385 |
|
386 | |
387 |
|
388 |
|
389 | setIconsState() {
|
390 | for (let i = 0; i < this.fltIcons.length; i++) {
|
391 | this.changeState(i, false);
|
392 | }
|
393 | }
|
394 |
|
395 | |
396 |
|
397 |
|
398 |
|
399 |
|
400 | changeState(colIndex, active) {
|
401 | let icon = this.fltIcons[colIndex];
|
402 | if (icon) {
|
403 | icon.src = active ? this.activeIconPath : this.iconPath;
|
404 | }
|
405 | }
|
406 |
|
407 | |
408 |
|
409 |
|
410 | destroy() {
|
411 | if (!this.initialized) {
|
412 | return;
|
413 | }
|
414 |
|
415 | this.filtersCache = [];
|
416 | for (let i = 0; i < this.fltElms.length; i++) {
|
417 | let container = this.fltElms[i],
|
418 | placeholder = container.parentNode,
|
419 | icon = this.fltSpans[i],
|
420 | iconImg = this.fltIcons[i];
|
421 | if (container) {
|
422 | removeElm(container);
|
423 | this.filtersCache[i] = container;
|
424 | }
|
425 | container = null;
|
426 | if (placeholder) {
|
427 | removeElm(placeholder);
|
428 | }
|
429 | placeholder = null;
|
430 | if (icon) {
|
431 | removeElm(icon);
|
432 | }
|
433 | icon = null;
|
434 | if (iconImg) {
|
435 | removeElm(iconImg);
|
436 | }
|
437 | iconImg = null;
|
438 | }
|
439 | this.fltElms = [];
|
440 | this.fltSpans = [];
|
441 | this.fltIcons = [];
|
442 |
|
443 |
|
444 | this.tf.externalFltIds = [];
|
445 |
|
446 |
|
447 | this.emitter.off(['before-filtering'], () => this.setIconsState());
|
448 | this.emitter.off(['after-filtering'], () => this.closeAll());
|
449 | this.emitter.off(['cell-processed'],
|
450 | (tf, cellIndex) => this.changeState(cellIndex, true));
|
451 | this.emitter.off(['filters-row-inserted'], () => this.buildIcons());
|
452 | this.emitter.off(['before-filter-init'],
|
453 | (tf, colIndex) => this.build(colIndex));
|
454 |
|
455 | this.initialized = false;
|
456 | }
|
457 |
|
458 | }
|
459 |
|
460 |
|
461 | PopupFilter.meta = {altName: 'popupFilters'};
|