From ae0d63b86f4785fa4d35b3359ed4e782f479d0fb Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 27 Apr 2025 15:34:41 -0400 Subject: [PATCH] fix: checkbox in toolbar does not select all files (Fixes #25) --- CHANGELOG.md | 13 +++++- public/js/domUtils.js | 20 +++++++-- public/js/fileListView.js | 86 +++++++++++++++++++++------------------ 3 files changed, 75 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fa59c1..e0414f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## Changes 4/27/2025 + +- **Select-All** checkbox now correctly toggles all `.file-checkbox` inputs + - Updated `toggleAllCheckboxes(masterCheckbox)` to call `updateRowHighlight()` on each row so selections get the `.row-selected` highlight +- **Master checkbox sync** in toolbar + - Enhanced `updateFileActionButtons()` to set the header checkbox to checked, unchecked, or indeterminate based on how many files are selected + +--- + ## Changes 4/26/2025 1.2.6 **Apache / Dockerfile (CSP)** @@ -210,7 +219,7 @@ Refactored to: 1. Fetch CSRF 2. POST credentials to `/api/auth/auth.php` - 3. On `totp_required`, re‑fetch CSRF *again* before calling `openTOTPLoginModal()` + 3. On `totp_required`, re‑fetch CSRF again before calling `openTOTPLoginModal()` 4. Handle full logins vs. TOTP flows cleanly. - **TOTP handlers update** @@ -1156,7 +1165,7 @@ The enhancements extend the existing drag-and-drop functionality by adding a hea - Adjusted file preview and icon styling for better alignment. - Centered the header and optimized the layout for a clean, modern appearance. -*This changelog and feature summary reflect the improvements made during the refactor from a monolithic utils file to modular ES6 components, along with enhancements in UI responsiveness, sorting, file uploads, and file management operations.* +This changelog and feature summary reflect the improvements made during the refactor from a monolithic utils file to modular ES6 components, along with enhancements in UI responsiveness, sorting, file uploads, and file management operations. --- diff --git a/public/js/domUtils.js b/public/js/domUtils.js index 905af8a..29fa737 100644 --- a/public/js/domUtils.js +++ b/public/js/domUtils.js @@ -25,8 +25,9 @@ export function toggleAllCheckboxes(masterCheckbox) { const checkboxes = document.querySelectorAll(".file-checkbox"); checkboxes.forEach(chk => { chk.checked = masterCheckbox.checked; + updateRowHighlight(chk); }); - updateFileActionButtons(); // update buttons based on current selection + updateFileActionButtons(); } export function updateFileActionButtons() { @@ -38,6 +39,21 @@ export function updateFileActionButtons() { const zipBtn = document.getElementById("downloadZipBtn"); const extractZipBtn = document.getElementById("extractZipBtn"); + // keep the “select all” in sync —— + const master = document.getElementById("selectAll"); + if (master) { + if (selectedCheckboxes.length === fileCheckboxes.length) { + master.checked = true; + master.indeterminate = false; + } else if (selectedCheckboxes.length === 0) { + master.checked = false; + master.indeterminate = false; + } else { + master.checked = false; + master.indeterminate = true; + } + } + if (fileCheckboxes.length === 0) { if (copyBtn) copyBtn.style.display = "none"; if (moveBtn) moveBtn.style.display = "none"; @@ -271,8 +287,6 @@ export function toggleRowSelection(event, fileName) { const start = Math.min(currentIndex, lastIndex); const end = Math.max(currentIndex, lastIndex); - // If neither CTRL nor Meta is pressed, you might choose - // to clear existing selections. For this example we leave existing selections intact. for (let i = start; i <= end; i++) { const cb = allRows[i].querySelector(".file-checkbox"); if (cb) { diff --git a/public/js/fileListView.js b/public/js/fileListView.js index f039cb7..8cb2128 100644 --- a/public/js/fileListView.js +++ b/public/js/fileListView.js @@ -340,47 +340,55 @@ export function renderFileTable(folder, container) { fileListContent.innerHTML = combinedTopHTML + headerHTML + rowsHTML + bottomControlsHTML; + // hook up the master checkbox + const selectAll = document.getElementById("selectAll"); + if (selectAll) { + selectAll.addEventListener("change", () => { + toggleAllCheckboxes(selectAll); + }); + } + // 1) Row-click selects the row -fileListContent.querySelectorAll("tbody tr").forEach(row => { - row.addEventListener("click", e => { - // grab the underlying checkbox value - const cb = row.querySelector(".file-checkbox"); - if (!cb) return; - toggleRowSelection(e, cb.value); + fileListContent.querySelectorAll("tbody tr").forEach(row => { + row.addEventListener("click", e => { + // grab the underlying checkbox value + const cb = row.querySelector(".file-checkbox"); + if (!cb) return; + toggleRowSelection(e, cb.value); + }); }); - }); - - // 2) Download buttons - fileListContent.querySelectorAll(".download-btn").forEach(btn => { - btn.addEventListener("click", e => { - e.stopPropagation(); - openDownloadModal(btn.dataset.downloadName, btn.dataset.downloadFolder); + + // 2) Download buttons + fileListContent.querySelectorAll(".download-btn").forEach(btn => { + btn.addEventListener("click", e => { + e.stopPropagation(); + openDownloadModal(btn.dataset.downloadName, btn.dataset.downloadFolder); + }); }); - }); - - // 3) Edit buttons - fileListContent.querySelectorAll(".edit-btn").forEach(btn => { - btn.addEventListener("click", e => { - e.stopPropagation(); - editFile(btn.dataset.editName, btn.dataset.editFolder); + + // 3) Edit buttons + fileListContent.querySelectorAll(".edit-btn").forEach(btn => { + btn.addEventListener("click", e => { + e.stopPropagation(); + editFile(btn.dataset.editName, btn.dataset.editFolder); + }); }); - }); - - // 4) Rename buttons - fileListContent.querySelectorAll(".rename-btn").forEach(btn => { - btn.addEventListener("click", e => { - e.stopPropagation(); - renameFile(btn.dataset.renameName, btn.dataset.renameFolder); + + // 4) Rename buttons + fileListContent.querySelectorAll(".rename-btn").forEach(btn => { + btn.addEventListener("click", e => { + e.stopPropagation(); + renameFile(btn.dataset.renameName, btn.dataset.renameFolder); + }); }); - }); - - // 5) Preview buttons (if you still have a .preview-btn) - fileListContent.querySelectorAll(".preview-btn").forEach(btn => { - btn.addEventListener("click", e => { - e.stopPropagation(); - previewFile(btn.dataset.previewUrl, btn.dataset.previewName); + + // 5) Preview buttons (if you still have a .preview-btn) + fileListContent.querySelectorAll(".preview-btn").forEach(btn => { + btn.addEventListener("click", e => { + e.stopPropagation(); + previewFile(btn.dataset.previewUrl, btn.dataset.previewName); + }); }); - }); createViewToggleButton(); @@ -575,7 +583,7 @@ export function renderGalleryView(folder, container) { style="position:absolute; top:5px; left:5px; width:16px; height:16px;"> @@ -590,20 +598,20 @@ export function renderGalleryView(folder, container) {
${file.editable ? ` ` : ""}