From 86e4b662ce6af926e0d1d3d00266efcdae8aebc0 Mon Sep 17 00:00:00 2001 From: justusaac <72957314+justusaac@users.noreply.github.com> Date: Sat, 10 May 2025 03:08:19 -0500 Subject: [PATCH] WebUI: Select multiple files to rename with Shift Convenience feature in the "Rename Files" menu in the WebUI. If you click one file's checkbox, and then click another with Shift held, all the checkboxes between those two will be selected/unselected based on the state of the first checkbox. It's based on what the Windows file explorer does when holding Ctrl and Shift Closes #22455. PR #22610. --- src/webui/www/private/scripts/dynamicTable.js | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index fdbbca346..ac38ee42a 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -2185,6 +2185,7 @@ window.qBittorrent.DynamicTable ??= (() => { prevFilteredRows = []; prevSortedColumn = null; prevReverseSort = null; + prevCheckboxNum = null; fileTree = new window.qBittorrent.FileTree.FileTree(); setupVirtualList() { @@ -2344,13 +2345,41 @@ window.qBittorrent.DynamicTable ??= (() => { checkbox.type = "checkbox"; checkbox.className = "RenamingCB"; checkbox.addEventListener("click", (e) => { - const id = e.target.dataset.id; - const node = that.getNode(id); - node.checked = e.target.checked ? 0 : 1; - node.full_data.checked = node.checked; - that.updateGlobalCheckbox(); - that.onRowSelectionChange(node); e.stopPropagation(); + const targetId = e.target.dataset.id; + const ids = []; + // when holding shift, set all files between the previously selected one and the clicked one + if (e.shiftKey && (that.prevCheckboxNum !== null) && (targetId !== that.prevCheckboxNum)) { + const targetState = that.tableBody.querySelector(`.RenamingCB[data-id="${that.prevCheckboxNum}"]`).checked; + const checkboxes = that.tableBody.getElementsByClassName("RenamingCB"); + let started = false; + for (const cb of checkboxes) { + const currId = cb.dataset.id; + if ((currId === targetId) || (currId === that.prevCheckboxNum)) { + if (started) { + ids.push(currId); + cb.checked = targetState; + break; + } + started = true; + } + if (started) { + ids.push(currId); + cb.checked = targetState; + } + } + } + else { + ids.push(targetId); + } + for (const id of ids) { + const node = that.getNode(id); + node.checked = e.target.checked ? 0 : 1; + node.full_data.checked = node.checked; + } + that.updateGlobalCheckbox(); + that.onRowSelectionChange(that.getNode(targetId)); + that.prevCheckboxNum = targetId; }); checkbox.indeterminate = false; td.append(checkbox);