225 lines
6.1 KiB
JavaScript
225 lines
6.1 KiB
JavaScript
import $ from './dom';
|
|
import {
|
|
makeDataAttributeString,
|
|
promisify
|
|
} from './utils';
|
|
|
|
export default class RowManager {
|
|
constructor(instance) {
|
|
this.instance = instance;
|
|
this.options = this.instance.options;
|
|
this.wrapper = this.instance.wrapper;
|
|
this.bodyScrollable = this.instance.bodyScrollable;
|
|
|
|
this.bindEvents();
|
|
this.refreshRows = promisify(this.refreshRows, this);
|
|
}
|
|
|
|
get datamanager() {
|
|
return this.instance.datamanager;
|
|
}
|
|
|
|
get cellmanager() {
|
|
return this.instance.cellmanager;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
refreshRow(row, rowIndex) {
|
|
const _row = this.datamanager.updateRow(row, rowIndex);
|
|
|
|
_row.forEach(cell => {
|
|
this.cellmanager.refreshCell(cell);
|
|
});
|
|
}
|
|
|
|
getCheckedRows() {
|
|
if (!this.checkMap) {
|
|
return [];
|
|
}
|
|
|
|
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;
|
|
const selector = rowIndex =>
|
|
`.data-table-col[data-row-index="${rowIndex}"][data-col-index="0"] [type="checkbox"]`;
|
|
// update internal map
|
|
this.checkMap[rowIndex] = value;
|
|
// set checkbox value explicitly
|
|
$.each(selector(rowIndex), 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 = this.getRow$(rowIndex);
|
|
if (!$row) return;
|
|
|
|
if (!toggle && this.bodyScrollable.classList.contains('row-highlight-all')) {
|
|
$row.classList.add('row-unhighlight');
|
|
return;
|
|
}
|
|
|
|
if (toggle && $row.classList.contains('row-unhighlight')) {
|
|
$row.classList.remove('row-unhighlight');
|
|
}
|
|
|
|
this._highlightedRows = this._highlightedRows || {};
|
|
|
|
if (toggle) {
|
|
$row.classList.add('row-highlight');
|
|
this._highlightedRows[rowIndex] = $row;
|
|
} else {
|
|
$row.classList.remove('row-highlight');
|
|
delete this._highlightedRows[rowIndex];
|
|
}
|
|
}
|
|
|
|
highlightAll(toggle = true) {
|
|
if (toggle) {
|
|
this.bodyScrollable.classList.add('row-highlight-all');
|
|
} else {
|
|
this.bodyScrollable.classList.remove('row-highlight-all');
|
|
for (const rowIndex in this._highlightedRows) {
|
|
const $row = this._highlightedRows[rowIndex];
|
|
$row.classList.remove('row-highlight');
|
|
}
|
|
this._highlightedRows = {};
|
|
}
|
|
}
|
|
|
|
getRow$(rowIndex) {
|
|
return $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
|
|
}
|
|
|
|
getTotalRows() {
|
|
return this.datamanager.getRowCount();
|
|
}
|
|
|
|
getFirstRowIndex() {
|
|
return 0;
|
|
}
|
|
|
|
getLastRowIndex() {
|
|
return this.datamanager.getRowCount() - 1;
|
|
}
|
|
|
|
scrollToRow(rowIndex) {
|
|
rowIndex = +rowIndex;
|
|
this._lastScrollTo = this._lastScrollTo || 0;
|
|
const $row = this.getRow$(rowIndex);
|
|
if ($.inViewport($row, this.bodyScrollable)) return;
|
|
|
|
const {
|
|
height
|
|
} = $row.getBoundingClientRect();
|
|
const {
|
|
top,
|
|
bottom
|
|
} = this.bodyScrollable.getBoundingClientRect();
|
|
const rowsInView = Math.floor((bottom - top) / height);
|
|
|
|
let offset = 0;
|
|
if (rowIndex > this._lastScrollTo) {
|
|
offset = height * ((rowIndex + 1) - rowsInView);
|
|
} else {
|
|
offset = height * ((rowIndex + 1) - 1);
|
|
}
|
|
|
|
this._lastScrollTo = rowIndex;
|
|
$.scrollTop(this.bodyScrollable, offset);
|
|
}
|
|
|
|
getRowHTML(row, props) {
|
|
const dataAttr = makeDataAttributeString(props);
|
|
|
|
if (props.isFilter) {
|
|
row = row.map(cell => (Object.assign(cell, {
|
|
content: this.getFilterInput({
|
|
colIndex: cell.colIndex
|
|
}),
|
|
isFilter: 1,
|
|
isHeader: undefined,
|
|
editable: false
|
|
})));
|
|
}
|
|
|
|
return `
|
|
<tr class="data-table-row" ${dataAttr}>
|
|
${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')}
|
|
</tr>
|
|
`;
|
|
}
|
|
|
|
getFilterInput(props) {
|
|
const dataAttr = makeDataAttributeString(props);
|
|
return `<input class="data-table-filter input-style" type="text" ${dataAttr} />`;
|
|
}
|
|
}
|