UNPKG

tabulator-tables

Version:

Interactive table generation JavaScript library

641 lines (474 loc) 15.4 kB
var ColumnManager = function(table){ this.table = table; //hold parent table this.blockHozScrollEvent = false; this.headersElement = this.createHeadersElement(); this.element = this.createHeaderElement(); //containing element this.rowManager = null; //hold row manager object this.columns = []; // column definition object this.columnsByIndex = []; //columns by index this.columnsByField = {}; //columns by field this.scrollLeft = 0; this.element.insertBefore(this.headersElement, this.element.firstChild); }; ////////////// Setup Functions ///////////////// ColumnManager.prototype.createHeadersElement = function (){ var el = document.createElement("div"); el.classList.add("tabulator-headers"); return el; }; ColumnManager.prototype.createHeaderElement = function (){ var el = document.createElement("div"); el.classList.add("tabulator-header"); if(!this.table.options.headerVisible){ el.classList.add("tabulator-header-hidden"); } return el; }; ColumnManager.prototype.initialize = function (){ var self = this; //scroll body along with header // self.element.addEventListener("scroll", function(e){ // if(!self.blockHozScrollEvent){ // self.table.rowManager.scrollHorizontal(self.element.scrollLeft); // } // }); }; //link to row manager ColumnManager.prototype.setRowManager = function(manager){ this.rowManager = manager; }; //return containing element ColumnManager.prototype.getElement = function(){ return this.element; }; //return header containing element ColumnManager.prototype.getHeadersElement = function(){ return this.headersElement; }; // ColumnManager.prototype.tempScrollBlock = function(){ // clearTimeout(this.blockHozScrollEvent); // this.blockHozScrollEvent = setTimeout(() => {this.blockHozScrollEvent = false;}, 50); // } //scroll horizontally to match table body ColumnManager.prototype.scrollHorizontal = function(left){ var hozAdjust = 0, scrollWidth = this.element.scrollWidth - this.table.element.clientWidth; // this.tempScrollBlock(); this.element.scrollLeft = left; //adjust for vertical scrollbar moving table when present if(left > scrollWidth){ hozAdjust = left - scrollWidth; this.element.style.marginLeft = (-(hozAdjust)) + "px"; }else{ this.element.style.marginLeft = 0; } //keep frozen columns fixed in position //this._calcFrozenColumnsPos(hozAdjust + 3); this.scrollLeft = left; if(this.table.modExists("frozenColumns")){ this.table.modules.frozenColumns.scrollHorizontal(); } }; ///////////// Column Setup Functions ///////////// ColumnManager.prototype.generateColumnsFromRowData = function(data){ var cols = [], row, sorter; if(data && data.length){ row = data[0]; for(var key in row){ let col = { field:key, title:key, }; let value = row[key]; switch(typeof value){ case "undefined": sorter = "string"; break; case "boolean": sorter = "boolean"; break; case "object": if(Array.isArray(value)){ sorter = "array"; }else{ sorter = "string"; } break; default: if(!isNaN(value) && value !== ""){ sorter = "number"; }else{ if(value.match(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+$/i)){ sorter = "alphanum"; }else{ sorter = "string"; } } break; } col.sorter = sorter; cols.push(col); } this.table.options.columns = cols; this.setColumns(this.table.options.columns); } }; ColumnManager.prototype.setColumns = function(cols, row){ var self = this; while(self.headersElement.firstChild) self.headersElement.removeChild(self.headersElement.firstChild); self.columns = []; self.columnsByIndex = []; self.columnsByField = {}; //reset frozen columns if(self.table.modExists("frozenColumns")){ self.table.modules.frozenColumns.reset(); } cols.forEach(function(def, i){ self._addColumn(def); }); self._reIndexColumns(); if(self.table.options.responsiveLayout && self.table.modExists("responsiveLayout", true)){ self.table.modules.responsiveLayout.initialize(); } self.redraw(true); }; ColumnManager.prototype._addColumn = function(definition, before, nextToColumn){ var column = new Column(definition, this), colEl = column.getElement(), index = nextToColumn ? this.findColumnIndex(nextToColumn) : nextToColumn; if(nextToColumn && index > -1){ var parentIndex = this.columns.indexOf(nextToColumn.getTopColumn()); var nextEl = nextToColumn.getElement(); if(before){ this.columns.splice(parentIndex, 0, column); nextEl.parentNode.insertBefore(colEl, nextEl); }else{ this.columns.splice(parentIndex + 1, 0, column); nextEl.parentNode.insertBefore(colEl, nextEl.nextSibling); } }else{ if(before){ this.columns.unshift(column); this.headersElement.insertBefore(column.getElement(), this.headersElement.firstChild); }else{ this.columns.push(column); this.headersElement.appendChild(column.getElement()); } } return column; }; ColumnManager.prototype.registerColumnField = function(col){ if(col.definition.field){ this.columnsByField[col.definition.field] = col; } }; ColumnManager.prototype.registerColumnPosition = function(col){ this.columnsByIndex.push(col); }; ColumnManager.prototype._reIndexColumns = function(){ this.columnsByIndex = []; this.columns.forEach(function(column){ column.reRegisterPosition(); }); }; //ensure column headers take up the correct amount of space in column groups ColumnManager.prototype._verticalAlignHeaders = function(){ var self = this, minHeight = 0; self.columns.forEach(function(column){ var height; column.clearVerticalAlign(); height = column.getHeight(); if(height > minHeight){ minHeight = height; } }); self.columns.forEach(function(column){ column.verticalAlign(self.table.options.columnVertAlign, minHeight); }); self.rowManager.adjustTableSize(); }; //////////////// Column Details ///////////////// ColumnManager.prototype.findColumn = function(subject){ var self = this; if(typeof subject == "object"){ if(subject instanceof Column){ //subject is column element return subject; }else if(subject instanceof ColumnComponent){ //subject is public column component return subject._getSelf() || false; }else if(typeof HTMLElement !== "undefined" && subject instanceof HTMLElement){ //subject is a HTML element of the column header let match = self.columns.find(function(column){ return column.element === subject; }); return match || false; } }else{ //subject should be treated as the field name of the column return this.columnsByField[subject] || false; } //catch all for any other type of input return false; }; ColumnManager.prototype.getColumnByField = function(field){ return this.columnsByField[field]; }; ColumnManager.prototype.getColumnByIndex = function(index){ return this.columnsByIndex[index]; }; ColumnManager.prototype.getFirstVisibileColumn = function(index){ var index = this.columnsByIndex.findIndex(function(col){ return col.visible; }); return index > -1 ? this.columnsByIndex[index] : false; }; ColumnManager.prototype.getColumns = function(){ return this.columns; }; ColumnManager.prototype.findColumnIndex = function(column){ return this.columnsByIndex.findIndex(function(col){ return column === col; }); }; //return all columns that are not groups ColumnManager.prototype.getRealColumns = function(){ return this.columnsByIndex; }; //travers across columns and call action ColumnManager.prototype.traverse = function(callback){ var self = this; self.columnsByIndex.forEach(function(column,i){ callback(column, i); }); }; //get defintions of actual columns ColumnManager.prototype.getDefinitions = function(active){ var self = this, output = []; self.columnsByIndex.forEach(function(column){ if(!active || (active && column.visible)){ output.push(column.getDefinition()); } }); return output; }; //get full nested definition tree ColumnManager.prototype.getDefinitionTree = function(){ var self = this, output = []; self.columns.forEach(function(column){ output.push(column.getDefinition(true)); }); return output; }; ColumnManager.prototype.getComponents = function(structured){ var self = this, output = [], columns = structured ? self.columns : self.columnsByIndex; columns.forEach(function(column){ output.push(column.getComponent()); }); return output; }; ColumnManager.prototype.getWidth = function(){ var width = 0; this.columnsByIndex.forEach(function(column){ if(column.visible){ width += column.getWidth(); } }); return width; }; ColumnManager.prototype.moveColumn = function(from, to, after){ this._moveColumnInArray(this.columns, from, to, after); this._moveColumnInArray(this.columnsByIndex, from, to, after, true); if(this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)){ this.table.modules.responsiveLayout.initialize(); } if(this.table.options.columnMoved){ this.table.options.columnMoved.call(this.table, from.getComponent(), this.table.columnManager.getComponents()); } if(this.table.options.persistentLayout && this.table.modExists("persistence", true)){ this.table.modules.persistence.save("columns"); } }; ColumnManager.prototype._moveColumnInArray = function(columns, from, to, after, updateRows){ var fromIndex = columns.indexOf(from), toIndex; if (fromIndex > -1) { columns.splice(fromIndex, 1); toIndex = columns.indexOf(to); if (toIndex > -1) { if(after){ toIndex = toIndex+1; } }else{ toIndex = fromIndex; } columns.splice(toIndex, 0, from); if(updateRows){ this.table.rowManager.rows.forEach(function(row){ if(row.cells.length){ var cell = row.cells.splice(fromIndex, 1)[0]; row.cells.splice(toIndex, 0, cell); } }); } } }; ColumnManager.prototype.scrollToColumn = function(column, position, ifVisible){ var left = 0, offset = 0, adjust = 0, colEl = column.getElement(); return new Promise((resolve, reject) => { if(typeof position === "undefined"){ position = this.table.options.scrollToColumnPosition; } if(typeof ifVisible === "undefined"){ ifVisible = this.table.options.scrollToColumnIfVisible; } if(column.visible){ //align to correct position switch(position){ case "middle": case "center": adjust = -this.element.clientWidth / 2; break; case "right": adjust = colEl.clientWidth - this.headersElement.clientWidth; break; } //check column visibility if(!ifVisible){ offset = colEl.offsetLeft; if(offset > 0 && offset + colEl.offsetWidth < this.element.clientWidth){ return false; } } //calculate scroll position left = colEl.offsetLeft + this.element.scrollLeft + adjust; left = Math.max(Math.min(left, this.table.rowManager.element.scrollWidth - this.table.rowManager.element.clientWidth),0); this.table.rowManager.scrollHorizontal(left); this.scrollHorizontal(left); resolve(); }else{ console.warn("Scroll Error - Column not visible"); reject("Scroll Error - Column not visible"); } }); }; //////////////// Cell Management ///////////////// ColumnManager.prototype.generateCells = function(row){ var self = this; var cells = []; self.columnsByIndex.forEach(function(column){ cells.push(column.generateCell(row)); }); return cells; }; //////////////// Column Management ///////////////// ColumnManager.prototype.getFlexBaseWidth = function(){ var self = this, totalWidth = self.table.element.clientWidth, //table element width fixedWidth = 0; //adjust for vertical scrollbar if present if(self.rowManager.element.scrollHeight > self.rowManager.element.clientHeight){ totalWidth -= self.rowManager.element.offsetWidth - self.rowManager.element.clientWidth; } this.columnsByIndex.forEach(function(column){ var width, minWidth, colWidth; if(column.visible){ width = column.definition.width || 0; minWidth = typeof column.minWidth == "undefined" ? self.table.options.columnMinWidth : parseInt(column.minWidth); if(typeof(width) == "string"){ if(width.indexOf("%") > -1){ colWidth = (totalWidth / 100) * parseInt(width) ; }else{ colWidth = parseInt(width); } }else{ colWidth = width; } fixedWidth += colWidth > minWidth ? colWidth : minWidth; } }); return fixedWidth; }; ColumnManager.prototype.addColumn = function(definition, before, nextToColumn){ var column = this._addColumn(definition, before, nextToColumn); this._reIndexColumns(); if(this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)){ this.table.modules.responsiveLayout.initialize(); } if(this.table.modExists("columnCalcs")){ this.table.modules.columnCalcs.recalc(this.table.rowManager.activeRows); } this.redraw(); if(this.table.modules.layout.getMode() != "fitColumns"){ column.reinitializeWidth(); } this._verticalAlignHeaders(); this.table.rowManager.reinitialize(); }; //remove column from system ColumnManager.prototype.deregisterColumn = function(column){ var field = column.getField(), index; //remove from field list if(field){ delete this.columnsByField[field]; } //remove from index list index = this.columnsByIndex.indexOf(column); if(index > -1){ this.columnsByIndex.splice(index, 1); } //remove from column list index = this.columns.indexOf(column); if(index > -1){ this.columns.splice(index, 1); } if(this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)){ this.table.modules.responsiveLayout.initialize(); } this.redraw(); }; //redraw columns ColumnManager.prototype.redraw = function(force){ if(force){ if(Tabulator.prototype.helpers.elVisible(this.element)){ this._verticalAlignHeaders(); } this.table.rowManager.resetScroll(); this.table.rowManager.reinitialize(); } if(this.table.modules.layout.getMode() == "fitColumns"){ this.table.modules.layout.layout(); }else{ if(force){ this.table.modules.layout.layout(); }else{ if(this.table.options.responsiveLayout && this.table.modExists("responsiveLayout", true)){ this.table.modules.responsiveLayout.update(); } } } if(this.table.modExists("frozenColumns")){ this.table.modules.frozenColumns.layout(); } if(this.table.modExists("columnCalcs")){ this.table.modules.columnCalcs.recalc(this.table.rowManager.activeRows); } if(force){ if(this.table.options.persistentLayout && this.table.modExists("persistence", true)){ this.table.modules.persistence.save("columns"); } if(this.table.modExists("columnCalcs")){ this.table.modules.columnCalcs.redraw(); } } this.table.footerManager.redraw(); };