This commit is contained in:
@@ -40,6 +40,9 @@
|
||||
<input class="form-check-input" type="checkbox" id="recursiveToggle">
|
||||
<label class="form-check-label" for="recursiveToggle">Recursive Scan (Subfolders)</label>
|
||||
</div>
|
||||
<button class="btn btn-danger ms-auto d-none" id="deleteSelectedBtn" onclick="deleteSelected()">
|
||||
<i class="fa-solid fa-trash-alt me-1"></i>Delete Selected
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,6 +52,7 @@
|
||||
<table class="table table-dark table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 30px;"><input type="checkbox" class="form-check-input" id="selectAllCheckbox"></th>
|
||||
<th class="icon-col"></th>
|
||||
<th>Name</th>
|
||||
<th>Size</th>
|
||||
@@ -86,8 +90,27 @@
|
||||
const API_BASE = '/api';
|
||||
let currentPath = "";
|
||||
|
||||
// Initial Load
|
||||
document.addEventListener('DOMContentLoaded', () => loadFiles());
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Initial Load
|
||||
loadFiles();
|
||||
|
||||
const selectAllCheckbox = document.getElementById('selectAllCheckbox');
|
||||
const fileTableBody = document.getElementById('fileTableBody');
|
||||
|
||||
selectAllCheckbox.addEventListener('change', (e) => {
|
||||
const checkboxes = fileTableBody.querySelectorAll('.file-checkbox');
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.checked = e.target.checked;
|
||||
});
|
||||
updateDeleteButtonVisibility();
|
||||
});
|
||||
|
||||
fileTableBody.addEventListener('change', (e) => {
|
||||
if (e.target.classList.contains('file-checkbox')) {
|
||||
updateDeleteButtonVisibility();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
async function loadFiles() {
|
||||
const path = document.getElementById('pathInput').value;
|
||||
@@ -127,12 +150,11 @@
|
||||
if (parentPath === '') parentPath = '/';
|
||||
|
||||
const tr = document.createElement('tr');
|
||||
tr.className = 'file-row';
|
||||
tr.onclick = () => enterDir(parentPath);
|
||||
tr.innerHTML = `
|
||||
<td class="icon-col"><i class="fa-solid fa-arrow-turn-up text-secondary"></i></td>
|
||||
<td>..</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="text-end"></td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
@@ -141,17 +163,13 @@
|
||||
if (files.length === 0) {
|
||||
// If we haven't added the "up" directory, show no files.
|
||||
if (tbody.childElementCount === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="text-center text-muted">No files found.</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-muted">No files found.</td></tr>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
files.forEach(file => {
|
||||
const tr = document.createElement('tr');
|
||||
tr.className = 'file-row';
|
||||
if (file.is_dir) {
|
||||
tr.onclick = () => enterDir(file.path);
|
||||
}
|
||||
|
||||
// Icon logic
|
||||
let icon = 'fa-file';
|
||||
@@ -164,13 +182,29 @@
|
||||
const size = file.is_dir ? '-' : (file.size / 1024).toFixed(1) + ' KB';
|
||||
|
||||
tr.innerHTML = `
|
||||
<td><input type="checkbox" class="form-check-input file-checkbox" data-path="${file.path.replace(/\\/g, '\\\\')}"></td>
|
||||
<td class="icon-col"><i class="fa-solid ${icon} ${color}"></i></td>
|
||||
<td>${file.name}</td>
|
||||
<td class="file-name-cell">${file.name}</td>
|
||||
<td>${size}</td>
|
||||
<td class="text-end">
|
||||
${getActions(file)}
|
||||
</td>
|
||||
`;
|
||||
|
||||
// Row click should not trigger when clicking on interactive elements
|
||||
tr.addEventListener('click', (e) => {
|
||||
if (e.target.matches('input, button, a, i')) return; // Ignore clicks on actions/checkboxes
|
||||
if (file.is_dir) {
|
||||
enterDir(file.path);
|
||||
}
|
||||
});
|
||||
|
||||
// Make the text part of the cell clickable for directory navigation
|
||||
const fileNameCell = tr.querySelector('.file-name-cell');
|
||||
if(file.is_dir) {
|
||||
fileNameCell.classList.add('file-row');
|
||||
fileNameCell.onclick = () => enterDir(file.path);
|
||||
}
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
@@ -232,7 +266,47 @@
|
||||
alert("Network error");
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteSelected() {
|
||||
const selectedCheckboxes = document.querySelectorAll('.file-checkbox:checked');
|
||||
if (selectedCheckboxes.length === 0) {
|
||||
alert("Please select files to delete.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm(`Are you sure you want to delete ${selectedCheckboxes.length} selected files? This cannot be undone.`)) return;
|
||||
|
||||
const paths = Array.from(selectedCheckboxes).map(cb => cb.dataset.path);
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/delete_multiple`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ paths: paths })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
loadFiles(); // Refresh list
|
||||
} else {
|
||||
alert("Error deleting files: " + (data.error || "Unknown error"));
|
||||
}
|
||||
} catch (err) {
|
||||
alert("Network error during multiple delete.");
|
||||
}
|
||||
}
|
||||
|
||||
function updateDeleteButtonVisibility() {
|
||||
const selectedCheckboxes = document.querySelectorAll('.file-checkbox:checked');
|
||||
const deleteBtn = document.getElementById('deleteSelectedBtn');
|
||||
if (selectedCheckboxes.length > 0) {
|
||||
deleteBtn.classList.remove('d-none');
|
||||
} else {
|
||||
deleteBtn.classList.add('d-none');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user