tabulator-tables
Version:
Interactive table generation JavaScript library
333 lines (257 loc) • 8.6 kB
JavaScript
import Module from '../../core/Module.js';
class FrozenColumns extends Module{
constructor(table){
super(table);
this.leftColumns = [];
this.rightColumns = [];
this.leftMargin = 0;
this.rightMargin = 0;
this.rightPadding = 0;
this.initializationMode = "left";
this.active = false;
this.blocked = true;
this.registerColumnOption("frozen");
}
//reset initial state
reset(){
this.initializationMode = "left";
this.leftColumns = [];
this.rightColumns = [];
this.leftMargin = 0;
this.rightMargin = 0;
this.rightMargin = 0;
this.active = false;
this.table.columnManager.headersElement.style.marginLeft = 0;
this.table.columnManager.element.style.paddingRight = 0;
}
initialize(){
this.subscribe("cell-layout", this.layoutCell.bind(this));
this.subscribe("column-init", this.initializeColumn.bind(this));
this.subscribe("column-width", this.layout.bind(this));
this.subscribe("row-layout-after", this.layoutRow.bind(this));
this.subscribe("table-layout", this.layout.bind(this));
this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
this.subscribe("columns-loading", this.reset.bind(this));
this.subscribe("column-add", this.reinitializeColumns.bind(this));
this.subscribe("column-delete", this.reinitializeColumns.bind(this));
this.subscribe("table-redraw", this.layout.bind(this));
this.subscribe("layout-refreshing", this.blockLayout.bind(this));
this.subscribe("layout-refreshed", this.unblockLayout.bind(this));
}
blockLayout(){
this.blocked = true;
}
unblockLayout(){
this.blocked = false;
}
layoutCell(cell){
this.layoutElement(cell.element, cell.column);
}
reinitializeColumns(){
this.reset();
this.table.columnManager.columnsByIndex.forEach((column) => {
this.initializeColumn(column);
});
}
//initialize specific column
initializeColumn(column){
var config = {margin:0, edge:false};
if(!column.isGroup){
if(this.frozenCheck(column)){
config.position = this.initializationMode;
if(this.initializationMode == "left"){
this.leftColumns.push(column);
}else{
this.rightColumns.unshift(column);
}
this.active = true;
column.modules.frozen = config;
}else{
this.initializationMode = "right";
}
}
}
frozenCheck(column){
if(column.parent.isGroup && column.definition.frozen){
console.warn("Frozen Column Error - Parent column group must be frozen, not individual columns or sub column groups");
}
if(column.parent.isGroup){
return this.frozenCheck(column.parent);
}else{
return column.definition.frozen;
}
}
//quick layout to smooth horizontal scrolling
scrollHorizontal(){
if(this.active){
this.calcMargins(true);
this.layoutColumnPosition();
this.layoutCalcRows();
this.reinitializeRows();
}
}
//calculate margins for rows
calcMargins(scroll){
if(!scroll){
this.leftMargin = this._calcSpace(this.leftColumns, this.leftColumns.length) + "px";
this.rightMargin = this._calcSpace(this.rightColumns, this.rightColumns.length) + "px";
this.table.rowManager.tableElement.style.marginRight = this.rightMargin;
}
//calculate right frozen columns
this.rightPadding = this.table.rowManager.element.clientWidth + this.table.columnManager.scrollLeft;
}
//layout calculation rows
layoutCalcRows(){
if(this.table.modExists("columnCalcs")){
if(this.table.modules.columnCalcs.topInitialized && this.table.modules.columnCalcs.topRow){
this.layoutRow(this.table.modules.columnCalcs.topRow);
}
if(this.table.modules.columnCalcs.botInitialized && this.table.modules.columnCalcs.botRow){
this.layoutRow(this.table.modules.columnCalcs.botRow);
}
if(this.table.modExists("groupRows")){
this.layoutGroupCalcs(this.table.modules.groupRows.getGroups());
}
}
}
layoutGroupCalcs(groups){
groups.forEach((group) => {
if(group.calcs.top){
this.layoutRow(group.calcs.top);
}
if(group.calcs.bottom){
this.layoutRow(group.calcs.bottom);
}
if(group.groupList && group.groupList.length){
this.layoutGroupCalcs(group.groupList);
}
});
}
//calculate column positions and layout headers
layoutColumnPosition(allCells){
var leftParents = [];
var leftMargin = 0;
var rightMargin = 0;
this.table.columnManager.headersElement.style.marginLeft = this.leftMargin;
this.table.columnManager.element.style.paddingRight = this.rightMargin;
this.leftColumns.forEach((column, i) => {
column.modules.frozen.marginValue = leftMargin + this.table.columnManager.scrollLeft;
column.modules.frozen.margin = column.modules.frozen.marginValue + "px";
if(column.visible){
leftMargin += column.getWidth();
}
if(i == this.leftColumns.length - 1){
column.modules.frozen.edge = true;
}else{
column.modules.frozen.edge = false;
}
if(column.parent.isGroup){
var parentEl = this.getColGroupParentElement(column);
if(!leftParents.includes(parentEl)){
this.layoutElement(parentEl, column);
leftParents.push(parentEl);
}
if(column.modules.frozen.edge){
parentEl.classList.add("tabulator-frozen-" + column.modules.frozen.position);
}
}else{
this.layoutElement(column.getElement(), column);
}
if(allCells){
column.cells.forEach((cell) => {
this.layoutElement(cell.getElement(true), column);
});
}
});
this.rightColumns.forEach((column, i) => {
if(column.visible){
rightMargin += column.getWidth();
}
column.modules.frozen.marginValue = this.rightPadding - rightMargin;
column.modules.frozen.margin = column.modules.frozen.marginValue + "px";
if(i == this.rightColumns.length - 1){
column.modules.frozen.edge = true;
}else{
column.modules.frozen.edge = false;
}
if(column.parent.isGroup){
this.layoutElement(this.getColGroupParentElement(column), column);
}else{
this.layoutElement(column.getElement(), column);
}
if(allCells){
column.cells.forEach((cell) => {
this.layoutElement(cell.getElement(true), column);
});
}
});
}
getColGroupParentElement(column){
return column.parent.isGroup ? this.getColGroupParentElement(column.parent) : column.getElement();
}
//layout columns appropriately
layout(){
if(this.active && !this.blocked){
//calculate row padding
this.calcMargins();
//calculate left columns
this.layoutColumnPosition();
this.reinitializeRows();
this.layoutCalcRows();
}
}
reinitializeRows(){
var visibleRows = this.table.rowManager.getVisibleRows(true);
var otherRows = this.table.rowManager.getRows().filter(row => !visibleRows.includes(row));
otherRows.forEach((row) =>{
row.deinitialize();
});
visibleRows.forEach((row) =>{
if(row.type === "row"){
this.layoutRow(row);
}
});
}
layoutRow(row){
// console.trace("row")
var rowEl = row.getElement();
rowEl.style.paddingLeft = this.leftMargin;
if(this.table.options.layout === "fitDataFill" && this.rightColumns.length){
this.table.rowManager.getTableElement().style.minWidth = "calc(100% - " + this.rightMargin + ")";
}
this.leftColumns.forEach((column) => {
var cell = row.getCell(column);
if(cell){
this.layoutElement(cell.getElement(true), column);
}
});
this.rightColumns.forEach((column) => {
var cell = row.getCell(column);
if(cell){
this.layoutElement(cell.getElement(true), column);
}
});
}
layoutElement(element, column){
if(column.modules.frozen){
element.style.position = "absolute";
element.style.left = column.modules.frozen.margin;
element.classList.add("tabulator-frozen");
if(column.modules.frozen.edge){
element.classList.add("tabulator-frozen-" + column.modules.frozen.position);
}
}
}
_calcSpace(columns, index){
var width = 0;
for (let i = 0; i < index; i++){
if(columns[i].visible){
width += columns[i].getWidth();
}
}
return width;
}
}
FrozenColumns.moduleName = "frozenColumns";
export default FrozenColumns;