Add RowManager and ColumnManager

This commit is contained in:
Faris Ansari 2017-11-06 18:25:07 +05:30
parent 785cf8f466
commit 0ccc3627ae
9 changed files with 1348 additions and 1075 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -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
View 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'));
}
}

View File

@ -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) {

View File

@ -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() {

View File

@ -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
View 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;
}
}

View File

@ -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
}; };