Fix permanent delete

This commit is contained in:
2025-05-27 11:43:10 +02:00
parent e5d54c499b
commit a67470d616
11 changed files with 176 additions and 126 deletions

View File

@@ -1360,7 +1360,9 @@ document.addEventListener('DOMContentLoaded', function() {
moveModal = new bootstrap.Modal(document.getElementById('moveModal'));
// Add click handler for move confirmation button
document.getElementById('confirmMoveBtn').addEventListener('click', moveFileConfirmed);
if (canMove === true || canMove === 'true') {
document.getElementById('confirmMoveBtn').addEventListener('click', moveFileConfirmed);
}
// Add click handler for new folder button
if (canUpload === true || canUpload === 'true') {
@@ -1715,126 +1717,140 @@ document.addEventListener('DOMContentLoaded', function() {
// Start processing files
await processNextFile();
}
// Robust modal show logic
function showOverwriteModal(filename) {
console.log('[Modal] showOverwriteModal called for', filename);
// If there's an existing modal promise, resolve it with skip
if (modalResolve) {
modalResolve('skip');
modalResolve = null;
}
// Create a new promise for this modal interaction
modalPromise = new Promise((resolve) => {
modalResolve = resolve;
// Update modal content
document.getElementById('overwriteFileName').textContent = filename;
// Get modal elements
const modalEl = document.getElementById('overwriteConfirmModal');
// Ensure modal is properly initialized with static backdrop
if (!overwriteModal) {
overwriteModal = new bootstrap.Modal(modalEl, {
backdrop: 'static',
keyboard: false
});
}
// Get fresh button references
const confirmOverwriteBtn = document.getElementById('confirmOverwriteBtn');
const skipOverwriteBtn = document.getElementById('skipOverwriteBtn');
const confirmAllOverwriteBtn = document.getElementById('confirmAllOverwriteBtn');
const skipAllOverwriteBtn = document.getElementById('skipAllOverwriteBtn');
// Remove any existing event listeners by cloning and replacing
const newConfirmOverwriteBtn = confirmOverwriteBtn.cloneNode(true);
const newSkipOverwriteBtn = skipOverwriteBtn.cloneNode(true);
const newConfirmAllOverwriteBtn = confirmAllOverwriteBtn.cloneNode(true);
const newSkipAllOverwriteBtn = skipAllOverwriteBtn.cloneNode(true);
confirmOverwriteBtn.parentNode.replaceChild(newConfirmOverwriteBtn, confirmOverwriteBtn);
skipOverwriteBtn.parentNode.replaceChild(newSkipOverwriteBtn, skipOverwriteBtn);
confirmAllOverwriteBtn.parentNode.replaceChild(newConfirmAllOverwriteBtn, confirmAllOverwriteBtn);
skipAllOverwriteBtn.parentNode.replaceChild(newSkipAllOverwriteBtn, skipAllOverwriteBtn);
let modalClosed = false;
// Function to handle modal resolution
const resolveModal = (choice) => {
if (!modalClosed) {
modalClosed = true;
if (modalResolve) {
modalResolve(choice);
modalResolve = null;
}
overwriteModal.hide();
}
};
// Add click handlers directly to the buttons
newConfirmOverwriteBtn.onclick = () => {
console.log('[Modal] Overwrite clicked');
resolveModal('overwrite');
};
newSkipOverwriteBtn.onclick = () => {
console.log('[Modal] Skip clicked');
resolveModal('skip');
};
newConfirmAllOverwriteBtn.onclick = () => {
console.log('[Modal] Overwrite All clicked');
overwriteAll = true;
resolveModal('overwrite_all');
};
newSkipAllOverwriteBtn.onclick = () => {
console.log('[Modal] Skip All clicked');
skipAll = true;
resolveModal('skip_all');
};
// Prevent modal from being closed by clicking outside or pressing escape
modalEl.addEventListener('click', (e) => {
if (e.target === modalEl) {
e.preventDefault();
e.stopPropagation();
}
});
// Add modal close handler
const handleModalClose = (e) => {
if (!modalClosed && modalResolve) {
console.log('[Modal] Modal closed without explicit choice');
e.preventDefault();
e.stopPropagation();
// Re-show the modal if it was closed without a choice
overwriteModal.show();
}
};
// Remove any existing close handler and add new one
modalEl.removeEventListener('hidden.bs.modal', handleModalClose);
modalEl.addEventListener('hidden.bs.modal', handleModalClose);
// Show the modal
overwriteModal.show();
// Ensure modal is visible and focused
modalEl.style.display = 'block';
modalEl.classList.add('show');
modalEl.focus();
});
return modalPromise;
}
}
});
// Add event listener for delete confirmation button
if (canDelete === true || canDelete === 'true') {
document.getElementById('confirmDeleteBtn').addEventListener('click', deleteFileConfirmed);
}
// Add event listener for rename confirmation button
if (canRename === true || canRename === 'true') {
document.getElementById('confirmRenameBtn').addEventListener('click', function() {
if (!renameTarget) return;
let newName = document.getElementById('renameInput').value.trim();
if (renameIsFile) {
if (!newName) {
document.getElementById('renameError').textContent = 'New name is required.';
return;
}
newName = newName + renameOrigExt;
}
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
if (!newName) {
document.getElementById('renameError').textContent = 'New name is required.';
return;
}
fetch(`/api/rooms/${roomId}/rename`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({
old_name: renameTarget,
new_name: newName,
path: currentPath
})
})
.then(r => r.json())
.then(res => {
if (res.success) {
fetchFiles();
var modalEl = document.getElementById('renameModal');
var modal = bootstrap.Modal.getInstance(modalEl);
modal.hide();
} else {
document.getElementById('renameError').textContent = res.error || 'Rename failed.';
}
})
.catch(() => {
document.getElementById('renameError').textContent = 'Rename failed.';
});
});
}
// Add event listener for download selected
if (canDownload === true || canDownload === 'true') {
document.getElementById('downloadSelectedBtn').addEventListener('click', function() {
const selectedCheckboxes = document.querySelectorAll('.select-item-checkbox:checked');
if (selectedCheckboxes.length === 0) return;
const selectedItems = Array.from(selectedCheckboxes).map(cb => {
const idx = parseInt(cb.dataset.idx);
return window.currentFiles[idx];
});
// Submit the request to download the zip
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
fetch(`/api/rooms/${roomId}/download-zip`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ items: selectedItems })
})
.then(response => {
if (!response.ok) {
throw new Error('Download failed');
}
return response.blob();
})
.then(blob => {
// Create a download link and trigger it
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'download.zip';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
a.remove();
})
.catch(error => {
console.error('Error downloading files:', error);
document.getElementById('fileError').textContent = 'Failed to download files.';
});
});
}
// Add event listener for batch delete
if (canDelete === true || canDelete === 'true') {
document.getElementById('deleteSelectedBtn').addEventListener('click', function() {
const selectedCheckboxes = document.querySelectorAll('.select-item-checkbox:checked');
if (selectedCheckboxes.length === 0) return;
batchDeleteItems = Array.from(selectedCheckboxes).map(cb => {
const idx = parseInt(cb.dataset.idx);
return window.currentFiles[idx];
});
// Get the modal element
const modalEl = document.getElementById('deleteConfirmModal');
if (!modalEl) {
console.error('Delete modal element not found');
return;
}
// Initialize the modal if it hasn't been initialized
if (!deleteModal) {
deleteModal = new bootstrap.Modal(modalEl);
}
// Update modal content
const fileNameEl = document.getElementById('deleteFileName');
const labelEl = document.getElementById('deleteConfirmLabel');
if (fileNameEl) fileNameEl.textContent = `${selectedCheckboxes.length} item${selectedCheckboxes.length > 1 ? 's' : ''}`;
if (labelEl) labelEl.textContent = 'Move to Trash';
// Show the modal
deleteModal.show();
});
}
function navigateToParent() {
if (!currentPath) return;
const parts = currentPath.split('/');