1
0
Fork 0
mirror of https://github.com/koalyptus/TableFilter.git synced 2024-06-03 06:22:34 +02:00
TableFilter/src/modules/popupFilter.js

365 lines
10 KiB
JavaScript
Raw Normal View History

import {Feature} from '../feature';
2016-05-15 04:56:12 +02:00
import {isFn} from '../types';
2016-05-24 10:42:11 +02:00
import {createElm, removeElm} from '../dom';
2016-06-02 06:13:56 +02:00
import {addEvt, cancelEvt, stopEvt, targetEvt} from '../event';
import {INPUT, NONE} from '../const';
2015-02-15 09:55:23 +01:00
/**
* Pop-up filter component
* @export
* @class PopupFilter
* @extends {Feature}
*/
2016-05-24 10:42:11 +02:00
export class PopupFilter extends Feature {
2015-02-15 09:55:23 +01:00
/**
* Creates an instance of PopupFilter
* @param {TableFilter} tf TableFilter instance
2015-02-15 09:55:23 +01:00
*/
2016-05-24 10:42:11 +02:00
constructor(tf) {
super(tf, 'popupFilters');
2015-02-15 09:55:23 +01:00
// Configuration object
2016-05-24 10:42:11 +02:00
let f = this.config;
2015-02-15 09:55:23 +01:00
// Enable external filters
2015-02-15 09:55:23 +01:00
tf.isExternalFlt = true;
tf.externalFltTgtIds = [];
/**
* Filter icon path
* @type {String}
*/
2016-08-04 08:11:19 +02:00
this.iconPath = f.popup_filters_image ||
2016-05-24 10:42:11 +02:00
tf.themesPath + 'icn_filter.gif';
/**
* Active filter icon path
* @type {string}
*/
2016-08-04 08:11:19 +02:00
this.activeIconPath = f.popup_filters_image_active ||
2016-05-24 10:42:11 +02:00
tf.themesPath + 'icn_filterActive.gif';
/**
* HTML for the filter icon
* @type {string}
*/
2016-08-04 08:11:19 +02:00
this.iconHtml = f.popup_filters_image_html ||
'<img src="' + this.iconPath + '" alt="Column filter" />';
/**
* Css class assigned to filter container element
* @type {String}
*/
2016-08-04 08:11:19 +02:00
this.containerCssClass = f.popup_div_css_class || 'popUpFilter';
/**
* Callback fired before a popup filter is opened
* @type {Function}
*/
2016-08-04 08:11:19 +02:00
this.onBeforeOpen = isFn(f.on_before_popup_filter_open) ?
2015-02-15 09:55:23 +01:00
f.on_before_popup_filter_open : null;
/**
* Callback fired after a popup filter is opened
* @type {Function}
*/
2016-08-04 08:11:19 +02:00
this.onAfterOpen = isFn(f.on_after_popup_filter_open) ?
2015-02-15 09:55:23 +01:00
f.on_after_popup_filter_open : null;
/**
* Callback fired before a popup filter is closed
* @type {Function}
*/
2016-08-04 08:11:19 +02:00
this.onBeforeClose = isFn(f.on_before_popup_filter_close) ?
2015-02-15 09:55:23 +01:00
f.on_before_popup_filter_close : null;
/**
* Callback fired after a popup filter is closed
* @type {Function}
*/
2016-08-04 08:11:19 +02:00
this.onAfterClose = isFn(f.on_after_popup_filter_close) ?
2015-02-15 09:55:23 +01:00
f.on_after_popup_filter_close : null;
/**
* Collection of filters spans
* @type {Array}
* @private
*/
2016-08-04 08:11:19 +02:00
this.fltSpans = [];
/**
* Collection of filters icons
* @type {Array}
* @private
*/
2016-08-04 08:11:19 +02:00
this.fltIcons = [];
/**
* Collection of filters icons cached after pop-up filters are removed
* @type {Array}
* @private
*/
2016-08-04 08:11:19 +02:00
this.filtersCache = null;
/**
* Collection of filters containers
* @type {Array}
* @private
*/
2016-08-04 08:11:19 +02:00
this.fltElms = this.filtersCache || [];
/**
* Ensure filter's container element width matches column width
* @type {Boolean}
*/
2016-08-04 08:11:19 +02:00
this.adjustToContainer = true;
2015-02-15 09:55:23 +01:00
/**
* Prefix for pop-up filter container ID
* @type {String}
* @private
*/
2016-08-04 08:11:19 +02:00
this.prfxDiv = 'popUpDiv_';
2015-02-15 09:55:23 +01:00
}
/**
* Click event handler for pop-up filter icon
* @private
*/
2016-05-24 10:42:11 +02:00
onClick(evt) {
2016-06-02 06:13:56 +02:00
let elm = targetEvt(evt).parentNode,
2015-02-15 09:55:23 +01:00
colIndex = parseInt(elm.getAttribute('ci'), 10);
this.closeAll(colIndex);
this.toggle(colIndex);
2016-08-04 08:11:19 +02:00
if (this.adjustToContainer) {
let popUpDiv = this.fltElms[colIndex],
header = this.tf.getHeaderElement(colIndex),
2015-02-15 09:55:23 +01:00
headerWidth = header.clientWidth * 0.95;
2016-02-16 08:41:47 +01:00
popUpDiv.style.width = parseInt(headerWidth, 10) + 'px';
2015-02-15 09:55:23 +01:00
}
2016-06-02 06:13:56 +02:00
cancelEvt(evt);
stopEvt(evt);
2015-02-15 09:55:23 +01:00
}
/**
* Initialize DOM elements
*/
2016-05-24 10:42:11 +02:00
init() {
if (this.initialized) {
return;
}
2016-05-24 10:42:11 +02:00
let tf = this.tf;
2016-01-04 07:59:30 +01:00
// Override headers row index if no grouped headers
// TODO: Because of the filters row generation, headers row index needs
// adjusting: prevent useless row generation
2016-09-20 05:40:38 +02:00
if (tf.headersRow <= 1 && isNaN(tf.config().headers_row_index)) {
2016-01-04 07:59:30 +01:00
tf.headersRow = 0;
}
2016-09-20 05:40:38 +02:00
// Adjust headers row index for grid-layout mode
// TODO: Because of the filters row generation, headers row index needs
// adjusting: prevent useless row generation
2016-09-20 05:40:38 +02:00
if (tf.gridLayout) {
tf.headersRow--;
this.buildIcons();
2015-02-15 09:55:23 +01:00
}
// subscribe to events
2016-09-20 05:40:38 +02:00
this.emitter.on(['before-filtering'], () => this.setIconsState());
2016-05-24 10:42:11 +02:00
this.emitter.on(['after-filtering'], () => this.closeAll());
2016-01-03 03:49:04 +01:00
this.emitter.on(['cell-processed'],
2016-09-20 05:40:38 +02:00
(tf, cellIndex) => this.changeState(cellIndex, true));
this.emitter.on(['filters-row-inserted'], () => this.buildIcons());
this.emitter.on(['before-filter-init'],
2016-05-24 10:42:11 +02:00
(tf, colIndex) => this.build(colIndex));
/**
* @inherited
*/
this.initialized = true;
}
/**
* Reset previously destroyed feature
*/
2016-05-24 10:42:11 +02:00
reset() {
this.enable();
this.init();
this.buildAll();
2015-02-15 09:55:23 +01:00
}
2016-09-20 05:40:38 +02:00
/**
* Build all filters icons
*/
buildIcons() {
let tf = this.tf;
// TODO: Because of the filters row generation, headers row index needs
// adjusting: prevent useless row generation
2016-09-20 05:40:38 +02:00
tf.headersRow++;
for (let i = 0; i < tf.nbCells; i++) {
if (tf.getFilterType(i) === NONE) {
continue;
}
let popUpSpan = createElm('span', ['ci', i]);
2016-09-20 05:40:38 +02:00
popUpSpan.innerHTML = this.iconHtml;
let header = tf.getHeaderElement(i);
header.appendChild(popUpSpan);
addEvt(popUpSpan, 'click', (evt) => this.onClick(evt));
this.fltSpans[i] = popUpSpan;
this.fltIcons[i] = popUpSpan.firstChild;
}
}
/**
* Build all pop-up filters elements
*/
2016-05-24 10:42:11 +02:00
buildAll() {
2016-08-04 08:11:19 +02:00
for (let i = 0; i < this.filtersCache.length; i++) {
this.build(i, this.filtersCache[i]);
2015-02-15 09:55:23 +01:00
}
}
/**
* Build a specified pop-up filter elements
* @param {Number} colIndex Column index
* @param {Object} div Optional container DOM element
*/
2016-05-24 10:42:11 +02:00
build(colIndex, div) {
let tf = this.tf;
let popUpDiv = div ||
createElm('div', ['id', this.prfxDiv + tf.id + '_' + colIndex]);
2016-08-04 08:11:19 +02:00
popUpDiv.className = this.containerCssClass;
2015-02-15 09:55:23 +01:00
tf.externalFltTgtIds.push(popUpDiv.id);
2016-05-24 10:42:11 +02:00
let header = tf.getHeaderElement(colIndex);
2015-02-15 09:55:23 +01:00
header.insertBefore(popUpDiv, header.firstChild);
2016-06-02 06:13:56 +02:00
addEvt(popUpDiv, 'click', (evt) => stopEvt(evt));
2016-08-04 08:11:19 +02:00
this.fltElms[colIndex] = popUpDiv;
2015-02-15 09:55:23 +01:00
}
/**
* Toogle visibility of specified filter
* @param {Number} colIndex Column index
*/
2016-05-24 10:42:11 +02:00
toggle(colIndex) {
let tf = this.tf,
2016-08-04 08:11:19 +02:00
popUpFltElm = this.fltElms[colIndex];
2016-05-24 10:42:11 +02:00
if (popUpFltElm.style.display === NONE ||
popUpFltElm.style.display === '') {
2016-08-04 08:11:19 +02:00
if (this.onBeforeOpen) {
this.onBeforeOpen.call(
null, this, this.fltElms[colIndex], colIndex);
2015-02-15 09:55:23 +01:00
}
popUpFltElm.style.display = 'block';
2016-05-24 10:42:11 +02:00
if (tf.getFilterType(colIndex) === INPUT) {
let flt = tf.getFilterElement(colIndex);
if (flt) {
flt.focus();
}
2015-02-15 09:55:23 +01:00
}
2016-08-04 08:11:19 +02:00
if (this.onAfterOpen) {
this.onAfterOpen.call(
null, this, this.fltElms[colIndex], colIndex);
2015-02-15 09:55:23 +01:00
}
} else {
2016-08-04 08:11:19 +02:00
if (this.onBeforeClose) {
this.onBeforeClose.call(
null, this, this.fltElms[colIndex], colIndex);
2015-02-15 09:55:23 +01:00
}
popUpFltElm.style.display = NONE;
2016-08-04 08:11:19 +02:00
if (this.onAfterClose) {
this.onAfterClose.call(
null, this, this.fltElms[colIndex], colIndex);
2015-02-15 09:55:23 +01:00
}
}
}
/**
* Close all filters excepted for the specified one if any
* @param {Number} exceptIdx Column index of the filter to not close
*/
2016-05-24 10:42:11 +02:00
closeAll(exceptIdx) {
2016-08-04 08:11:19 +02:00
for (let i = 0; i < this.fltElms.length; i++) {
2016-05-24 10:42:11 +02:00
if (i === exceptIdx) {
2015-02-15 09:55:23 +01:00
continue;
}
2016-08-04 08:11:19 +02:00
let popUpFltElm = this.fltElms[i];
2016-05-24 10:42:11 +02:00
if (popUpFltElm) {
popUpFltElm.style.display = NONE;
2015-02-15 09:55:23 +01:00
}
}
}
/**
* Build all the icons representing the pop-up filters
*/
2016-09-20 05:40:38 +02:00
setIconsState() {
2016-08-04 08:11:19 +02:00
for (let i = 0; i < this.fltIcons.length; i++) {
2016-09-20 05:40:38 +02:00
this.changeState(i, false);
2015-02-15 09:55:23 +01:00
}
}
/**
* Apply specified icon state
* @param {Number} colIndex Column index
* @param {Boolean} active Apply active state
*/
2016-09-20 05:40:38 +02:00
changeState(colIndex, active) {
2016-08-04 08:11:19 +02:00
if (this.fltIcons[colIndex]) {
this.fltIcons[colIndex].src = active ?
this.activeIconPath : this.iconPath;
2015-02-15 09:55:23 +01:00
}
}
/**
* Remove pop-up filters
*/
2016-05-24 10:42:11 +02:00
destroy() {
if (!this.initialized) {
return;
}
2016-08-04 08:11:19 +02:00
this.filtersCache = [];
for (let i = 0; i < this.fltElms.length; i++) {
let popUpFltElm = this.fltElms[i],
popUpFltSpan = this.fltSpans[i],
popUpFltImg = this.fltIcons[i];
2016-05-24 10:42:11 +02:00
if (popUpFltElm) {
removeElm(popUpFltElm);
2016-08-04 08:11:19 +02:00
this.filtersCache[i] = popUpFltElm;
2015-02-15 09:55:23 +01:00
}
popUpFltElm = null;
2016-05-24 10:42:11 +02:00
if (popUpFltSpan) {
removeElm(popUpFltSpan);
2015-02-15 09:55:23 +01:00
}
popUpFltSpan = null;
2016-05-24 10:42:11 +02:00
if (popUpFltImg) {
removeElm(popUpFltImg);
2015-02-17 12:17:17 +01:00
}
popUpFltImg = null;
2015-02-15 09:55:23 +01:00
}
2016-08-04 08:11:19 +02:00
this.fltElms = [];
this.fltSpans = [];
this.fltIcons = [];
// unsubscribe to events
2016-09-20 05:40:38 +02:00
this.emitter.off(['before-filtering'], () => this.setIconsState());
2016-05-24 10:42:11 +02:00
this.emitter.off(['after-filtering'], () => this.closeAll());
2016-01-03 03:49:04 +01:00
this.emitter.off(['cell-processed'],
2016-09-20 05:40:38 +02:00
(tf, cellIndex) => this.changeState(cellIndex, true));
this.emitter.off(['filters-row-inserted'], () => this.buildIcons());
this.emitter.off(['before-filter-init'],
2016-05-24 10:42:11 +02:00
(tf, colIndex) => this.build(colIndex));
this.initialized = false;
2015-02-15 09:55:23 +01:00
}
2015-02-17 12:17:17 +01:00
2015-02-15 09:55:23 +01:00
}