From be7cfeedda64e185dfc1053f0755a2784e5ce0da Mon Sep 17 00:00:00 2001 From: justusaac Date: Thu, 24 Apr 2025 23:34:17 -0500 Subject: [PATCH] WebUI: Select multiple files to rename with Shift Convenience feature in the "Rename Files..." menu in the Web UI. If you click one file 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. Closes #22455 --- src/webui/www/private/scripts/dynamicTable.js | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index d05cd8c53..4305c74c2 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -2194,6 +2194,7 @@ window.qBittorrent.DynamicTable ??= (() => { prevFilteredRows: [], prevSortedColumn: null, prevReverseSort: null, + prevCheckboxNum: null, fileTree: new window.qBittorrent.FileTree.FileTree(), setupVirtualList: function() { @@ -2354,13 +2355,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; + 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(node); + that.onRowSelectionChange(that.getNode(targetId)); e.stopPropagation(); + that.prevCheckboxNum = targetId; }); checkbox.indeterminate = false; td.append(checkbox);