tabulator-tables
Version:
Interactive table generation JavaScript library
349 lines (268 loc) • 9.73 kB
JavaScript
import Module from '../../core/Module.js';
export default class ResizeColumns extends Module{
static moduleName = "resizeColumns";
constructor(table){
super(table);
this.startColumn = false;
this.startX = false;
this.startWidth = false;
this.latestX = false;
this.handle = null;
this.initialNextColumn = null;
this.nextColumn = null;
this.initialized = false;
this.registerColumnOption("resizable", true);
this.registerTableOption("resizableColumnFit", false);
this.registerTableOption("resizableColumnGuide", false);
}
initialize(){
this.subscribe("column-rendered", this.layoutColumnHeader.bind(this));
}
initializeEventWatchers(){
if(!this.initialized){
this.subscribe("cell-rendered", this.layoutCellHandles.bind(this));
this.subscribe("cell-delete", this.deInitializeComponent.bind(this));
this.subscribe("cell-height", this.resizeHandle.bind(this));
this.subscribe("column-moved", this.columnLayoutUpdated.bind(this));
this.subscribe("column-hide", this.deInitializeColumn.bind(this));
this.subscribe("column-show", this.columnLayoutUpdated.bind(this));
this.subscribe("column-width", this.columnWidthUpdated.bind(this));
this.subscribe("column-delete", this.deInitializeComponent.bind(this));
this.subscribe("column-height", this.resizeHandle.bind(this));
this.initialized = true;
}
}
layoutCellHandles(cell){
if(cell.row.type === "row"){
this.deInitializeComponent(cell);
this.initializeColumn("cell", cell, cell.column, cell.element);
}
}
layoutColumnHeader(column){
if(column.definition.resizable){
this.initializeEventWatchers();
this.deInitializeComponent(column);
this.initializeColumn("header", column, column, column.element);
}
}
columnLayoutUpdated(column){
var prev = column.prevColumn();
this.reinitializeColumn(column);
if(prev){
this.reinitializeColumn(prev);
}
}
columnWidthUpdated(column){
if(column.modules.frozen){
if(this.table.modules.frozenColumns.leftColumns.includes(column)){
this.table.modules.frozenColumns.leftColumns.forEach((col) => {
this.reinitializeColumn(col);
});
}else if(this.table.modules.frozenColumns.rightColumns.includes(column)){
this.table.modules.frozenColumns.rightColumns.forEach((col) => {
this.reinitializeColumn(col);
});
}
}
}
frozenColumnOffset(column){
var offset = false;
if(column.modules.frozen){
offset = column.modules.frozen.marginValue;
if(column.modules.frozen.position === "left"){
offset += column.getWidth() - 3;
}else{
if(offset){
offset -= 3;
}
}
}
return offset !== false ? offset + "px" : false;
}
reinitializeColumn(column){
var frozenOffset = this.frozenColumnOffset(column);
column.cells.forEach((cell) => {
if(cell.modules.resize && cell.modules.resize.handleEl){
if(frozenOffset){
cell.modules.resize.handleEl.style[column.modules.frozen.position] = frozenOffset;
cell.modules.resize.handleEl.style["z-index"] = 11;
}
cell.element.after(cell.modules.resize.handleEl);
}
});
if(column.modules.resize && column.modules.resize.handleEl){
if(frozenOffset){
column.modules.resize.handleEl.style[column.modules.frozen.position] = frozenOffset;
}
column.element.after(column.modules.resize.handleEl);
}
}
initializeColumn(type, component, column, element){
var self = this,
variableHeight = false,
mode = column.definition.resizable,
config = {},
nearestColumn = column.getLastColumn();
//set column resize mode
if(type === "header"){
variableHeight = column.definition.formatter == "textarea" || column.definition.variableHeight;
config = {variableHeight:variableHeight};
}
if((mode === true || mode == type) && this._checkResizability(nearestColumn)){
var handle = document.createElement('span');
handle.className = "tabulator-col-resize-handle";
handle.addEventListener("click", function(e){
e.stopPropagation();
});
var handleDown = function(e){
self.startColumn = column;
self.initialNextColumn = self.nextColumn = nearestColumn.nextColumn();
self._mouseDown(e, nearestColumn, handle);
};
handle.addEventListener("mousedown", handleDown);
handle.addEventListener("touchstart", handleDown, {passive: true});
//resize column on double click
handle.addEventListener("dblclick", (e) => {
var oldWidth = nearestColumn.getWidth();
e.stopPropagation();
nearestColumn.reinitializeWidth(true);
if(oldWidth !== nearestColumn.getWidth()){
self.dispatch("column-resized", nearestColumn);
self.dispatchExternal("columnResized", nearestColumn.getComponent());
}
});
if(column.modules.frozen){
handle.style.position = "sticky";
handle.style[column.modules.frozen.position] = this.frozenColumnOffset(column);
}
config.handleEl = handle;
if(element.parentNode && column.visible){
element.after(handle);
}
}
component.modules.resize = config;
}
deInitializeColumn(column){
this.deInitializeComponent(column);
column.cells.forEach((cell) => {
this.deInitializeComponent(cell);
});
}
deInitializeComponent(component){
var handleEl;
if(component.modules.resize){
handleEl = component.modules.resize.handleEl;
if(handleEl && handleEl.parentElement){
handleEl.parentElement.removeChild(handleEl);
}
}
}
resizeHandle(component, height){
if(component.modules.resize && component.modules.resize.handleEl){
component.modules.resize.handleEl.style.height = height;
}
}
resize(e, column){
var x = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX,
startDiff = x - this.startX,
moveDiff = x - this.latestX,
blockedBefore, blockedAfter;
this.latestX = x;
if(this.table.rtl){
startDiff = -startDiff;
moveDiff = -moveDiff;
}
blockedBefore = column.width == column.minWidth || column.width == column.maxWidth;
column.setWidth(this.startWidth + startDiff);
blockedAfter = column.width == column.minWidth || column.width == column.maxWidth;
if(moveDiff < 0){
this.nextColumn = this.initialNextColumn;
}
if(this.table.options.resizableColumnFit && this.nextColumn && !(blockedBefore && blockedAfter)){
let colWidth = this.nextColumn.getWidth();
if(moveDiff > 0){
if(colWidth <= this.nextColumn.minWidth){
this.nextColumn = this.nextColumn.nextColumn();
}
}
if(this.nextColumn){
this.nextColumn.setWidth(this.nextColumn.getWidth() - moveDiff);
}
}
this.table.columnManager.rerenderColumns(true);
if(!this.table.browserSlow && column.modules.resize && column.modules.resize.variableHeight){
column.checkCellHeights();
}
}
calcGuidePosition(e, column, handle) {
var mouseX = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX,
handleX = handle.getBoundingClientRect().x - this.table.element.getBoundingClientRect().x,
tableX = this.table.element.getBoundingClientRect().x,
columnX = column.element.getBoundingClientRect().left - tableX,
mouseDiff = mouseX - this.startX,
pos = Math.max(handleX + mouseDiff, columnX + column.minWidth);
if(column.maxWidth){
pos = Math.min(pos, columnX + column.maxWidth);
}
return pos;
}
_checkResizability(column){
return column.definition.resizable;
}
_mouseDown(e, column, handle){
var self = this,
guideEl;
this.dispatchExternal("columnResizing", column.getComponent());
if(self.table.options.resizableColumnGuide){
guideEl = document.createElement("span");
guideEl.classList.add('tabulator-col-resize-guide');
self.table.element.appendChild(guideEl);
setTimeout(() => {
guideEl.style.left = self.calcGuidePosition(e, column, handle) + "px";
});
}
self.table.element.classList.add("tabulator-block-select");
function mouseMove(e){
if(self.table.options.resizableColumnGuide){
guideEl.style.left = self.calcGuidePosition(e, column, handle) + "px";
}else{
self.resize(e, column);
}
}
function mouseUp(e){
if(self.table.options.resizableColumnGuide){
self.resize(e, column);
guideEl.remove();
}
//block editor from taking action while resizing is taking place
if(self.startColumn.modules.edit){
self.startColumn.modules.edit.blocked = false;
}
if(self.table.browserSlow && column.modules.resize && column.modules.resize.variableHeight){
column.checkCellHeights();
}
document.body.removeEventListener("mouseup", mouseUp);
document.body.removeEventListener("mousemove", mouseMove);
handle.removeEventListener("touchmove", mouseMove);
handle.removeEventListener("touchend", mouseUp);
self.table.element.classList.remove("tabulator-block-select");
if(self.startWidth !== column.getWidth()){
self.table.columnManager.verticalAlignHeaders();
self.dispatch("column-resized", column);
self.dispatchExternal("columnResized", column.getComponent());
}
}
e.stopPropagation(); //prevent resize from interfering with movable columns
//block editor from taking action while resizing is taking place
if(self.startColumn.modules.edit){
self.startColumn.modules.edit.blocked = true;
}
self.startX = typeof e.clientX === "undefined" ? e.touches[0].clientX : e.clientX;
self.latestX = self.startX;
self.startWidth = column.getWidth();
document.body.addEventListener("mousemove", mouseMove);
document.body.addEventListener("mouseup", mouseUp);
handle.addEventListener("touchmove", mouseMove, {passive: true});
handle.addEventListener("touchend", mouseUp);
}
}