1
0
Fork 0
mirror of https://github.com/koalyptus/TableFilter.git synced 2024-05-13 11:56:46 +02:00
TableFilter/src/modules/gridLayout.js

447 lines
13 KiB
JavaScript
Raw Normal View History

import {Feature} from '../feature';
2016-05-25 09:31:53 +02:00
import {createElm, removeElm, elm, tag} from '../dom';
2016-06-05 10:44:21 +02:00
import {isNull} from '../types';
2016-06-02 06:13:56 +02:00
import {addEvt, targetEvt} from '../event';
2016-05-20 10:08:39 +02:00
import {contains} from '../string';
import {NONE} from '../const';
2014-11-22 15:01:29 +01:00
2016-06-05 10:44:21 +02:00
/**
* Grid layout, table with fixed headers
*/
2016-05-15 05:33:16 +02:00
export class GridLayout extends Feature {
2014-11-22 15:01:29 +01:00
2014-11-23 11:31:55 +01:00
/**
2016-06-05 10:44:21 +02:00
* Creates an instance of GridLayout
2014-11-23 11:31:55 +01:00
* @param {Object} tf TableFilter instance
*/
2016-05-15 05:33:16 +02:00
constructor(tf) {
super(tf, 'gridLayout');
2016-01-04 07:59:30 +01:00
let f = this.config;
2014-11-22 15:01:29 +01:00
2016-06-13 11:17:13 +02:00
/**
* Grid-layout container width as CSS string
* @type {String}
*/
2016-06-05 10:44:21 +02:00
this.width = f.grid_width || null;
2016-06-13 11:17:13 +02:00
/**
* Grid-layout container height as CSS string
* @type {String}
*/
2016-06-05 10:44:21 +02:00
this.height = f.grid_height || null;
2016-06-13 11:17:13 +02:00
/**
* Css class for main container element
* @type {String}
*/
2016-06-05 10:44:21 +02:00
this.mainContCssClass = f.grid_cont_css_class || 'grd_Cont';
2016-06-13 11:17:13 +02:00
/**
* Css class for body table container element
* @type {String}
*/
2016-06-05 10:44:21 +02:00
this.contCssClass = f.grid_tbl_cont_css_class || 'grd_tblCont';
2016-06-13 11:17:13 +02:00
/**
* Css class for headers table container element
* @type {String}
*/
2016-06-05 10:44:21 +02:00
this.headContCssClass = f.grid_tblHead_cont_css_class ||
2014-11-22 15:01:29 +01:00
'grd_headTblCont';
2016-06-13 11:17:13 +02:00
/**
* Css class for toolbar container element (rows counter, paging etc.)
* @type {String}
*/
2016-06-05 10:44:21 +02:00
this.infDivCssClass = f.grid_inf_grid_css_class || 'grd_inf';
2016-06-13 11:17:13 +02:00
/**
* Index of the headers row, default: 0
* @type {Number}
*/
2016-06-05 10:44:21 +02:00
this.headRowIndex = f.grid_headers_row_index || 0;
2016-06-13 11:17:13 +02:00
/**
* Collection of the header row indexes to be moved into headers table
* @type {Array}
*/
2016-06-05 10:44:21 +02:00
this.headRows = f.grid_headers_rows || [0];
2016-06-13 11:17:13 +02:00
/**
* Enable or disable column filters generation, default: true
* @type {Boolean}
*/
2016-06-05 10:44:21 +02:00
this.enableFilters = f.grid_enable_default_filters === false ?
false : true;
2016-06-13 11:17:13 +02:00
/**
* Enable or disable column headers, default: false
* @type {Boolean}
*/
2016-03-06 11:24:29 +01:00
this.noHeaders = Boolean(f.grid_no_headers);
2016-06-13 11:17:13 +02:00
/**
* Grid-layout default column widht as CSS string
* @type {String}
*/
2016-06-05 10:44:21 +02:00
this.defaultColWidth = f.grid_default_col_width || '100px';
2014-11-22 15:01:29 +01:00
2016-06-13 11:17:13 +02:00
/**
* List of column elements
* @type {Array}
* @private
*/
2016-06-05 10:44:21 +02:00
this.colElms = [];
2014-11-23 11:31:55 +01:00
2016-06-13 11:17:13 +02:00
/**
* Prefix for grid-layout main container ID
* @type {String}
* @private
*/
this.prfxMainTblCont = 'gridCont_';
2016-06-13 11:17:13 +02:00
/**
* Prefix for grid-layout body table container ID
* @type {String}
* @private
*/
this.prfxTblCont = 'tblCont_';
2016-06-13 11:17:13 +02:00
/**
* Prefix for grid-layout headers table container ID
* @type {String}
* @private
*/
this.prfxHeadTblCont = 'tblHeadCont_';
2016-06-13 11:17:13 +02:00
/**
* Prefix for grid-layout headers table ID
* @type {String}
* @private
*/
this.prfxHeadTbl = 'tblHead_';
2016-06-13 11:17:13 +02:00
/**
* Prefix for grid-layout filter's cell ID
* @type {String}
* @private
*/
this.prfxGridFltTd = '_td_';
2016-06-13 11:17:13 +02:00
/**
* Prefix for grid-layout header's cell ID
* @type {String}
* @private
*/
this.prfxGridTh = 'tblHeadTh_';
2016-06-13 11:17:13 +02:00
/**
* Mark-up of original HTML table
* @type {String}
* @private
*/
this.sourceTblHtml = tf.tbl.outerHTML;
// filters flag at TF level
2016-06-05 10:44:21 +02:00
tf.fltGrid = this.enableFilters;
2014-11-22 15:01:29 +01:00
}
2014-11-23 11:31:55 +01:00
/**
* Generates a grid with fixed headers
2016-06-05 10:44:21 +02:00
*
* TODO: reduce size of init by extracting single purposed methods
2014-11-23 11:31:55 +01:00
*/
2016-05-15 05:33:16 +02:00
init() {
2016-01-04 07:59:30 +01:00
let tf = this.tf;
let f = this.config;
let tbl = tf.tbl;
2014-11-22 15:01:29 +01:00
2016-05-15 05:33:16 +02:00
if (this.initialized) {
2014-11-23 11:31:55 +01:00
return;
}
2016-01-04 07:59:30 +01:00
// Override reference rows indexes
2016-05-15 04:56:12 +02:00
tf.refRow = isNull(tf.startRow) ? 0 : tf.startRow;
2016-01-04 07:59:30 +01:00
tf.headersRow = 0;
tf.filtersRowIndex = 1;
2014-11-22 15:01:29 +01:00
tf.isExternalFlt = true;
2016-06-13 11:17:13 +02:00
// Assign default column widths
2016-06-13 04:49:27 +02:00
this.setDefaultColWidths();
2014-11-22 15:01:29 +01:00
2016-07-02 12:25:23 +02:00
// Initial table width
let tblW = this.initialTableWidth();
// if (tbl.width !== '') {
// tblW = tbl.width;
// }
// else if (tbl.style.width !== '') {
// tblW = parseInt(tbl.style.width, 10);
// } else {
// tblW = tbl.clientWidth;
// }
2014-11-22 15:01:29 +01:00
//Main container: it will contain all the elements
2016-05-24 10:42:11 +02:00
this.tblMainCont = createElm('div',
['id', this.prfxMainTblCont + tf.id]);
2016-06-05 10:44:21 +02:00
this.tblMainCont.className = this.mainContCssClass;
if (this.width) {
this.tblMainCont.style.width = this.width;
}
2014-11-23 04:34:57 +01:00
tbl.parentNode.insertBefore(this.tblMainCont, tbl);
2014-11-22 15:01:29 +01:00
//Table container: div wrapping content table
2016-05-24 10:42:11 +02:00
this.tblCont = createElm('div', ['id', this.prfxTblCont + tf.id]);
2016-06-05 10:44:21 +02:00
this.tblCont.className = this.contCssClass;
if (this.width) {
if (this.width.indexOf('%') !== -1) {
this.tblCont.style.width = '100%';
} else {
2016-06-05 10:44:21 +02:00
this.tblCont.style.width = this.width;
}
2014-11-22 15:01:29 +01:00
}
2016-06-05 10:44:21 +02:00
if (this.height) {
this.tblCont.style.height = this.height;
2014-11-22 15:01:29 +01:00
}
2014-11-23 04:34:57 +01:00
tbl.parentNode.insertBefore(this.tblCont, tbl);
2016-05-24 10:42:11 +02:00
let t = removeElm(tbl);
2014-11-22 15:01:29 +01:00
this.tblCont.appendChild(t);
//In case table width is expressed in %
2016-05-15 05:33:16 +02:00
if (tbl.style.width === '') {
2016-05-20 10:08:39 +02:00
tbl.style.width = (contains('%', tblW) ?
2014-11-22 15:01:29 +01:00
tbl.clientWidth : tblW) + 'px';
}
2016-05-24 10:42:11 +02:00
let d = removeElm(this.tblCont);
2014-11-22 15:01:29 +01:00
this.tblMainCont.appendChild(d);
//Headers table container: div wrapping headers table
2016-05-24 10:42:11 +02:00
this.headTblCont = createElm(
2016-05-15 05:33:16 +02:00
'div', ['id', this.prfxHeadTblCont + tf.id]);
2016-06-05 10:44:21 +02:00
this.headTblCont.className = this.headContCssClass;
if (this.width) {
if (this.width.indexOf('%') !== -1) {
this.headTblCont.style.width = '100%';
} else {
2016-06-05 10:44:21 +02:00
this.headTblCont.style.width = this.width;
}
2014-11-22 15:01:29 +01:00
}
//Headers table
2016-05-24 10:42:11 +02:00
this.headTbl = createElm('table', ['id', this.prfxHeadTbl + tf.id]);
let tH = createElm('tHead');
2014-11-22 15:01:29 +01:00
//1st row should be headers row, ids are added if not set
//Those ids are used by the sort feature
2016-06-05 10:44:21 +02:00
let hRow = tbl.rows[this.headRowIndex];
2016-01-04 07:59:30 +01:00
let sortTriggers = [];
2016-05-15 05:33:16 +02:00
for (let n = 0; n < tf.nbCells; n++) {
2016-01-04 07:59:30 +01:00
let c = hRow.cells[n];
let thId = c.getAttribute('id');
2016-05-15 05:33:16 +02:00
if (!thId || thId === '') {
thId = this.prfxGridTh + n + '_' + tf.id;
2014-11-22 15:01:29 +01:00
c.setAttribute('id', thId);
}
sortTriggers.push(thId);
}
//Filters row is created
2016-05-24 10:42:11 +02:00
let filtersRow = createElm('tr');
2016-06-05 10:44:21 +02:00
if (this.enableFilters && tf.fltGrid) {
2014-11-22 15:01:29 +01:00
tf.externalFltTgtIds = [];
2016-05-15 05:33:16 +02:00
for (let j = 0; j < tf.nbCells; j++) {
let fltTdId = tf.prfxFlt + j + this.prfxGridFltTd + tf.id;
2016-05-24 10:42:11 +02:00
let cl = createElm(tf.fltCellTag, ['id', fltTdId]);
2014-11-22 15:01:29 +01:00
filtersRow.appendChild(cl);
tf.externalFltTgtIds[j] = fltTdId;
}
}
2016-03-06 11:24:29 +01:00
2014-11-22 15:01:29 +01:00
//Headers row are moved from content table to headers table
2016-05-15 05:33:16 +02:00
if (!this.noHeaders) {
2016-06-05 10:44:21 +02:00
for (let i = 0; i < this.headRows.length; i++) {
2016-06-13 11:17:13 +02:00
let headRow = tbl.rows[this.headRows[i]];
2016-03-06 11:24:29 +01:00
tH.appendChild(headRow);
}
} else {
// Handle table with no headers, assuming here headers do not
// exist
2016-05-24 10:42:11 +02:00
tH.appendChild(createElm('tr'));
2014-11-22 15:01:29 +01:00
}
2016-03-06 11:24:29 +01:00
2014-11-22 15:01:29 +01:00
this.headTbl.appendChild(tH);
2016-05-15 05:33:16 +02:00
if (tf.filtersRowIndex === 0) {
2016-01-04 07:59:30 +01:00
tH.insertBefore(filtersRow, hRow);
2014-11-22 15:01:29 +01:00
} else {
tH.appendChild(filtersRow);
}
this.headTblCont.appendChild(this.headTbl);
this.tblCont.parentNode.insertBefore(this.headTblCont, this.tblCont);
//THead needs to be removed in content table for sort feature
2016-05-24 10:42:11 +02:00
let thead = tag(tbl, 'thead');
2016-05-15 05:33:16 +02:00
if (thead.length > 0) {
2014-11-22 15:01:29 +01:00
tbl.removeChild(thead[0]);
}
//Headers table style
this.headTbl.style.tableLayout = 'fixed';
tbl.style.tableLayout = 'fixed';
this.headTbl.cellPadding = tbl.cellPadding;
this.headTbl.cellSpacing = tbl.cellSpacing;
2015-04-24 12:38:20 +02:00
// this.headTbl.style.width = tbl.style.width;
2014-11-22 15:01:29 +01:00
//content table without headers needs col widths to be reset
tf.setColWidths(this.headTbl);
2014-11-22 15:01:29 +01:00
2014-11-23 11:31:55 +01:00
//Headers container width
// this.headTblCont.style.width = this.tblCont.clientWidth+'px';
2014-11-23 11:31:55 +01:00
2014-11-22 15:01:29 +01:00
tbl.style.width = '';
2015-04-24 12:38:20 +02:00
//
this.headTbl.style.width = tbl.clientWidth + 'px';
//
2014-11-22 15:01:29 +01:00
//scroll synchronisation
2016-06-02 06:13:56 +02:00
addEvt(this.tblCont, 'scroll', (evt) => {
let elm = targetEvt(evt);
2016-01-04 07:59:30 +01:00
let scrollLeft = elm.scrollLeft;
2015-04-24 12:38:20 +02:00
this.headTblCont.scrollLeft = scrollLeft;
2014-11-22 15:01:29 +01:00
//New pointerX calc taking into account scrollLeft
2015-04-24 12:38:20 +02:00
// if(!o.isPointerXOverwritten){
// try{
// o.Evt.pointerX = function(evt){
2016-01-04 07:59:30 +01:00
// let e = evt || global.event;
// let bdScrollLeft = tf_StandardBody().scrollLeft +
2015-04-24 12:38:20 +02:00
// scrollLeft;
// return (e.pageX + scrollLeft) ||
// (e.clientX + bdScrollLeft);
// };
// o.isPointerXOverwritten = true;
// } catch(err) {
// o.isPointerXOverwritten = false;
// }
// }
2014-11-22 15:01:29 +01:00
});
//Configure sort extension if any
2016-05-15 05:33:16 +02:00
let sort = (f.extensions || []).filter(function (itm) {
return itm.name === 'sort';
});
2016-05-15 05:33:16 +02:00
if (sort.length === 1) {
sort[0].async_sort = true;
sort[0].trigger_ids = sortTriggers;
2014-11-22 15:01:29 +01:00
}
//Cols generation for all browsers excepted IE<=7
2016-05-24 10:42:11 +02:00
this.tblHasColTag = tag(tbl, 'col').length > 0 ? true : false;
2014-11-23 11:31:55 +01:00
2015-01-11 11:22:52 +01:00
//Col elements are enough to keep column widths after sorting and
//filtering
2016-05-15 05:33:16 +02:00
let createColTags = function () {
for (let k = (tf.nbCells - 1); k >= 0; k--) {
2016-05-24 10:42:11 +02:00
let col = createElm('col', ['id', tf.id + '_col_' + k]);
2015-06-06 12:06:15 +02:00
tbl.insertBefore(col, tbl.firstChild);
2015-05-28 15:44:23 +02:00
col.style.width = tf.colWidths[k];
2016-06-05 10:44:21 +02:00
this.colElms[k] = col;
2015-01-11 11:22:52 +01:00
}
2015-06-06 12:06:15 +02:00
this.tblHasColTag = true;
2015-01-11 11:22:52 +01:00
};
2015-06-06 12:06:15 +02:00
2016-05-15 05:33:16 +02:00
if (!this.tblHasColTag) {
2015-06-06 12:06:15 +02:00
createColTags.call(this);
2015-01-11 11:22:52 +01:00
} else {
2016-05-24 10:42:11 +02:00
let cols = tag(tbl, 'col');
2016-05-15 05:33:16 +02:00
for (let ii = 0; ii < tf.nbCells; ii++) {
cols[ii].setAttribute('id', tf.id + '_col_' + ii);
2015-05-28 15:44:23 +02:00
cols[ii].style.width = tf.colWidths[ii];
2016-06-05 10:44:21 +02:00
this.colElms.push(cols[ii]);
2015-01-11 11:22:52 +01:00
}
}
2014-11-22 15:01:29 +01:00
2016-05-15 05:33:16 +02:00
if (tf.popupFilters) {
filtersRow.style.display = NONE;
}
2016-05-15 05:33:16 +02:00
if (tbl.clientWidth !== this.headTbl.clientWidth) {
tbl.style.width = this.headTbl.clientWidth + 'px';
2014-11-22 15:01:29 +01:00
}
this.initialized = true;
2014-11-22 15:01:29 +01:00
}
2016-06-13 11:17:13 +02:00
/**
* Set grid-layout default column widths if column widths are not defined
* @private
*/
setDefaultColWidths() {
2016-06-13 04:49:27 +02:00
let tf = this.tf;
2016-06-13 11:17:13 +02:00
if (tf.hasColWidths) {
2016-06-13 04:49:27 +02:00
return;
}
for (let k = 0, len = tf.getCellsNb(); k < len; k++) {
let colW;
let cell = tf.tbl.rows[tf.getHeadersRowIndex()].cells[k];
if (cell.width !== '') {
colW = cell.width;
} else if (cell.style.width !== '') {
colW = parseInt(cell.style.width, 10);
} else {
colW = this.defaultColWidth;
}
tf.colWidths[k] = colW;
}
tf.hasColWidths = true;
tf.setColWidths();
}
2016-07-02 12:25:23 +02:00
/**
* Initial table width
* @returns {Number}
* @private
*/
initialTableWidth() {
let tbl = this.tf.tbl;
let width; //initial table width
if (tbl.width !== '') {
width = tbl.width;
}
else if (tbl.style.width !== '') {
width = tbl.style.width;
} else {
width = tbl.clientWidth;
}
return parseInt(width, 10);
}
2014-11-23 11:31:55 +01:00
/**
* Removes the grid layout
*/
2016-05-15 05:33:16 +02:00
destroy() {
2016-01-04 07:59:30 +01:00
let tf = this.tf;
let tbl = tf.tbl;
2014-11-22 15:01:29 +01:00
2016-05-15 05:33:16 +02:00
if (!this.initialized) {
2014-11-22 15:01:29 +01:00
return;
}
2016-05-24 10:42:11 +02:00
let t = removeElm(tbl);
2014-11-22 15:01:29 +01:00
this.tblMainCont.parentNode.insertBefore(t, this.tblMainCont);
2016-05-24 10:42:11 +02:00
removeElm(this.tblMainCont);
2014-11-22 15:01:29 +01:00
this.tblMainCont = null;
this.headTblCont = null;
this.headTbl = null;
this.tblCont = null;
tbl.outerHTML = this.sourceTblHtml;
2015-12-09 07:24:45 +01:00
//needed to keep reference of table element for future usage
2016-05-25 09:31:53 +02:00
this.tf.tbl = elm(tf.id);
this.initialized = false;
2014-11-22 15:01:29 +01:00
}
}