fix: checkbox in toolbar does not select all files (Fixes #25)
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,5 +1,14 @@
|
|||||||
# Changelog
|
# 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
|
## Changes 4/26/2025 1.2.6
|
||||||
|
|
||||||
**Apache / Dockerfile (CSP)**
|
**Apache / Dockerfile (CSP)**
|
||||||
@@ -210,7 +219,7 @@
|
|||||||
Refactored to:
|
Refactored to:
|
||||||
1. Fetch CSRF
|
1. Fetch CSRF
|
||||||
2. POST credentials to `/api/auth/auth.php`
|
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.
|
4. Handle full logins vs. TOTP flows cleanly.
|
||||||
|
|
||||||
- **TOTP handlers update**
|
- **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.
|
- Adjusted file preview and icon styling for better alignment.
|
||||||
- Centered the header and optimized the layout for a clean, modern appearance.
|
- 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ export function toggleAllCheckboxes(masterCheckbox) {
|
|||||||
const checkboxes = document.querySelectorAll(".file-checkbox");
|
const checkboxes = document.querySelectorAll(".file-checkbox");
|
||||||
checkboxes.forEach(chk => {
|
checkboxes.forEach(chk => {
|
||||||
chk.checked = masterCheckbox.checked;
|
chk.checked = masterCheckbox.checked;
|
||||||
|
updateRowHighlight(chk);
|
||||||
});
|
});
|
||||||
updateFileActionButtons(); // update buttons based on current selection
|
updateFileActionButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateFileActionButtons() {
|
export function updateFileActionButtons() {
|
||||||
@@ -38,6 +39,21 @@ export function updateFileActionButtons() {
|
|||||||
const zipBtn = document.getElementById("downloadZipBtn");
|
const zipBtn = document.getElementById("downloadZipBtn");
|
||||||
const extractZipBtn = document.getElementById("extractZipBtn");
|
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 (fileCheckboxes.length === 0) {
|
||||||
if (copyBtn) copyBtn.style.display = "none";
|
if (copyBtn) copyBtn.style.display = "none";
|
||||||
if (moveBtn) moveBtn.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 start = Math.min(currentIndex, lastIndex);
|
||||||
const end = Math.max(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++) {
|
for (let i = start; i <= end; i++) {
|
||||||
const cb = allRows[i].querySelector(".file-checkbox");
|
const cb = allRows[i].querySelector(".file-checkbox");
|
||||||
if (cb) {
|
if (cb) {
|
||||||
|
|||||||
@@ -340,47 +340,55 @@ export function renderFileTable(folder, container) {
|
|||||||
|
|
||||||
fileListContent.innerHTML = combinedTopHTML + headerHTML + rowsHTML + bottomControlsHTML;
|
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
|
// 1) Row-click selects the row
|
||||||
fileListContent.querySelectorAll("tbody tr").forEach(row => {
|
fileListContent.querySelectorAll("tbody tr").forEach(row => {
|
||||||
row.addEventListener("click", e => {
|
row.addEventListener("click", e => {
|
||||||
// grab the underlying checkbox value
|
// grab the underlying checkbox value
|
||||||
const cb = row.querySelector(".file-checkbox");
|
const cb = row.querySelector(".file-checkbox");
|
||||||
if (!cb) return;
|
if (!cb) return;
|
||||||
toggleRowSelection(e, cb.value);
|
toggleRowSelection(e, cb.value);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
// 2) Download buttons
|
||||||
// 2) Download buttons
|
fileListContent.querySelectorAll(".download-btn").forEach(btn => {
|
||||||
fileListContent.querySelectorAll(".download-btn").forEach(btn => {
|
btn.addEventListener("click", e => {
|
||||||
btn.addEventListener("click", e => {
|
e.stopPropagation();
|
||||||
e.stopPropagation();
|
openDownloadModal(btn.dataset.downloadName, btn.dataset.downloadFolder);
|
||||||
openDownloadModal(btn.dataset.downloadName, btn.dataset.downloadFolder);
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
// 3) Edit buttons
|
||||||
// 3) Edit buttons
|
fileListContent.querySelectorAll(".edit-btn").forEach(btn => {
|
||||||
fileListContent.querySelectorAll(".edit-btn").forEach(btn => {
|
btn.addEventListener("click", e => {
|
||||||
btn.addEventListener("click", e => {
|
e.stopPropagation();
|
||||||
e.stopPropagation();
|
editFile(btn.dataset.editName, btn.dataset.editFolder);
|
||||||
editFile(btn.dataset.editName, btn.dataset.editFolder);
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
// 4) Rename buttons
|
||||||
// 4) Rename buttons
|
fileListContent.querySelectorAll(".rename-btn").forEach(btn => {
|
||||||
fileListContent.querySelectorAll(".rename-btn").forEach(btn => {
|
btn.addEventListener("click", e => {
|
||||||
btn.addEventListener("click", e => {
|
e.stopPropagation();
|
||||||
e.stopPropagation();
|
renameFile(btn.dataset.renameName, btn.dataset.renameFolder);
|
||||||
renameFile(btn.dataset.renameName, btn.dataset.renameFolder);
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
// 5) Preview buttons (if you still have a .preview-btn)
|
||||||
// 5) Preview buttons (if you still have a .preview-btn)
|
fileListContent.querySelectorAll(".preview-btn").forEach(btn => {
|
||||||
fileListContent.querySelectorAll(".preview-btn").forEach(btn => {
|
btn.addEventListener("click", e => {
|
||||||
btn.addEventListener("click", e => {
|
e.stopPropagation();
|
||||||
e.stopPropagation();
|
previewFile(btn.dataset.previewUrl, btn.dataset.previewName);
|
||||||
previewFile(btn.dataset.previewUrl, btn.dataset.previewName);
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
createViewToggleButton();
|
createViewToggleButton();
|
||||||
|
|
||||||
@@ -575,7 +583,7 @@ export function renderGalleryView(folder, container) {
|
|||||||
style="position:absolute; top:5px; left:5px; width:16px; height:16px;"></label>
|
style="position:absolute; top:5px; left:5px; width:16px; height:16px;"></label>
|
||||||
|
|
||||||
<div class="gallery-preview" style="cursor:pointer;"
|
<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}">
|
data-preview-name="${file.name}">
|
||||||
${thumbnail}
|
${thumbnail}
|
||||||
</div>
|
</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;">
|
<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"
|
<button type="button" class="btn btn-sm btn-success download-btn"
|
||||||
data-download-name="${escapeHTML(file.name)}"
|
data-download-name="${escapeHTML(file.name)}"
|
||||||
data-download-folder="${file.folder||"root"}"
|
data-download-folder="${file.folder || "root"}"
|
||||||
title="${t('download')}">
|
title="${t('download')}">
|
||||||
<i class="material-icons">file_download</i>
|
<i class="material-icons">file_download</i>
|
||||||
</button>
|
</button>
|
||||||
${file.editable ? `
|
${file.editable ? `
|
||||||
<button type="button" class="btn btn-sm edit-btn"
|
<button type="button" class="btn btn-sm edit-btn"
|
||||||
data-edit-name="${escapeHTML(file.name)}"
|
data-edit-name="${escapeHTML(file.name)}"
|
||||||
data-edit-folder="${file.folder||"root"}"
|
data-edit-folder="${file.folder || "root"}"
|
||||||
title="${t('edit')}">
|
title="${t('edit')}">
|
||||||
<i class="material-icons">edit</i>
|
<i class="material-icons">edit</i>
|
||||||
</button>` : ""}
|
</button>` : ""}
|
||||||
<button type="button" class="btn btn-sm btn-warning rename-btn"
|
<button type="button" class="btn btn-sm btn-warning rename-btn"
|
||||||
data-rename-name="${escapeHTML(file.name)}"
|
data-rename-name="${escapeHTML(file.name)}"
|
||||||
data-rename-folder="${file.folder||"root"}"
|
data-rename-folder="${file.folder || "root"}"
|
||||||
title="${t('rename')}">
|
title="${t('rename')}">
|
||||||
<i class="material-icons">drive_file_rename_outline</i>
|
<i class="material-icons">drive_file_rename_outline</i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user