fradrive/frontend/src/utils/inputs/checkrange.js
2022-10-12 09:35:16 +02:00

129 lines
4.1 KiB
JavaScript

// SPDX-FileCopyrightText: 2022 Sarah Vaupel <sarah.vaupel@ifi.lmu.de>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
import { Utility } from '../../core/utility';
import { TableIndices } from '../../lib/table/table';
import { FrontendTooltips } from '../../lib/tooltips/frontend-tooltips';
import { Translations } from '../../messages';
const CHECKRANGE_INITIALIZED_CLASS = 'checkrange--initialized';
const CHECKBOX_SELECTOR = '[type="checkbox"]';
@Utility({
selector: 'table:not([uw-no-check-all])',
})
export class CheckRange {
_lastCheckedCell = null;
_element;
_tableIndices;
_columns = new Array();
constructor(element) {
if(!element) {
throw new Error('Check Range Utility cannot be setup without an element');
}
this._element = element;
if (this._element.classList.contains(CHECKRANGE_INITIALIZED_CLASS))
return false;
this._tableIndices = new TableIndices(this._element);
this._gatherColumns();
let checkboxColumns = this._findCheckboxColumns();
checkboxColumns.forEach(columnId => this._setUpShiftClickOnColumn(columnId));
this._element.classList.add(CHECKRANGE_INITIALIZED_CLASS);
}
_setUpShiftClickOnColumn(columnId) {
if (!this._columns || columnId < 0 || columnId >= this._columns.length) return;
let column = this._columns[columnId];
let language = document.documentElement.lang;
let toolTipMessage = Translations.getTranslation('checkrangeTooltip', language);
FrontendTooltips.addToolTip(column[0], toolTipMessage);
column.forEach(el => el.addEventListener('click', (ev) => {
if(ev.shiftKey && this.lastCheckedCell !== null) {
let lastClickedIndex = this._tableIndices.rowIndex(this._lastCheckedCell);
let currentCellIndex = this._tableIndices.rowIndex(el);
let cell = this._columns[columnId][currentCellIndex];
if(currentCellIndex > lastClickedIndex)
this._handleCellsInBetween(cell, lastClickedIndex, currentCellIndex, columnId);
else
this._handleCellsInBetween(cell, currentCellIndex, lastClickedIndex, columnId);
} else {
this._lastCheckedCell = el;
}
}));
}
_handleCellsInBetween(cell, firstRowIndex, lastRowIndex, columnId) {
if(this._isChecked(cell)) {
this._uncheckMultipleCells(firstRowIndex, lastRowIndex, columnId);
} else {
this._checkMultipleCells(firstRowIndex, lastRowIndex, columnId);
}
}
_checkMultipleCells(firstRowIndex, lastRowIndex, columnId) {
for(let i=firstRowIndex; i<=lastRowIndex; i++) {
let cell = this._columns[columnId][i];
if (cell.tagName !== 'TH') {
cell.querySelector(CHECKBOX_SELECTOR).checked = true;
}
}
}
_uncheckMultipleCells(firstRowIndex, lastRowIndex, columnId) {
for(let i=firstRowIndex; i<=lastRowIndex; i++) {
let cell = this._columns[columnId][i];
if (cell.tagName !== 'TH') {
cell.querySelector(CHECKBOX_SELECTOR).checked = false;
}
}
}
_isChecked(cell) {
return cell.querySelector(CHECKBOX_SELECTOR).checked;
}
_gatherColumns() {
for (const rowIndex of Array(this._tableIndices.maxRow + 1).keys()) {
for (const colIndex of Array(this._tableIndices.maxCol + 1).keys()) {
const cell = this._tableIndices.getCell(rowIndex, colIndex);
if (!cell)
continue;
if (!this._columns[colIndex])
this._columns[colIndex] = new Array();
this._columns[colIndex][rowIndex] = cell;
}
}
}
_findCheckboxColumns() {
let checkboxColumnIds = new Array();
this._columns.forEach((col, i) => {
if (this._isCheckboxColumn(col)) {
checkboxColumnIds.push(i);
}
});
return checkboxColumnIds;
}
_isCheckboxColumn(col) {
return col.every(cell => cell.tagName == 'TH' || cell.querySelector(CHECKBOX_SELECTOR))
&& col.some(cell => cell.querySelector(CHECKBOX_SELECTOR));
}
}