import $ from './dom';
import { getRowHTML } from './rowmanager';
import { getDefault } from './utils';
export default class ColumnManager {
constructor(instance) {
this.instance = instance;
this.options = this.instance.options;
this.header = this.instance.header;
this.datamanager = this.instance.datamanager;
this.style = this.instance.style;
this.wrapper = this.instance.wrapper;
this.rowmanager = this.instance.rowmanager;
this.bindEvents();
}
renderHeader() {
const columns = this.datamanager.getColumns();
this.header.innerHTML = `
${getRowHTML(columns, { isHeader: 1 })}
`;
}
bindEvents() {
this.bindResizeColumn();
this.bindSortColumn();
}
bindResizeColumn() {
let isDragging = false;
let $currCell, startWidth, startX;
$.on(this.header, 'mousedown', '.data-table-col', (e, $cell) => {
$currCell = $cell;
const { colIndex } = $.data($currCell);
const col = this.getColumn(colIndex);
if (col && col.resizable === false) {
return;
}
isDragging = true;
startWidth = $.style($('.content', $currCell), 'width');
startX = e.pageX;
});
$.on(document.body, 'mouseup', (e) => {
if (!$currCell) return;
isDragging = false;
const { colIndex } = $.data($currCell);
const width = $.style($('.content', $currCell), 'width');
this.setColumnWidth(colIndex, width);
this.instance.setBodyWidth();
$currCell = null;
});
$.on(document.body, 'mousemove', (e) => {
if (!isDragging) return;
const finalWidth = startWidth + (e.pageX - startX);
const { colIndex } = $.data($currCell);
if (this.getColumnMinWidth(colIndex) > finalWidth) {
// don't resize past minWidth
return;
}
this.setColumnHeaderWidth(colIndex, finalWidth);
});
}
bindSortColumn() {
$.on(this.header, 'click', '.data-table-col .content span', (e, span) => {
const $cell = span.closest('.data-table-col');
let { colIndex, sortOrder } = $.data($cell);
sortOrder = getDefault(sortOrder, 'none');
const col = this.getColumn(colIndex);
if (col && col.sortable === false) {
return;
}
// reset sort indicator
$('.sort-indicator', this.header).textContent = '';
$.each('.data-table-col', this.header).map($cell => {
$.data($cell, {
sortOrder: 'none'
});
});
let nextSortOrder, textContent;
if (sortOrder === 'none') {
nextSortOrder = 'asc';
textContent = '▲';
} else if (sortOrder === 'asc') {
nextSortOrder = 'desc';
textContent = '▼';
} else if (sortOrder === 'desc') {
nextSortOrder = 'none';
textContent = '';
}
$.data($cell, {
sortOrder: nextSortOrder
});
$('.sort-indicator', $cell).textContent = textContent;
if (this.events && this.events.onSort) {
this.events.onSort(colIndex, nextSortOrder);
} else {
this.sortRows(colIndex, nextSortOrder);
this.rowmanager.refreshRows();
}
});
}
setDimensions() {
this.setHeaderStyle();
this.setupMinWidth();
this.setNaturalColumnWidth();
this.distributeRemainingWidth();
this.setColumnAlignments();
}
setHeaderStyle() {
if (!this.options.takeAvailableSpace) {
// setting width as 0 will ensure that the
// header doesn't take the available space
$.style(this.header, {
width: 0
});
}
$.style(this.header, {
margin: 0
});
}
setupMinWidth() {
// cache minWidth for each column
this.minWidthMap = getDefault(this.minWidthMap, []);
$.each('.data-table-col', this.header).map(col => {
const width = $.style($('.content', col), 'width');
const { colIndex } = $.data(col);
if (!this.minWidthMap[colIndex]) {
// only set this once
this.minWidthMap[colIndex] = width;
}
});
}
setNaturalColumnWidth() {
// set initial width as naturally calculated by table's first row
$.each('.data-table-row[data-row-index="0"] .data-table-col', this.bodyScrollable).map($cell => {
let width = $.style($('.content', $cell), 'width');
const height = $.style($('.content', $cell), 'height');
const { colIndex } = $.data($cell);
const minWidth = this.getColumnMinWidth(colIndex);
if (width < minWidth) {
width = minWidth;
}
this.setColumnWidth(colIndex, width);
this.setDefaultCellHeight(height);
});
}
distributeRemainingWidth() {
if (!this.options.takeAvailableSpace) return;
const wrapperWidth = $.style(this.instance.datatableWrapper, 'width');
const headerWidth = $.style(this.header, 'width');
if (headerWidth >= wrapperWidth) {
// don't resize, horizontal scroll takes place
return;
}
const deltaWidth = (wrapperWidth - headerWidth) / this.datamanager.getColumnCount(true);
this.datamanager.getColumns(true).map(col => {
const width = $.style(this.getColumnHeaderElement(col.colIndex), 'width');
let finalWidth = Math.min(width + deltaWidth) - 2;
this.setColumnHeaderWidth(col.colIndex, finalWidth);
this.setColumnWidth(col.colIndex, finalWidth);
});
this.instance.setBodyWidth();
}
setDefaultCellHeight(height) {
this.style.setStyle('.data-table-col .content', {
height: height + 'px'
});
}
setColumnAlignments() {
// align columns
this.getColumns()
.map(column => {
if (['left', 'center', 'right'].includes(column.align)) {
this.style.setStyle(`.data-table [data-col-index="${column.colIndex}"]`, {
'text-align': column.align
});
}
});
}
sortRows(colIndex, sortOrder) {
this.datamanager.sortRows(colIndex, sortOrder);
}
getColumn(colIndex) {
return this.datamanager.getColumn(colIndex);
}
getColumns() {
return this.datamanager.getColumns();
}
setColumnWidth(colIndex, width) {
this._columnWidthMap = this._columnWidthMap || [];
let index = this._columnWidthMap[colIndex];
const selector = `[data-col-index="${colIndex}"] .content, [data-col-index="${colIndex}"] .edit-cell`;
const styles = {
width: width + 'px'
};
index = this.style.setStyle(selector, styles, index);
this._columnWidthMap[colIndex] = index;
}
setColumnHeaderWidth(colIndex, width) {
this.$columnMap = this.$columnMap || [];
const selector = `[data-col-index="${colIndex}"][data-is-header] .content`;
let $column = this.$columnMap[colIndex];
if (!$column) {
$column = this.header.querySelector(selector);
this.$columnMap[colIndex] = $column;
}
$column.style.width = width + 'px';
}
getColumnMinWidth(colIndex) {
colIndex = +colIndex;
return this.minWidthMap && this.minWidthMap[colIndex];
}
getFirstColumnIndex() {
if (this.options.addCheckboxColumn && this.options.addSerialNoColumn) {
return 2;
}
if (this.options.addCheckboxColumn || this.options.addSerialNoColumn) {
return 1;
}
return 0;
}
getLastColumnIndex() {
return this.datamanager.getColumnCount() - 1;
}
getColumnHeaderElement(colIndex) {
colIndex = +colIndex;
if (colIndex < 0) return null;
return $(`.data-table-col[data-is-header][data-col-index="${colIndex}"]`, this.wrapper);
}
getSerialColumnIndex() {
const columns = this.datamanager.getColumns();
return columns.findIndex(column => column.content.includes('Sr. No'));
}
}