fix: checkbox in toolbar does not select all files (Fixes #25)

This commit is contained in:
Ryan
2025-04-27 15:34:41 -04:00
committed by GitHub
parent 41ade2e205
commit ae0d63b86f
3 changed files with 75 additions and 44 deletions

View File

@@ -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`, refetch CSRF *again* before calling `openTOTPLoginModal()`
3. On `totp_required`, refetch 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.
---

View File

@@ -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) {

View File

@@ -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;"></label>
<div class="gallery-preview" style="cursor:pointer;"
data-preview-url="${folderPath+encodeURIComponent(file.name)}?t=${Date.now()}"
data-preview-url="${folderPath + encodeURIComponent(file.name)}?t=${Date.now()}"
data-preview-name="${file.name}">
${thumbnail}
</div>
@@ -590,20 +598,20 @@ export function renderGalleryView(folder, container) {
<div class="button-wrap" style="display:flex; justify-content:center; gap:5px; margin-top:5px;">
<button type="button" class="btn btn-sm btn-success download-btn"
data-download-name="${escapeHTML(file.name)}"
data-download-folder="${file.folder||"root"}"
data-download-folder="${file.folder || "root"}"
title="${t('download')}">
<i class="material-icons">file_download</i>
</button>
${file.editable ? `
<button type="button" class="btn btn-sm edit-btn"
data-edit-name="${escapeHTML(file.name)}"
data-edit-folder="${file.folder||"root"}"
data-edit-folder="${file.folder || "root"}"
title="${t('edit')}">
<i class="material-icons">edit</i>
</button>` : ""}
<button type="button" class="btn btn-sm btn-warning rename-btn"
data-rename-name="${escapeHTML(file.name)}"
data-rename-folder="${file.folder||"root"}"
data-rename-folder="${file.folder || "root"}"
title="${t('rename')}">
<i class="material-icons">drive_file_rename_outline</i>
</button>