From 1bce53a9a3531ca44afbd5af432b7ad710834da6 Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Wed, 10 Jan 2024 14:08:47 -0500 Subject: [PATCH 1/2] added multi select added multi select --- changes/add_GLT-4047 | 1 + ts/component/table-builder.ts | 80 ++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 changes/add_GLT-4047 diff --git a/changes/add_GLT-4047 b/changes/add_GLT-4047 new file mode 100644 index 00000000..866d5059 --- /dev/null +++ b/changes/add_GLT-4047 @@ -0,0 +1 @@ +Range selection by allowing users to click a row, hold the Shift key, and click another row, thereby toggling the selection state of all rows in between \ No newline at end of file diff --git a/ts/component/table-builder.ts b/ts/component/table-builder.ts index 8e9bd2c1..e988392d 100644 --- a/ts/component/table-builder.ts +++ b/ts/component/table-builder.ts @@ -134,6 +134,7 @@ export class TableBuilder { selectedItems: Set = new Set(); selectAllCheckbox?: HTMLInputElement; onFilterChange?: (key: string, value: string, add: boolean) => void; + lastClickedRowIndex: number | null = null; constructor( definition: TableDefinition, @@ -164,6 +165,17 @@ export class TableBuilder { this.onFilterChange = onFilterChange; this.container = container; this.columns = definition.generateColumns(); + document.addEventListener("keydown", (event: KeyboardEvent) => { + if (event.key === "Shift") { + this.isShiftKeyPressed = true; + } + }); + + document.addEventListener("keyup", (event: KeyboardEvent) => { + if (event.key === "Shift") { + this.isShiftKeyPressed = false; + } + }); } public applyFilter(key: string, value: string, add: boolean) { @@ -662,7 +674,7 @@ export class TableBuilder { private addTableBody(table: HTMLTableElement, data?: ParentType[]) { if (data && data.length) { let previousSubheading: string | null = null; - data.forEach((parent) => { + data.forEach((parent, index) => { if (this.definition.getSubheading) { const currentSubheading = this.definition.getSubheading(parent); if (currentSubheading !== previousSubheading) { @@ -670,7 +682,7 @@ export class TableBuilder { previousSubheading = currentSubheading; } } - this.addDataRow(table, parent); + this.addDataRow(table, parent, index); }); } else { this.addNoDataRow(table); @@ -774,7 +786,11 @@ export class TableBuilder { th.appendChild(document.createTextNode(text || "Other")); } - private addDataRow(table: HTMLTableElement, parent: ParentType) { + private addDataRow( + table: HTMLTableElement, + parent: ParentType, + rowIndex: number + ) { let children: ChildType[] = []; if (this.definition.getChildren) { children = this.definition.getChildren(parent); @@ -784,7 +800,7 @@ export class TableBuilder { tbody.classList.add("nobreak"); const tr = this.addBodyRow(tbody, parent); if (this.definition.bulkActions) { - this.addRowSelectCell(tr, parent); + this.addRowSelectCell(tr, parent, rowIndex); } this.columns.forEach((column, i) => { if (column.child) { @@ -839,24 +855,68 @@ export class TableBuilder { cell.appendChild(document.createTextNode("NO DATA")); } - private addRowSelectCell(tr: HTMLTableRowElement, item: ParentType) { + private isShiftKeyPressed: boolean = false; + + private addRowSelectCell( + tr: HTMLTableRowElement, + item: ParentType, + rowIndex: number + ) { const td = makeCell(tr, true); const checkbox = document.createElement("input"); checkbox.className = "row-select"; checkbox.type = "checkbox"; + checkbox.onchange = (event) => { - if (checkbox.checked) { - this.selectedItems.add(item); + const currentRowIndex = rowIndex; + + if (this.isShiftKeyPressed && this.lastClickedRowIndex !== null) { + this.toggleRange( + this.lastClickedRowIndex, + currentRowIndex, + checkbox.checked + ); } else { - if (this.selectAllCheckbox) { - this.selectAllCheckbox.checked = false; - this.selectedItems.delete(item); + if (checkbox.checked) { + this.selectedItems.add(item); + } else { + if (this.selectAllCheckbox) { + this.selectAllCheckbox.checked = false; + this.selectedItems.delete(item); + } } } + this.lastClickedRowIndex = currentRowIndex; }; + td.appendChild(checkbox); } + private toggleRange( + startIndex: number, + endIndex: number, + isSelected: boolean + ) { + const [minIndex, maxIndex] = [ + Math.min(startIndex, endIndex), + Math.max(startIndex, endIndex), + ]; + + const rowSelects = this.container.getElementsByClassName("row-select"); + for (let i = minIndex; i <= maxIndex; i++) { + const rowSelect = rowSelects[i] as HTMLInputElement; + if (rowSelect) { + rowSelect.checked = isSelected; + const item = this.allItems[i]; + if (isSelected) { + this.selectedItems.add(item); + } else { + this.selectedItems.delete(item); + } + } + } + } + private addParentCell( tr: HTMLTableRowElement, column: ColumnDefinition, From 1e71e91dec1b52ef044544a06a41df64b42a0938 Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Fri, 19 Jan 2024 13:35:35 -0500 Subject: [PATCH 2/2] updated with main + fixups --- ts/component/table-builder.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ts/component/table-builder.ts b/ts/component/table-builder.ts index e988392d..bf40f4a3 100644 --- a/ts/component/table-builder.ts +++ b/ts/component/table-builder.ts @@ -135,6 +135,7 @@ export class TableBuilder { selectAllCheckbox?: HTMLInputElement; onFilterChange?: (key: string, value: string, add: boolean) => void; lastClickedRowIndex: number | null = null; + private isShiftKeyPressed: boolean = false; constructor( definition: TableDefinition, @@ -855,8 +856,6 @@ export class TableBuilder { cell.appendChild(document.createTextNode("NO DATA")); } - private isShiftKeyPressed: boolean = false; - private addRowSelectCell( tr: HTMLTableRowElement, item: ParentType,