Add RowManager and ColumnManager
This commit is contained in:
parent
785cf8f466
commit
0ccc3627ae
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -9,6 +9,8 @@ export default class CellManager {
|
|||||||
this.options = this.instance.options;
|
this.options = this.instance.options;
|
||||||
this.style = this.instance.style;
|
this.style = this.instance.style;
|
||||||
this.bodyScrollable = this.instance.bodyScrollable;
|
this.bodyScrollable = this.instance.bodyScrollable;
|
||||||
|
this.columnmanager = this.instance.columnmanager;
|
||||||
|
this.rowmanager = this.instance.rowmanager;
|
||||||
|
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
}
|
}
|
||||||
@ -77,7 +79,7 @@ export default class CellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let $cell = this.$focusedCell;
|
let $cell = this.$focusedCell;
|
||||||
const { rowIndex, colIndex } = this.getCellAttr($cell);
|
const { rowIndex, colIndex } = $.data($cell);
|
||||||
|
|
||||||
if (direction === 'left') {
|
if (direction === 'left') {
|
||||||
$cell = this.getLeftMostCell$(rowIndex);
|
$cell = this.getLeftMostCell$(rowIndex);
|
||||||
@ -97,7 +99,7 @@ export default class CellManager {
|
|||||||
if (!this.$focusedCell) return false;
|
if (!this.$focusedCell) return false;
|
||||||
|
|
||||||
if (!this.inViewport(this.$focusedCell)) {
|
if (!this.inViewport(this.$focusedCell)) {
|
||||||
const { rowIndex } = this.getCellAttr(this.$focusedCell);
|
const { rowIndex } = $.data(this.$focusedCell);
|
||||||
|
|
||||||
this.scrollToRow(rowIndex - this.getRowCountPerPage() + 2);
|
this.scrollToRow(rowIndex - this.getRowCountPerPage() + 2);
|
||||||
return true;
|
return true;
|
||||||
@ -173,9 +175,9 @@ export default class CellManager {
|
|||||||
focusCell($cell) {
|
focusCell($cell) {
|
||||||
if (!$cell) return;
|
if (!$cell) return;
|
||||||
|
|
||||||
const { colIndex } = this.getCellAttr($cell);
|
const { colIndex, isHeader } = $.data($cell);
|
||||||
|
|
||||||
if (this.isStandardCell(colIndex)) {
|
if (this.isStandardCell(colIndex) || isHeader) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,8 +199,8 @@ export default class CellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
highlightRowColumnHeader($cell) {
|
highlightRowColumnHeader($cell) {
|
||||||
const { colIndex, rowIndex } = this.getCellAttr($cell);
|
const { colIndex, rowIndex } = $.data($cell);
|
||||||
const _colIndex = this.instance.getSerialColumnIndex();
|
const _colIndex = this.columnmanager.getSerialColumnIndex();
|
||||||
const colHeaderSelector = `.data-table-header .data-table-col[data-col-index="${colIndex}"]`;
|
const colHeaderSelector = `.data-table-header .data-table-col[data-col-index="${colIndex}"]`;
|
||||||
const rowHeaderSelector = `.data-table-col[data-row-index="${rowIndex}"][data-col-index="${_colIndex}"]`;
|
const rowHeaderSelector = `.data-table-col[data-row-index="${rowIndex}"][data-col-index="${_colIndex}"]`;
|
||||||
|
|
||||||
@ -226,6 +228,8 @@ export default class CellManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_selectArea($cell1, $cell2) {
|
_selectArea($cell1, $cell2) {
|
||||||
|
if ($cell1 === $cell2) return false;
|
||||||
|
|
||||||
const cells = this.getCellsInRange($cell1, $cell2);
|
const cells = this.getCellsInRange($cell1, $cell2);
|
||||||
if (!cells) return false;
|
if (!cells) return false;
|
||||||
|
|
||||||
@ -246,8 +250,8 @@ export default class CellManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cell1 = this.getCellAttr($cell1);
|
const cell1 = $.data($cell1);
|
||||||
const cell2 = this.getCellAttr($cell2);
|
const cell2 = $.data($cell2);
|
||||||
|
|
||||||
colIndex1 = cell1.colIndex;
|
colIndex1 = cell1.colIndex;
|
||||||
rowIndex1 = cell1.rowIndex;
|
rowIndex1 = cell1.rowIndex;
|
||||||
@ -300,15 +304,15 @@ export default class CellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
activateEditing($cell) {
|
activateEditing($cell) {
|
||||||
const { rowIndex, colIndex } = this.getCellAttr($cell);
|
const { rowIndex, colIndex } = $.data($cell);
|
||||||
const col = this.instance.getColumn(colIndex);
|
const col = this.instance.columnmanager.getColumn(colIndex);
|
||||||
|
|
||||||
if (col && col.editable === false) {
|
if (col && col.editable === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$editingCell) {
|
if (this.$editingCell) {
|
||||||
const { _rowIndex, _colIndex } = this.getCellAttr(this.$editingCell);
|
const { _rowIndex, _colIndex } = $.data(this.$editingCell);
|
||||||
|
|
||||||
if (rowIndex === _rowIndex && colIndex === _colIndex) {
|
if (rowIndex === _rowIndex && colIndex === _colIndex) {
|
||||||
// editing the same cell
|
// editing the same cell
|
||||||
@ -364,7 +368,7 @@ export default class CellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
submitEditing($cell) {
|
submitEditing($cell) {
|
||||||
const { rowIndex, colIndex } = this.getCellAttr($cell);
|
const { rowIndex, colIndex } = $.data($cell);
|
||||||
|
|
||||||
if ($cell) {
|
if ($cell) {
|
||||||
const editing = this.currentCellEditing;
|
const editing = this.currentCellEditing;
|
||||||
@ -428,7 +432,7 @@ export default class CellManager {
|
|||||||
|
|
||||||
isStandardCell(colIndex) {
|
isStandardCell(colIndex) {
|
||||||
// Standard cells are in Sr. No and Checkbox column
|
// Standard cells are in Sr. No and Checkbox column
|
||||||
return colIndex < this.instance.getFirstColumnIndex();
|
return colIndex < this.columnmanager.getFirstColumnIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
getCell$(colIndex, rowIndex) {
|
getCell$(colIndex, rowIndex) {
|
||||||
@ -436,14 +440,14 @@ export default class CellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAboveCell$($cell) {
|
getAboveCell$($cell) {
|
||||||
const { colIndex } = this.getCellAttr($cell);
|
const { colIndex } = $.data($cell);
|
||||||
const $aboveRow = $cell.parentElement.previousElementSibling;
|
const $aboveRow = $cell.parentElement.previousElementSibling;
|
||||||
|
|
||||||
return $(`[data-col-index="${colIndex}"]`, $aboveRow);
|
return $(`[data-col-index="${colIndex}"]`, $aboveRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBelowCell$($cell) {
|
getBelowCell$($cell) {
|
||||||
const { colIndex } = this.getCellAttr($cell);
|
const { colIndex } = $.data($cell);
|
||||||
const $belowRow = $cell.parentElement.nextElementSibling;
|
const $belowRow = $cell.parentElement.nextElementSibling;
|
||||||
|
|
||||||
return $(`[data-col-index="${colIndex}"]`, $belowRow);
|
return $(`[data-col-index="${colIndex}"]`, $belowRow);
|
||||||
@ -458,19 +462,19 @@ export default class CellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getLeftMostCell$(rowIndex) {
|
getLeftMostCell$(rowIndex) {
|
||||||
return this.getCell$(rowIndex, this.instance.getFirstColumnIndex());
|
return this.getCell$(rowIndex, this.columnmanager.getFirstColumnIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
getRightMostCell$(rowIndex) {
|
getRightMostCell$(rowIndex) {
|
||||||
return this.getCell$(rowIndex, this.instance.getLastColumnIndex());
|
return this.getCell$(rowIndex, this.columnmanager.getLastColumnIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
getTopMostCell$(colIndex) {
|
getTopMostCell$(colIndex) {
|
||||||
return this.getCell$(0, colIndex);
|
return this.getCell$(this.rowmanager.getFirstRowIndex(), colIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBottomMostCell$(colIndex) {
|
getBottomMostCell$(colIndex) {
|
||||||
return this.getCell$(this.instance.getLastRowIndex(), colIndex);
|
return this.getCell$(this.rowmanager.getLastRowIndex(), colIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCell(colIndex, rowIndex) {
|
getCell(colIndex, rowIndex) {
|
||||||
@ -486,12 +490,12 @@ export default class CellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inViewport($cell) {
|
inViewport($cell) {
|
||||||
let colIndex, rowIndex;
|
let colIndex, rowIndex; // eslint-disable-line
|
||||||
|
|
||||||
if (typeof $cell === 'number') {
|
if (typeof $cell === 'number') {
|
||||||
[colIndex, rowIndex] = arguments;
|
[colIndex, rowIndex] = arguments;
|
||||||
} else {
|
} else {
|
||||||
let cell = this.getCellAttr($cell);
|
let cell = $.data($cell);
|
||||||
|
|
||||||
colIndex = cell.colIndex;
|
colIndex = cell.colIndex;
|
||||||
rowIndex = cell.rowIndex;
|
rowIndex = cell.rowIndex;
|
||||||
@ -511,7 +515,7 @@ export default class CellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scrollToCell($cell) {
|
scrollToCell($cell) {
|
||||||
const { rowIndex } = this.getCellAttr($cell);
|
const { rowIndex } = $.data($cell);
|
||||||
|
|
||||||
this.scrollToRow(rowIndex);
|
this.scrollToRow(rowIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
271
src/columnmanager.js
Normal file
271
src/columnmanager.js
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
import $ from './dom';
|
||||||
|
import { getDefault, getHeaderHTML } 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 = getHeaderHTML(columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (column.align && ['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) {
|
||||||
|
const selector = `[data-col-index="${colIndex}"] .content, [data-col-index="${colIndex}"] .edit-cell`;
|
||||||
|
|
||||||
|
this.style.setStyle(selector, {
|
||||||
|
width: width + 'px'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setColumnHeaderWidth(colIndex, width) {
|
||||||
|
this.style.setStyle(`[data-col-index="${colIndex}"][data-is-header] .content`, {
|
||||||
|
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'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { isNumeric } from './utils';
|
||||||
|
|
||||||
export default class DataManager {
|
export default class DataManager {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
@ -14,6 +15,8 @@ export default class DataManager {
|
|||||||
|
|
||||||
this.columns = this.prepareColumns(columns);
|
this.columns = this.prepareColumns(columns);
|
||||||
this.rows = this.prepareRows(rows);
|
this.rows = this.prepareRows(rows);
|
||||||
|
|
||||||
|
this.prepareNumericColumns();
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareColumns(columns) {
|
prepareColumns(columns) {
|
||||||
@ -25,7 +28,8 @@ export default class DataManager {
|
|||||||
const val = {
|
const val = {
|
||||||
content: 'Sr. No',
|
content: 'Sr. No',
|
||||||
editable: false,
|
editable: false,
|
||||||
resizable: false
|
resizable: false,
|
||||||
|
align: 'center'
|
||||||
};
|
};
|
||||||
|
|
||||||
columns = [val].concat(columns);
|
columns = [val].concat(columns);
|
||||||
@ -60,6 +64,19 @@ export default class DataManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prepareNumericColumns() {
|
||||||
|
const row0 = this.getRow(0);
|
||||||
|
this.columns = this.columns.map((column, i) => {
|
||||||
|
|
||||||
|
const cellValue = row0[i].content;
|
||||||
|
if (!column.align && cellValue && isNumeric(cellValue)) {
|
||||||
|
column.align = 'right';
|
||||||
|
}
|
||||||
|
|
||||||
|
return column;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
prepareRows(rows) {
|
prepareRows(rows) {
|
||||||
if (!Array.isArray(rows) || !Array.isArray(rows[0])) {
|
if (!Array.isArray(rows) || !Array.isArray(rows[0])) {
|
||||||
throw new TypeError('`rows` must be an array of arrays');
|
throw new TypeError('`rows` must be an array of arrays');
|
||||||
@ -164,12 +181,36 @@ export default class DataManager {
|
|||||||
return this.rows.slice(start, end);
|
return this.rows.slice(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
getColumns() {
|
getColumns(skipStandardColumns) {
|
||||||
return this.columns;
|
let columns = this.columns;
|
||||||
|
|
||||||
|
if (skipStandardColumns) {
|
||||||
|
columns = columns.slice(this.getStandardColumnCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
getColumnCount() {
|
getStandardColumnCount() {
|
||||||
return this.columns.length;
|
if (this.options.addCheckboxColumn && this.options.addSerialNoColumn) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.addCheckboxColumn || this.options.addSerialNoColumn) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getColumnCount(skipStandardColumns) {
|
||||||
|
let val = this.columns.length;
|
||||||
|
|
||||||
|
if (skipStandardColumns) {
|
||||||
|
val = val - this.getStandardColumnCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
getColumn(colIndex) {
|
getColumn(colIndex) {
|
||||||
|
|||||||
390
src/datatable.js
390
src/datatable.js
@ -1,14 +1,14 @@
|
|||||||
import {
|
import {
|
||||||
getHeaderHTML,
|
|
||||||
getBodyHTML,
|
getBodyHTML,
|
||||||
getRowHTML,
|
getRowHTML
|
||||||
getDefault
|
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
import $ from './dom';
|
import $ from './dom';
|
||||||
|
|
||||||
import DataManager from './datamanager';
|
import DataManager from './datamanager';
|
||||||
import CellManager from './cellmanager';
|
import CellManager from './cellmanager';
|
||||||
|
import ColumnManager from './columnmanager';
|
||||||
|
import RowManager from './rowmanager';
|
||||||
import Style from './style';
|
import Style from './style';
|
||||||
|
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
@ -24,7 +24,7 @@ const DEFAULT_OPTIONS = {
|
|||||||
addCheckboxColumn: true,
|
addCheckboxColumn: true,
|
||||||
enableClusterize: true,
|
enableClusterize: true,
|
||||||
enableLogs: false,
|
enableLogs: false,
|
||||||
takeAvailableSpace: false
|
takeAvailableSpace: true
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class DataTable {
|
export default class DataTable {
|
||||||
@ -38,13 +38,13 @@ export default class DataTable {
|
|||||||
this.options = Object.assign({}, DEFAULT_OPTIONS, options);
|
this.options = Object.assign({}, DEFAULT_OPTIONS, options);
|
||||||
// custom user events
|
// custom user events
|
||||||
this.events = this.options.events;
|
this.events = this.options.events;
|
||||||
// map of checked rows
|
|
||||||
this.checkMap = [];
|
|
||||||
|
|
||||||
// make dom, make style, bind events
|
this.prepare();
|
||||||
this.make();
|
|
||||||
|
|
||||||
|
this.style = new Style(this.wrapper);
|
||||||
this.datamanager = new DataManager(this.options);
|
this.datamanager = new DataManager(this.options);
|
||||||
|
this.rowmanager = new RowManager(this);
|
||||||
|
this.columnmanager = new ColumnManager(this);
|
||||||
this.cellmanager = new CellManager(this);
|
this.cellmanager = new CellManager(this);
|
||||||
|
|
||||||
if (this.options.data) {
|
if (this.options.data) {
|
||||||
@ -52,13 +52,11 @@ export default class DataTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
make() {
|
prepare() {
|
||||||
this.makeDom();
|
this.prepareDom();
|
||||||
this.makeStyle();
|
|
||||||
this.bindEvents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
makeDom() {
|
prepareDom() {
|
||||||
this.wrapper.innerHTML = `
|
this.wrapper.innerHTML = `
|
||||||
<div class="data-table">
|
<div class="data-table">
|
||||||
<table class="data-table-header">
|
<table class="data-table-header">
|
||||||
@ -74,6 +72,7 @@ export default class DataTable {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
this.datatableWrapper = $('.data-table', this.wrapper);
|
||||||
this.header = $('.data-table-header', this.wrapper);
|
this.header = $('.data-table-header', this.wrapper);
|
||||||
this.bodyScrollable = $('.body-scrollable', this.wrapper);
|
this.bodyScrollable = $('.body-scrollable', this.wrapper);
|
||||||
}
|
}
|
||||||
@ -85,7 +84,7 @@ export default class DataTable {
|
|||||||
|
|
||||||
appendRows(rows) {
|
appendRows(rows) {
|
||||||
this.datamanager.appendRows(rows);
|
this.datamanager.appendRows(rows);
|
||||||
this.render();
|
this.rowmanager.refreshRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -95,9 +94,7 @@ export default class DataTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderHeader() {
|
renderHeader() {
|
||||||
const columns = this.datamanager.getColumns();
|
this.columnmanager.renderHeader();
|
||||||
|
|
||||||
this.header.innerHTML = getHeaderHTML(columns);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBody() {
|
renderBody() {
|
||||||
@ -119,8 +116,6 @@ export default class DataTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderBodyWithClusterize() {
|
renderBodyWithClusterize() {
|
||||||
const self = this;
|
|
||||||
|
|
||||||
// empty body
|
// empty body
|
||||||
this.bodyScrollable.innerHTML = `
|
this.bodyScrollable.innerHTML = `
|
||||||
<table class="data-table-body">
|
<table class="data-table-body">
|
||||||
@ -142,8 +137,8 @@ export default class DataTable {
|
|||||||
scrollElem: this.bodyScrollable,
|
scrollElem: this.bodyScrollable,
|
||||||
contentElem: $('tbody', this.bodyScrollable),
|
contentElem: $('tbody', this.bodyScrollable),
|
||||||
callbacks: {
|
callbacks: {
|
||||||
clusterChanged() {
|
clusterChanged: () => {
|
||||||
self.highlightCheckedRows();
|
this.rowmanager.highlightCheckedRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -192,59 +187,8 @@ export default class DataTable {
|
|||||||
return rows.map((row) => getRowHTML(row, { rowIndex: row[0].rowIndex }));
|
return rows.map((row) => getRowHTML(row, { rowIndex: row[0].rowIndex }));
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshRows() {
|
|
||||||
this.renderBody();
|
|
||||||
this.setDimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
bindEvents() {
|
|
||||||
this.bindResizeColumn();
|
|
||||||
this.bindSortColumn();
|
|
||||||
this.bindCheckbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
setDimensions() {
|
setDimensions() {
|
||||||
const self = this;
|
this.columnmanager.setDimensions();
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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 (!self.minWidthMap[colIndex]) {
|
|
||||||
// only set this once
|
|
||||||
self.minWidthMap[colIndex] = width;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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 } = self.getCellAttr($cell);
|
|
||||||
const minWidth = self.getColumnMinWidth(colIndex);
|
|
||||||
|
|
||||||
if (width < minWidth) {
|
|
||||||
width = minWidth;
|
|
||||||
}
|
|
||||||
self.setColumnWidth(colIndex, width);
|
|
||||||
self.setDefaultCellHeight(height);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.setBodyWidth();
|
this.setBodyWidth();
|
||||||
|
|
||||||
@ -252,315 +196,19 @@ export default class DataTable {
|
|||||||
marginTop: $.style(this.header, 'height') + 'px'
|
marginTop: $.style(this.header, 'height') + 'px'
|
||||||
});
|
});
|
||||||
|
|
||||||
// center align Sr. No column
|
|
||||||
if (this.options.addSerialNoColumn) {
|
|
||||||
const index = this.getSerialColumnIndex();
|
|
||||||
|
|
||||||
this.style.setStyle(`.data-table [data-col-index="${index}"]`, {
|
|
||||||
'text-align': 'center'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$.style($('table', this.bodyScrollable), {
|
$.style($('table', this.bodyScrollable), {
|
||||||
margin: 0
|
margin: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bindResizeColumn() {
|
|
||||||
const self = this;
|
|
||||||
let isDragging = false;
|
|
||||||
let $currCell, startWidth, startX;
|
|
||||||
|
|
||||||
$.on(this.header, 'mousedown', '.data-table-col', (e, cell) => {
|
|
||||||
$currCell = cell;
|
|
||||||
const { colIndex } = this.getCellAttr($currCell);
|
|
||||||
const col = self.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 } = this.getCellAttr($currCell);
|
|
||||||
const width = $.style($('.content', $currCell), 'width');
|
|
||||||
|
|
||||||
self.setColumnWidth(colIndex, width);
|
|
||||||
self.setBodyWidth();
|
|
||||||
$currCell = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
$.on(document.body, 'mousemove', (e) => {
|
|
||||||
if (!isDragging) return;
|
|
||||||
const finalWidth = startWidth + (e.pageX - startX);
|
|
||||||
const { colIndex } = this.getCellAttr($currCell);
|
|
||||||
|
|
||||||
if (self.getColumnMinWidth(colIndex) > finalWidth) {
|
|
||||||
// don't resize past minWidth
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.setColumnHeaderWidth(colIndex, finalWidth);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bindSortColumn() {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
$.on(this.header, 'click', '.data-table-col .content span', (e, span) => {
|
|
||||||
const $cell = span.closest('.data-table-col');
|
|
||||||
let { colIndex, sortOrder } = this.getCellAttr($cell);
|
|
||||||
sortOrder = getDefault(sortOrder, 'none');
|
|
||||||
const col = self.getColumn(colIndex);
|
|
||||||
|
|
||||||
if (col && col.sortable === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset sort indicator
|
|
||||||
$('.sort-indicator', this.header).textContent = '';
|
|
||||||
$.each('.data-table-col', this.header).map($cell => {
|
|
||||||
$cell.setAttribute('data-sort-order', 'none');
|
|
||||||
});
|
|
||||||
|
|
||||||
if (sortOrder === 'none') {
|
|
||||||
$cell.setAttribute('data-sort-order', 'asc');
|
|
||||||
$('.sort-indicator', $cell).textContent = '▲';
|
|
||||||
} else if (sortOrder === 'asc') {
|
|
||||||
$cell.setAttribute('data-sort-order', 'desc');
|
|
||||||
$('.sort-indicator', $cell).textContent = '▼';
|
|
||||||
} else if (sortOrder === 'desc') {
|
|
||||||
$cell.setAttribute('data-sort-order', 'none');
|
|
||||||
$('.sort-indicator', $cell).textContent = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// sortWith this action
|
|
||||||
sortOrder = $cell.getAttribute('data-sort-order');
|
|
||||||
|
|
||||||
if (self.events && self.events.onSort) {
|
|
||||||
self.events.onSort(colIndex, sortOrder);
|
|
||||||
} else {
|
|
||||||
self.sortRows(colIndex, sortOrder);
|
|
||||||
self.refreshRows();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sortRows(colIndex, sortOrder) {
|
|
||||||
this.datamanager.sortRows(colIndex, sortOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
bindCheckbox() {
|
|
||||||
if (!this.options.addCheckboxColumn) return;
|
|
||||||
|
|
||||||
$.on(this.wrapper, 'click', '.data-table-col[data-col-index="0"] [type="checkbox"]', (e, $checkbox) => {
|
|
||||||
const $cell = $checkbox.closest('.data-table-col');
|
|
||||||
const { rowIndex, isHeader } = this.getCellAttr($cell);
|
|
||||||
const checked = $checkbox.checked;
|
|
||||||
|
|
||||||
if (isHeader) {
|
|
||||||
this.checkAll(checked);
|
|
||||||
} else {
|
|
||||||
this.checkRow(rowIndex, checked);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getCheckedRows() {
|
|
||||||
return this.checkMap
|
|
||||||
.map((c, rowIndex) => {
|
|
||||||
if (c) {
|
|
||||||
return rowIndex;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.filter(c => {
|
|
||||||
return c !== null || c !== undefined;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
highlightCheckedRows() {
|
|
||||||
this.getCheckedRows()
|
|
||||||
.map(rowIndex => this.checkRow(rowIndex, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
checkRow(rowIndex, toggle) {
|
|
||||||
const value = toggle ? 1 : 0;
|
|
||||||
|
|
||||||
// update internal map
|
|
||||||
this.checkMap[rowIndex] = value;
|
|
||||||
// set checkbox value explicitly
|
|
||||||
$.each(`.data-table-col[data-row-index="${rowIndex}"][data-col-index="0"] [type="checkbox"]`, this.bodyScrollable)
|
|
||||||
.map(input => {
|
|
||||||
input.checked = toggle;
|
|
||||||
});
|
|
||||||
// highlight row
|
|
||||||
this.highlightRow(rowIndex, toggle);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAll(toggle) {
|
|
||||||
const value = toggle ? 1 : 0;
|
|
||||||
|
|
||||||
// update internal map
|
|
||||||
if (toggle) {
|
|
||||||
this.checkMap = Array.from(Array(this.getTotalRows())).map(c => value);
|
|
||||||
} else {
|
|
||||||
this.checkMap = [];
|
|
||||||
}
|
|
||||||
// set checkbox value
|
|
||||||
$.each('.data-table-col[data-col-index="0"] [type="checkbox"]', this.bodyScrollable)
|
|
||||||
.map(input => {
|
|
||||||
input.checked = toggle;
|
|
||||||
});
|
|
||||||
// highlight all
|
|
||||||
this.highlightAll(toggle);
|
|
||||||
}
|
|
||||||
|
|
||||||
highlightRow(rowIndex, toggle = true) {
|
|
||||||
const $row = $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
|
|
||||||
|
|
||||||
if (toggle) {
|
|
||||||
$row.classList.add('row-highlight');
|
|
||||||
} else {
|
|
||||||
$row.classList.remove('row-highlight');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
highlightAll(toggle = true) {
|
|
||||||
if (toggle) {
|
|
||||||
this.bodyScrollable.classList.add('row-highlight-all');
|
|
||||||
} else {
|
|
||||||
this.bodyScrollable.classList.remove('row-highlight-all');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setColumnWidth(colIndex, width) {
|
|
||||||
// set width for content
|
|
||||||
this.style.setStyle(`[data-col-index="${colIndex}"] .content`, {
|
|
||||||
width: width + 'px'
|
|
||||||
});
|
|
||||||
// set width for edit cell
|
|
||||||
this.style.setStyle(`[data-col-index="${colIndex}"] .edit-cell`, {
|
|
||||||
width: width + 'px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setColumnHeaderWidth(colIndex, width) {
|
|
||||||
this.style.setStyle(`[data-col-index="${colIndex}"][data-is-header] .content`, {
|
|
||||||
width: width + 'px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setDefaultCellHeight(height) {
|
|
||||||
this.style.setStyle('.data-table-col .content', {
|
|
||||||
height: height + 'px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setRowHeight(rowIndex, height) {
|
|
||||||
this.style.setStyle(`[data-row-index="${rowIndex}"] .content`, {
|
|
||||||
height: height + 'px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setColumnWidths() {
|
|
||||||
const availableWidth = this.wrapper.width();
|
|
||||||
const headerWidth = this.header.width();
|
|
||||||
|
|
||||||
if (headerWidth > availableWidth) {
|
|
||||||
// don't resize, horizontal scroll takes place
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns = this.datamanager.getColumns();
|
|
||||||
const deltaWidth = (availableWidth - headerWidth) / this.datamanager.getColumnCount();
|
|
||||||
|
|
||||||
columns.map(col => {
|
|
||||||
const width = $.style(this.getColumnHeaderElement(col.colIndex), 'width');
|
|
||||||
let finalWidth = width + deltaWidth - 16;
|
|
||||||
|
|
||||||
if (this.options.addSerialNoColumn && col.colIndex === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setColumnHeaderWidth(col.colIndex, finalWidth);
|
|
||||||
this.setColumnWidth(col.colIndex, finalWidth);
|
|
||||||
});
|
|
||||||
this.setBodyWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
setBodyWidth() {
|
setBodyWidth() {
|
||||||
const width = $.style(this.header, 'width');
|
const width = $.style(this.header, 'width');
|
||||||
|
|
||||||
$.style(this.bodyScrollable, { width });
|
$.style(this.bodyScrollable, { width: width + 'px' });
|
||||||
}
|
|
||||||
|
|
||||||
makeStyle() {
|
|
||||||
this.style = new Style(this.wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
getColumn(colIndex) {
|
|
||||||
return this.datamanager.getColumn(colIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
getRow(rowIndex) {
|
|
||||||
return this.datamanager.getRow(rowIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCell(colIndex, rowIndex) {
|
|
||||||
return this.datamanager.getCell(colIndex, rowIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getColumnHeaderElement(colIndex) {
|
getColumnHeaderElement(colIndex) {
|
||||||
colIndex = +colIndex;
|
return this.columnmanager.getColumnHeaderElement(colIndex);
|
||||||
if (colIndex < 0) return null;
|
|
||||||
return $(`.data-table-col[data-is-header][data-col-index="${colIndex}"]`, this.wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
getColumnMinWidth(colIndex) {
|
|
||||||
colIndex = +colIndex;
|
|
||||||
return this.minWidthMap && this.minWidthMap[colIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
getCellAttr($cell) {
|
|
||||||
return $.data($cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTotalRows() {
|
|
||||||
return this.datamanager.getRowCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLastRowIndex() {
|
|
||||||
return this.datamanager.getRowCount() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSerialColumnIndex() {
|
|
||||||
const columns = this.datamanager.getColumns();
|
|
||||||
|
|
||||||
return columns.findIndex(column => column.content.includes('Sr. No'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getViewportHeight() {
|
getViewportHeight() {
|
||||||
|
|||||||
10
src/dom.js
10
src/dom.js
@ -91,8 +91,14 @@ $.fire = (target, type, properties) => {
|
|||||||
return target.dispatchEvent(evt);
|
return target.dispatchEvent(evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
$.data = (element) => {
|
$.data = (element, attrs) => { // eslint-disable-line
|
||||||
return element.dataset;
|
if (!attrs) {
|
||||||
|
return element.dataset;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const attr in attrs) {
|
||||||
|
element.dataset[attr] = attrs[attr];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$.style = (elements, styleMap) => { // eslint-disable-line
|
$.style = (elements, styleMap) => { // eslint-disable-line
|
||||||
|
|||||||
120
src/rowmanager.js
Normal file
120
src/rowmanager.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import $ from './dom';
|
||||||
|
|
||||||
|
export default class RowManager {
|
||||||
|
constructor(instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
this.options = this.instance.options;
|
||||||
|
this.wrapper = this.instance.wrapper;
|
||||||
|
this.datamanager = this.instance.datamanager;
|
||||||
|
|
||||||
|
this.bindEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
bindEvents() {
|
||||||
|
this.bindCheckbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
bindCheckbox() {
|
||||||
|
if (!this.options.addCheckboxColumn) return;
|
||||||
|
|
||||||
|
// map of checked rows
|
||||||
|
this.checkMap = [];
|
||||||
|
|
||||||
|
$.on(this.wrapper, 'click', '.data-table-col[data-col-index="0"] [type="checkbox"]', (e, $checkbox) => {
|
||||||
|
const $cell = $checkbox.closest('.data-table-col');
|
||||||
|
const { rowIndex, isHeader } = $.data($cell);
|
||||||
|
const checked = $checkbox.checked;
|
||||||
|
|
||||||
|
if (isHeader) {
|
||||||
|
this.checkAll(checked);
|
||||||
|
} else {
|
||||||
|
this.checkRow(rowIndex, checked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshRows() {
|
||||||
|
this.instance.renderBody();
|
||||||
|
this.instance.setDimensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
getCheckedRows() {
|
||||||
|
return this.checkMap
|
||||||
|
.map((c, rowIndex) => {
|
||||||
|
if (c) {
|
||||||
|
return rowIndex;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter(c => {
|
||||||
|
return c !== null || c !== undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightCheckedRows() {
|
||||||
|
this.getCheckedRows()
|
||||||
|
.map(rowIndex => this.checkRow(rowIndex, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
checkRow(rowIndex, toggle) {
|
||||||
|
const value = toggle ? 1 : 0;
|
||||||
|
|
||||||
|
// update internal map
|
||||||
|
this.checkMap[rowIndex] = value;
|
||||||
|
// set checkbox value explicitly
|
||||||
|
$.each(`.data-table-col[data-row-index="${rowIndex}"][data-col-index="0"] [type="checkbox"]`, this.bodyScrollable)
|
||||||
|
.map(input => {
|
||||||
|
input.checked = toggle;
|
||||||
|
});
|
||||||
|
// highlight row
|
||||||
|
this.highlightRow(rowIndex, toggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAll(toggle) {
|
||||||
|
const value = toggle ? 1 : 0;
|
||||||
|
|
||||||
|
// update internal map
|
||||||
|
if (toggle) {
|
||||||
|
this.checkMap = Array.from(Array(this.getTotalRows())).map(c => value);
|
||||||
|
} else {
|
||||||
|
this.checkMap = [];
|
||||||
|
}
|
||||||
|
// set checkbox value
|
||||||
|
$.each('.data-table-col[data-col-index="0"] [type="checkbox"]', this.bodyScrollable)
|
||||||
|
.map(input => {
|
||||||
|
input.checked = toggle;
|
||||||
|
});
|
||||||
|
// highlight all
|
||||||
|
this.highlightAll(toggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightRow(rowIndex, toggle = true) {
|
||||||
|
const $row = $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
|
||||||
|
|
||||||
|
if (toggle) {
|
||||||
|
$row.classList.add('row-highlight');
|
||||||
|
} else {
|
||||||
|
$row.classList.remove('row-highlight');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightAll(toggle = true) {
|
||||||
|
if (toggle) {
|
||||||
|
this.bodyScrollable.classList.add('row-highlight-all');
|
||||||
|
} else {
|
||||||
|
this.bodyScrollable.classList.remove('row-highlight-all');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTotalRows() {
|
||||||
|
return this.datamanager.getRowCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
getFirstRowIndex() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastRowIndex() {
|
||||||
|
return this.datamanager.getRowCount() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -255,6 +255,10 @@ function copyTextToClipboard(text) {
|
|||||||
document.body.removeChild(textArea);
|
document.body.removeChild(textArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isNumeric(val) {
|
||||||
|
return !isNaN(val);
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getHeaderHTML,
|
getHeaderHTML,
|
||||||
getBodyHTML,
|
getBodyHTML,
|
||||||
@ -272,5 +276,6 @@ export default {
|
|||||||
escapeRegExp,
|
escapeRegExp,
|
||||||
getCellContent,
|
getCellContent,
|
||||||
copyTextToClipboard,
|
copyTextToClipboard,
|
||||||
camelCaseToDash
|
camelCaseToDash,
|
||||||
|
isNumeric
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user