1 | import {Feature} from '../../feature';
|
2 | import {
|
3 | addClass, removeClass, createCheckItem, createElm, elm, removeElm,
|
4 | getText, tag
|
5 | } from '../../dom';
|
6 | import {isUndef, EMPTY_FN, isNull} from '../../types';
|
7 | import {addEvt, targetEvt, removeEvt} from '../../event';
|
8 | import {root} from '../../root';
|
9 | import {NONE} from '../../const';
|
10 | import {
|
11 | defaultsBool, defaultsStr, defaultsFn, defaultsNb, defaultsArr
|
12 | } from '../../settings';
|
13 | import {RIGHT} from '../../modules/toolbar';
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | export default class ColsVisibility extends Feature {
|
19 |
|
20 | |
21 |
|
22 |
|
23 |
|
24 |
|
25 | constructor(tf, f) {
|
26 | super(tf, f.name);
|
27 |
|
28 |
|
29 | let cfg = this.config;
|
30 |
|
31 | |
32 |
|
33 |
|
34 |
|
35 | this.name = f.name;
|
36 |
|
37 | |
38 |
|
39 |
|
40 |
|
41 | this.desc = defaultsStr(f.description, 'Columns visibility manager');
|
42 |
|
43 | |
44 |
|
45 |
|
46 |
|
47 | this.spanEl = null;
|
48 |
|
49 | |
50 |
|
51 |
|
52 |
|
53 | this.btnEl = null;
|
54 |
|
55 | |
56 |
|
57 |
|
58 |
|
59 | this.contEl = null;
|
60 |
|
61 | |
62 |
|
63 |
|
64 |
|
65 | this.tickToHide = defaultsBool(f.tick_to_hide, true);
|
66 |
|
67 | |
68 |
|
69 |
|
70 |
|
71 | this.manager = defaultsBool(f.manager, true);
|
72 |
|
73 | |
74 |
|
75 |
|
76 |
|
77 | this.headersTbl = f.headers_table || null;
|
78 |
|
79 | |
80 |
|
81 |
|
82 |
|
83 | this.headersIndex = defaultsNb(f.headers_index, 1);
|
84 |
|
85 | |
86 |
|
87 |
|
88 |
|
89 | this.contElTgtId = defaultsStr(f.container_target_id, null);
|
90 |
|
91 | |
92 |
|
93 |
|
94 |
|
95 | this.headersText = defaultsArr(f.headers_text, []);
|
96 |
|
97 | |
98 |
|
99 |
|
100 |
|
101 | this.btnTgtId = defaultsStr(f.btn_target_id, null);
|
102 |
|
103 | |
104 |
|
105 |
|
106 |
|
107 | this.btnText = defaultsStr(f.btn_text, 'Columns▼');
|
108 |
|
109 | |
110 |
|
111 |
|
112 |
|
113 | this.btnHtml = defaultsStr(f.btn_html, null);
|
114 |
|
115 | |
116 |
|
117 |
|
118 |
|
119 | this.btnCssClass = defaultsStr(f.btn_css_class, 'colVis');
|
120 |
|
121 | |
122 |
|
123 |
|
124 |
|
125 | this.btnCloseText = defaultsStr(f.btn_close_text, 'Close');
|
126 |
|
127 | |
128 |
|
129 |
|
130 |
|
131 | this.btnCloseHtml = defaultsStr(f.btn_close_html, null);
|
132 |
|
133 | |
134 |
|
135 |
|
136 |
|
137 | this.btnCloseCssClass = defaultsStr(f.btn_close_css_class,
|
138 | this.btnCssClass);
|
139 |
|
140 | |
141 |
|
142 |
|
143 |
|
144 | this.stylesheet = defaultsStr(f.stylesheet, 'colsVisibility.css');
|
145 |
|
146 | |
147 |
|
148 |
|
149 |
|
150 | this.spanCssClass = defaultsStr(f.span_css_class, 'colVisSpan');
|
151 |
|
152 | |
153 |
|
154 |
|
155 |
|
156 | this.contCssClass = defaultsStr(f.cont_css_class, 'colVisCont');
|
157 |
|
158 | |
159 |
|
160 |
|
161 |
|
162 | this.listCssClass = defaultsStr(cfg.list_css_class, 'cols_checklist');
|
163 |
|
164 | |
165 |
|
166 |
|
167 |
|
168 | this.listItemCssClass = defaultsStr(cfg.checklist_item_css_class,
|
169 | 'cols_checklist_item');
|
170 |
|
171 | |
172 |
|
173 |
|
174 |
|
175 | this.listSlcItemCssClass = defaultsStr(
|
176 | cfg.checklist_selected_item_css_class,
|
177 | 'cols_checklist_slc_item'
|
178 | );
|
179 |
|
180 | |
181 |
|
182 |
|
183 |
|
184 |
|
185 | this.text = defaultsStr(f.text, this.tickToHide ? 'Hide: ' : 'Show: ');
|
186 |
|
187 | |
188 |
|
189 |
|
190 |
|
191 | this.atStart = defaultsArr(f.at_start, []);
|
192 |
|
193 | |
194 |
|
195 |
|
196 |
|
197 | this.enableHover = Boolean(f.enable_hover);
|
198 |
|
199 | |
200 |
|
201 |
|
202 |
|
203 | this.enableTickAll = Boolean(f.enable_tick_all);
|
204 |
|
205 | |
206 |
|
207 |
|
208 |
|
209 | this.tickAllText = defaultsStr(f.tick_all_text, 'Select all:');
|
210 |
|
211 | |
212 |
|
213 |
|
214 |
|
215 | this.toolbarPosition = defaultsStr(f.toolbar_position, RIGHT);
|
216 |
|
217 | |
218 |
|
219 |
|
220 |
|
221 | this.hiddenCols = [];
|
222 |
|
223 | |
224 |
|
225 |
|
226 |
|
227 | this.boundMouseup = null;
|
228 |
|
229 | |
230 |
|
231 |
|
232 |
|
233 | this.onLoaded = defaultsFn(f.on_loaded, EMPTY_FN);
|
234 |
|
235 | |
236 |
|
237 |
|
238 |
|
239 | this.onBeforeOpen = defaultsFn(f.on_before_open, EMPTY_FN);
|
240 |
|
241 | |
242 |
|
243 |
|
244 |
|
245 | this.onAfterOpen = defaultsFn(f.on_after_open, EMPTY_FN);
|
246 |
|
247 | |
248 |
|
249 |
|
250 |
|
251 | this.onBeforeClose = defaultsFn(f.on_before_close, EMPTY_FN);
|
252 |
|
253 | |
254 |
|
255 |
|
256 |
|
257 | this.onAfterClose = defaultsFn(f.on_after_close, EMPTY_FN);
|
258 |
|
259 | |
260 |
|
261 |
|
262 |
|
263 | this.onBeforeColHidden = defaultsFn(f.on_before_col_hidden, EMPTY_FN);
|
264 |
|
265 | |
266 |
|
267 |
|
268 |
|
269 | this.onAfterColHidden = defaultsFn(f.on_after_col_hidden, EMPTY_FN);
|
270 |
|
271 | |
272 |
|
273 |
|
274 |
|
275 | this.onBeforeColDisplayed = defaultsFn(f.on_before_col_displayed,
|
276 | EMPTY_FN);
|
277 |
|
278 | |
279 |
|
280 |
|
281 |
|
282 | this.onAfterColDisplayed = defaultsFn(f.on_after_col_displayed,
|
283 | EMPTY_FN);
|
284 |
|
285 |
|
286 | if (tf.gridLayout) {
|
287 | this.headersTbl = tf.feature('gridLayout').headTbl;
|
288 | this.headersIndex = 0;
|
289 | }
|
290 |
|
291 |
|
292 | tf.import(f.name + 'Style', tf.getStylePath() + this.stylesheet, null,
|
293 | 'link');
|
294 |
|
295 | this.enable();
|
296 | }
|
297 |
|
298 | |
299 |
|
300 |
|
301 |
|
302 | onMouseup(evt) {
|
303 | let targetElm = targetEvt(evt);
|
304 |
|
305 | while (targetElm && targetElm !== this.contEl
|
306 | && targetElm !== this.btnEl) {
|
307 | targetElm = targetElm.parentNode;
|
308 | }
|
309 |
|
310 | if (targetElm !== this.contEl && targetElm !== this.btnEl) {
|
311 | this.toggle();
|
312 | }
|
313 |
|
314 | return;
|
315 | }
|
316 |
|
317 | |
318 |
|
319 |
|
320 | toggle() {
|
321 |
|
322 | removeEvt(root, 'mouseup', this.boundMouseup);
|
323 |
|
324 | let contDisplay = this.contEl.style.display;
|
325 |
|
326 | if (contDisplay !== 'inline') {
|
327 | this.onBeforeOpen(this);
|
328 | }
|
329 | if (contDisplay === 'inline') {
|
330 | this.onBeforeClose(this);
|
331 | }
|
332 |
|
333 | this.contEl.style.display = contDisplay === 'inline' ?
|
334 | NONE : 'inline';
|
335 |
|
336 | if (contDisplay !== 'inline') {
|
337 | this.onAfterOpen(this);
|
338 | addEvt(root, 'mouseup', this.boundMouseup);
|
339 | }
|
340 | if (contDisplay === 'inline') {
|
341 | this.onAfterClose(this);
|
342 | }
|
343 | }
|
344 |
|
345 | |
346 |
|
347 |
|
348 |
|
349 | checkItem(lbl) {
|
350 | let li = lbl.parentNode;
|
351 | if (!li || !lbl) {
|
352 | return;
|
353 | }
|
354 | let isChecked = lbl.firstChild.checked;
|
355 | let colIndex = lbl.firstChild.getAttribute('id').split('_')[1];
|
356 | colIndex = parseInt(colIndex, 10);
|
357 | if (isChecked) {
|
358 | addClass(li, this.listSlcItemCssClass);
|
359 | } else {
|
360 | removeClass(li, this.listSlcItemCssClass);
|
361 | }
|
362 |
|
363 | let hide = false;
|
364 | if ((this.tickToHide && isChecked) ||
|
365 | (!this.tickToHide && !isChecked)) {
|
366 | hide = true;
|
367 | }
|
368 | this.setHidden(colIndex, hide);
|
369 | }
|
370 |
|
371 | |
372 |
|
373 |
|
374 | init() {
|
375 | if (this.initialized || !this.manager) {
|
376 | return;
|
377 | }
|
378 |
|
379 | this.emitter.emit('initializing-extension', this,
|
380 | !isNull(this.btnTgtId));
|
381 |
|
382 | this.emitter.on(['hide-column'],
|
383 | (tf, colIndex) => this.hideCol(colIndex));
|
384 |
|
385 | this.buildBtn();
|
386 | this.buildManager();
|
387 |
|
388 |
|
389 | this.initialized = true;
|
390 |
|
391 | this.boundMouseup = this.onMouseup.bind(this);
|
392 |
|
393 | this.emitter.emit('columns-visibility-initialized', this.tf, this);
|
394 | this.emitter.emit('extension-initialized', this);
|
395 |
|
396 |
|
397 |
|
398 | this._hideAtStart();
|
399 | }
|
400 |
|
401 | |
402 |
|
403 |
|
404 | buildBtn() {
|
405 | if (this.btnEl) {
|
406 | return;
|
407 | }
|
408 | let tf = this.tf;
|
409 | let span = createElm('span');
|
410 | span.className = this.spanCssClass;
|
411 |
|
412 |
|
413 | let targetEl = !this.btnTgtId ?
|
414 | tf.feature('toolbar').container(this.toolbarPosition) :
|
415 | elm(this.btnTgtId);
|
416 |
|
417 | if (!this.btnTgtId) {
|
418 | let firstChild = targetEl.firstChild;
|
419 | firstChild.parentNode.insertBefore(span, firstChild);
|
420 | } else {
|
421 | targetEl.appendChild(span);
|
422 | }
|
423 |
|
424 | if (!this.btnHtml) {
|
425 | let btn = createElm('a', ['href', 'javascript:;']);
|
426 | btn.className = this.btnCssClass;
|
427 | btn.title = this.desc;
|
428 |
|
429 | btn.innerHTML = this.btnText;
|
430 | span.appendChild(btn);
|
431 | if (!this.enableHover) {
|
432 | addEvt(btn, 'click', (evt) => this.toggle(evt));
|
433 | } else {
|
434 | addEvt(btn, 'mouseover', (evt) => this.toggle(evt));
|
435 | }
|
436 | } else {
|
437 | span.innerHTML = this.btnHtml;
|
438 | let colVisEl = span.firstChild;
|
439 | if (!this.enableHover) {
|
440 | addEvt(colVisEl, 'click', (evt) => this.toggle(evt));
|
441 | } else {
|
442 | addEvt(colVisEl, 'mouseover', (evt) => this.toggle(evt));
|
443 | }
|
444 | }
|
445 |
|
446 | this.spanEl = span;
|
447 | this.btnEl = this.spanEl.firstChild;
|
448 |
|
449 | this.onLoaded(this);
|
450 | }
|
451 |
|
452 | |
453 |
|
454 |
|
455 | buildManager() {
|
456 | let tf = this.tf;
|
457 |
|
458 | let container = !this.contElTgtId ?
|
459 | createElm('div') :
|
460 | elm(this.contElTgtId);
|
461 | container.className = this.contCssClass;
|
462 |
|
463 |
|
464 | let extNameLabel = createElm('p');
|
465 | extNameLabel.innerHTML = this.text;
|
466 | container.appendChild(extNameLabel);
|
467 |
|
468 |
|
469 | let ul = createElm('ul');
|
470 | ul.className = this.listCssClass;
|
471 |
|
472 | let tbl = this.headersTbl || tf.dom();
|
473 | let headerIndex = this.headersTbl ?
|
474 | this.headersIndex : tf.getHeadersRowIndex();
|
475 | let headerRow = tbl.rows[headerIndex];
|
476 |
|
477 |
|
478 | if (this.enableTickAll) {
|
479 | let li = createCheckItem('col__' + tf.id, this.tickAllText,
|
480 | this.tickAllText);
|
481 | addClass(li, this.listItemCssClass);
|
482 | ul.appendChild(li);
|
483 | li.check.checked = !this.tickToHide;
|
484 |
|
485 | addEvt(li.check, 'click', () => {
|
486 | for (let h = 0; h < headerRow.cells.length; h++) {
|
487 | let itm = elm('col_' + h + '_' + tf.id);
|
488 | if (itm && li.check.checked !== itm.checked) {
|
489 | itm.click();
|
490 | itm.checked = li.check.checked;
|
491 | }
|
492 | }
|
493 | });
|
494 | }
|
495 |
|
496 | for (let i = 0; i < headerRow.cells.length; i++) {
|
497 | let cell = headerRow.cells[i];
|
498 | let cellText = this.headersText[i] || this._getHeaderText(cell);
|
499 | let liElm = createCheckItem('col_' + i + '_' + tf.id, cellText,
|
500 | cellText);
|
501 | addClass(liElm, this.listItemCssClass);
|
502 | if (!this.tickToHide) {
|
503 | addClass(liElm, this.listSlcItemCssClass);
|
504 | }
|
505 | ul.appendChild(liElm);
|
506 | if (!this.tickToHide) {
|
507 | liElm.check.checked = true;
|
508 | }
|
509 |
|
510 | addEvt(liElm.check, 'click', (evt) => {
|
511 | let elm = targetEvt(evt);
|
512 | let lbl = elm.parentNode;
|
513 | this.checkItem(lbl);
|
514 | });
|
515 | }
|
516 |
|
517 |
|
518 | let p = createElm('p', ['align', 'center']);
|
519 | let btn;
|
520 |
|
521 | if (!this.btnCloseHtml) {
|
522 | btn = createElm('a', ['href', 'javascript:;']);
|
523 | btn.className = this.btnCloseCssClass;
|
524 | btn.innerHTML = this.btnCloseText;
|
525 | addEvt(btn, 'click', (evt) => this.toggle(evt));
|
526 | p.appendChild(btn);
|
527 | } else {
|
528 | p.innerHTML = this.btnCloseHtml;
|
529 | btn = p.firstChild;
|
530 | addEvt(btn, 'click', (evt) => this.toggle(evt));
|
531 | }
|
532 |
|
533 | container.appendChild(ul);
|
534 | container.appendChild(p);
|
535 |
|
536 | this.btnEl.parentNode.insertBefore(container, this.btnEl);
|
537 | this.contEl = container;
|
538 | }
|
539 |
|
540 | |
541 |
|
542 |
|
543 |
|
544 |
|
545 | setHidden(colIndex, hide) {
|
546 | let tf = this.tf;
|
547 | let tbl = tf.dom();
|
548 |
|
549 | if (hide) {
|
550 | this.onBeforeColHidden(this, colIndex);
|
551 | } else {
|
552 | this.onBeforeColDisplayed(this, colIndex);
|
553 | }
|
554 |
|
555 | this._hideElements(tbl, colIndex, hide);
|
556 | if (this.headersTbl) {
|
557 | this._hideElements(this.headersTbl, colIndex, hide);
|
558 | }
|
559 |
|
560 | let hiddenCols = this.hiddenCols;
|
561 | let itemIndex = hiddenCols.indexOf(colIndex);
|
562 | if (hide) {
|
563 | if (itemIndex === -1) {
|
564 | this.hiddenCols.push(colIndex);
|
565 | }
|
566 | } else {
|
567 | if (itemIndex !== -1) {
|
568 | this.hiddenCols.splice(itemIndex, 1);
|
569 | }
|
570 | }
|
571 |
|
572 | if (hide) {
|
573 | this.onAfterColHidden(this, colIndex);
|
574 | this.emitter.emit('column-hidden', tf, this, colIndex,
|
575 | this.hiddenCols);
|
576 | } else {
|
577 | this.onAfterColDisplayed(this, colIndex);
|
578 | this.emitter.emit('column-shown', tf, this, colIndex,
|
579 | this.hiddenCols);
|
580 | }
|
581 | }
|
582 |
|
583 | |
584 |
|
585 |
|
586 |
|
587 | showCol(colIndex) {
|
588 | if (isUndef(colIndex) || !this.isColHidden(colIndex)) {
|
589 | return;
|
590 | }
|
591 | if (this.manager && this.contEl) {
|
592 | let itm = elm('col_' + colIndex + '_' + this.tf.id);
|
593 | if (itm) {
|
594 | itm.click();
|
595 | }
|
596 | } else {
|
597 | this.setHidden(colIndex, false);
|
598 | }
|
599 | }
|
600 |
|
601 | |
602 |
|
603 |
|
604 |
|
605 | hideCol(colIndex) {
|
606 | if (isUndef(colIndex) || this.isColHidden(colIndex)) {
|
607 | return;
|
608 | }
|
609 | if (this.manager && this.contEl) {
|
610 | let itm = elm('col_' + colIndex + '_' + this.tf.id);
|
611 | if (itm) {
|
612 | itm.click();
|
613 | }
|
614 | } else {
|
615 | this.setHidden(colIndex, true);
|
616 | }
|
617 | }
|
618 |
|
619 | |
620 |
|
621 |
|
622 |
|
623 | isColHidden(colIndex) {
|
624 | if (this.hiddenCols.indexOf(colIndex) !== -1) {
|
625 | return true;
|
626 | }
|
627 | return false;
|
628 | }
|
629 |
|
630 | |
631 |
|
632 |
|
633 |
|
634 | toggleCol(colIndex) {
|
635 | if (isUndef(colIndex) || this.isColHidden(colIndex)) {
|
636 | this.showCol(colIndex);
|
637 | } else {
|
638 | this.hideCol(colIndex);
|
639 | }
|
640 | }
|
641 |
|
642 | |
643 |
|
644 |
|
645 |
|
646 | getHiddenCols() {
|
647 | return this.hiddenCols;
|
648 | }
|
649 |
|
650 | |
651 |
|
652 |
|
653 | destroy() {
|
654 | if (!this.initialized) {
|
655 | return;
|
656 | }
|
657 | if (elm(this.contElTgtId)) {
|
658 | elm(this.contElTgtId).innerHTML = '';
|
659 | } else {
|
660 | this.contEl.innerHTML = '';
|
661 | removeElm(this.contEl);
|
662 | this.contEl = null;
|
663 | }
|
664 | this.btnEl.innerHTML = '';
|
665 | removeElm(this.btnEl);
|
666 | this.btnEl = null;
|
667 |
|
668 | this.emitter.off(['hide-column'],
|
669 | (tf, colIndex) => this.hideCol(colIndex));
|
670 |
|
671 | this.boundMouseup = null;
|
672 |
|
673 | this.initialized = false;
|
674 | }
|
675 |
|
676 | _getHeaderText(cell) {
|
677 | if (!cell.hasChildNodes) {
|
678 | return '';
|
679 | }
|
680 |
|
681 | for (let i = 0; i < cell.childNodes.length; i++) {
|
682 | let n = cell.childNodes[i];
|
683 | if (n.nodeType === 3) {
|
684 | return n.nodeValue;
|
685 | } else if (n.nodeType === 1) {
|
686 | if (n.id && n.id.indexOf('popUp') !== -1) {
|
687 | continue;
|
688 | } else {
|
689 | return getText(n);
|
690 | }
|
691 | }
|
692 | continue;
|
693 | }
|
694 | return '';
|
695 | }
|
696 |
|
697 | _hideElements(tbl, colIdx, hide) {
|
698 | this._hideCells(tbl, colIdx, hide);
|
699 | this._hideCol(tbl, colIdx, hide);
|
700 | }
|
701 |
|
702 | _hideCells(tbl, colIdx, hide) {
|
703 | for (let i = 0; i < tbl.rows.length; i++) {
|
704 | let row = tbl.rows[i];
|
705 | let cell = row.cells[colIdx];
|
706 | if (cell) {
|
707 | cell.style.display = hide ? NONE : '';
|
708 | }
|
709 | }
|
710 | }
|
711 |
|
712 | _hideCol(tbl, colIdx, hide) {
|
713 | let colElms = tag(tbl, 'col');
|
714 | if (colElms.length === 0) {
|
715 | return;
|
716 | }
|
717 | colElms[colIdx].style.display = hide ? NONE : '';
|
718 | }
|
719 |
|
720 | _hideAtStart() {
|
721 | this.atStart.forEach((colIdx) => {
|
722 | this.hideCol(colIdx);
|
723 | });
|
724 | }
|
725 | }
|