// SPDX-FileCopyrightText: 2022 Sarah Vaupel // // 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)); } }