From 337bf73067f2b98450d0388a1c064f0d2f9c456c Mon Sep 17 00:00:00 2001 From: Johannes Eder Date: Tue, 21 Sep 2021 17:17:22 +0200 Subject: [PATCH] feat(checkrange): new util checkrange --- frontend/src/utils/inputs/checkrange.js | 97 +++++++++++++++++++++++++ frontend/src/utils/inputs/inputs.js | 2 + 2 files changed, 99 insertions(+) create mode 100644 frontend/src/utils/inputs/checkrange.js diff --git a/frontend/src/utils/inputs/checkrange.js b/frontend/src/utils/inputs/checkrange.js new file mode 100644 index 000000000..c65475b3a --- /dev/null +++ b/frontend/src/utils/inputs/checkrange.js @@ -0,0 +1,97 @@ +import { Utility } from '../../core/utility'; +import { TableIndices } from '../../lib/table/table'; + + +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 All 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) { + let column = this._columns[columnId]; + 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); + if(currentCellIndex > lastClickedIndex) + this._checkMultipleCells(lastClickedIndex, currentCellIndex, columnId); + else + this._checkMultipleCells(currentCellIndex, lastClickedIndex, columnId); + } else { + this._lastCheckedCell = el; + } + })); + } + + _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; + } + } + } + + + _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)); + } +} \ No newline at end of file diff --git a/frontend/src/utils/inputs/inputs.js b/frontend/src/utils/inputs/inputs.js index a072c2196..13d241895 100644 --- a/frontend/src/utils/inputs/inputs.js +++ b/frontend/src/utils/inputs/inputs.js @@ -2,6 +2,7 @@ import { Checkbox } from './checkbox'; import { FileInput } from './file-input'; import { FileMaxSize } from './file-max-size'; import { Password } from './password'; +import { CheckRange } from './checkrange'; import './inputs.sass'; import './radio-group.sass'; @@ -11,4 +12,5 @@ export const InputUtils = [ FileInput, FileMaxSize, Password, + CheckRange, ];