mirror of
https://git.sr.ht/~coasteen/webui
synced 2025-11-04 11:37:34 +01:00
265 lines
8.8 KiB
JavaScript
265 lines
8.8 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
fetchFiles();
|
|
|
|
document.getElementById('upload-form').addEventListener('submit', handleFileUpload);
|
|
document.getElementById('file-input').addEventListener('change', updateUploadList);
|
|
|
|
document.getElementById('select-all').addEventListener('click', handleSelectAll);
|
|
document.getElementById('batch-delete').addEventListener('click', handleBatchDelete);
|
|
document.getElementById('batch-download').addEventListener('click', handleBatchDownload);
|
|
document.getElementById('batch-preview').addEventListener('click', handleBatchPreview);
|
|
});
|
|
|
|
function fetchFiles() {
|
|
fetch('/files')
|
|
.then(response => response.json())
|
|
.then(files => {
|
|
const fileList = document.getElementById('file-list');
|
|
fileList.innerHTML = '';
|
|
files.forEach(file => {
|
|
const li = document.createElement('li');
|
|
|
|
const checkbox = document.createElement('input');
|
|
checkbox.type = 'checkbox';
|
|
checkbox.value = file.name;
|
|
checkbox.dataset.path = `/uploads/${file.name}`;
|
|
const extension = file.name.split('.').pop().toLowerCase();
|
|
checkbox.dataset.fileType = extension;
|
|
|
|
const fileInfo = document.createElement('span');
|
|
fileInfo.className = 'file-info';
|
|
fileInfo.textContent = `${file.name} (Size: ${file.size} bytes, Date: ${new Date(file.date).toLocaleString()})`;
|
|
|
|
li.appendChild(checkbox);
|
|
li.appendChild(fileInfo);
|
|
fileList.appendChild(li);
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching file list:', error);
|
|
});
|
|
}
|
|
|
|
function updateUploadList(event) {
|
|
const fileInput = event.target;
|
|
const uploadList = document.getElementById('upload-list');
|
|
uploadList.innerHTML = '';
|
|
|
|
if (fileInput.files.length === 0) return;
|
|
|
|
for (const file of fileInput.files) {
|
|
const li = document.createElement('li');
|
|
li.className = 'upload-item';
|
|
li.innerHTML = `
|
|
<span>${file.name} (Size: ${Math.round(file.size / 1024)} KB)</span>
|
|
<div id="progress-${file.name.replace(/[^a-zA-Z0-9]/g, '-')}" class="progress-bar">
|
|
<div class="progress-bar-fill" style="width: 0;"></div>
|
|
</div>
|
|
`;
|
|
uploadList.appendChild(li);
|
|
}
|
|
}
|
|
|
|
function handleFileUpload(event) {
|
|
event.preventDefault();
|
|
|
|
const form = event.target;
|
|
const formData = new FormData(form);
|
|
const fileInput = document.getElementById('file-input');
|
|
|
|
if (fileInput.files.length === 0) {
|
|
alert('Please select files to upload.');
|
|
return;
|
|
}
|
|
|
|
const xhr = new XMLHttpRequest();
|
|
|
|
xhr.upload.addEventListener('progress', (e) => {
|
|
if (e.lengthComputable) {
|
|
const percentComplete = (e.loaded / e.total) * 100;
|
|
const progressBars = document.querySelectorAll('.progress-bar-fill');
|
|
|
|
progressBars.forEach(bar => {
|
|
bar.style.width = percentComplete.toFixed(2) + '%';
|
|
});
|
|
}
|
|
}, false);
|
|
|
|
xhr.addEventListener('load', () => {
|
|
if (xhr.status === 200) {
|
|
alert(xhr.responseText);
|
|
form.reset();
|
|
document.getElementById('upload-list').innerHTML = '';
|
|
fetchFiles();
|
|
} else {
|
|
alert('File upload failed! Server responded with status ' + xhr.status);
|
|
}
|
|
});
|
|
|
|
xhr.addEventListener('error', () => {
|
|
console.error('Error uploading file:', xhr.statusText);
|
|
alert('File upload failed!');
|
|
});
|
|
|
|
xhr.open('POST', '/upload');
|
|
xhr.send(formData);
|
|
}
|
|
|
|
function getSelectedFiles() {
|
|
const selectedCheckboxes = document.querySelectorAll('#file-list input[type="checkbox"]:checked');
|
|
return Array.from(selectedCheckboxes).map(checkbox => ({
|
|
name: checkbox.value,
|
|
path: checkbox.dataset.path,
|
|
type: checkbox.dataset.fileType
|
|
}));
|
|
}
|
|
|
|
function handleSelectAll() {
|
|
const checkboxes = document.querySelectorAll('#file-list input[type="checkbox"]');
|
|
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
|
|
|
|
checkboxes.forEach(cb => {
|
|
cb.checked = !allChecked;
|
|
});
|
|
}
|
|
|
|
function handleBatchDelete() {
|
|
const filesToDelete = getSelectedFiles();
|
|
if (filesToDelete.length === 0) {
|
|
alert('No files selected for deletion.');
|
|
return;
|
|
}
|
|
|
|
if (!confirm(`Are you sure you want to delete ${filesToDelete.length} file(s)?`)) {
|
|
return;
|
|
}
|
|
|
|
const deletePromises = filesToDelete.map(file =>
|
|
fetch(`/delete/${file.name}`, { method: 'DELETE' })
|
|
.then(response => {
|
|
if (response.ok) {
|
|
return { name: file.name, status: 'Success' };
|
|
} else {
|
|
return { name: file.name, status: 'Failed' };
|
|
}
|
|
})
|
|
);
|
|
|
|
Promise.all(deletePromises)
|
|
.then(results => {
|
|
const successfulDeletes = results.filter(r => r.status === 'Success');
|
|
const failedDeletes = results.filter(r => r.status === 'Failed');
|
|
|
|
if (successfulDeletes.length > 0) {
|
|
alert(`Successfully deleted ${successfulDeletes.length} file(s).`);
|
|
}
|
|
if (failedDeletes.length > 0) {
|
|
alert(`Failed to delete ${failedDeletes.length} file(s). Check console for errors.`);
|
|
}
|
|
fetchFiles();
|
|
})
|
|
.catch(error => {
|
|
console.error('Error during batch deletion:', error);
|
|
alert('An error occurred during batch deletion.');
|
|
});
|
|
}
|
|
|
|
function handleBatchDownload() {
|
|
const filesToDownload = getSelectedFiles();
|
|
if (filesToDownload.length === 0) {
|
|
alert('No files selected for download.');
|
|
return;
|
|
}
|
|
|
|
filesToDownload.forEach(file => {
|
|
window.location.href = `/download/${file.name}`;
|
|
});
|
|
|
|
alert(`Initiating download for ${filesToDownload.length} file(s). Check your browser's download manager.`);
|
|
}
|
|
|
|
function handleBatchPreview() {
|
|
const selectedFiles = getSelectedFiles();
|
|
const previewableFiles = selectedFiles.filter(file =>
|
|
file.type === 'txt' || file.type.match(/^(jpg|jpeg|png|gif)$/)
|
|
);
|
|
|
|
if (previewableFiles.length === 0) {
|
|
alert('No previewable files (.txt, .jpg, .png, .gif) selected.');
|
|
return;
|
|
}
|
|
|
|
showMultiPreview(previewableFiles);
|
|
}
|
|
|
|
function showMultiPreview(files) {
|
|
let currentIndex = 0;
|
|
const previewContainer = document.createElement('div');
|
|
previewContainer.className = 'preview-modal';
|
|
|
|
const content = document.createElement('div');
|
|
content.className = 'preview-content';
|
|
|
|
const controls = document.createElement('div');
|
|
controls.className = 'preview-controls';
|
|
|
|
const prevButton = document.createElement('button');
|
|
prevButton.textContent = 'Previous';
|
|
prevButton.onclick = () => {
|
|
if (currentIndex > 0) {
|
|
currentIndex--;
|
|
updatePreviewContent();
|
|
}
|
|
};
|
|
|
|
const nextButton = document.createElement('button');
|
|
nextButton.textContent = 'Next';
|
|
nextButton.onclick = () => {
|
|
if (currentIndex < files.length - 1) {
|
|
currentIndex++;
|
|
updatePreviewContent();
|
|
}
|
|
};
|
|
|
|
const closeButton = document.createElement('button');
|
|
closeButton.textContent = 'Close Preview';
|
|
closeButton.onclick = () => {
|
|
document.body.removeChild(previewContainer);
|
|
};
|
|
|
|
controls.appendChild(prevButton);
|
|
controls.appendChild(closeButton);
|
|
controls.appendChild(nextButton);
|
|
|
|
const updatePreviewContent = () => {
|
|
content.innerHTML = '';
|
|
const file = files[currentIndex];
|
|
|
|
prevButton.disabled = currentIndex === 0;
|
|
nextButton.disabled = currentIndex === files.length - 1;
|
|
|
|
const counter = document.createElement('p');
|
|
counter.textContent = `File ${currentIndex + 1} of ${files.length}: ${file.name}`;
|
|
content.appendChild(counter);
|
|
|
|
if (file.type === 'txt') {
|
|
const textPreview = document.createElement('iframe');
|
|
textPreview.src = file.path;
|
|
textPreview.style.width = '100%';
|
|
textPreview.style.height = '400px';
|
|
content.appendChild(textPreview);
|
|
} else if (file.type.match(/^(jpg|jpeg|png|gif)$/)) {
|
|
const imgPreview = document.createElement('img');
|
|
imgPreview.src = file.path;
|
|
content.appendChild(imgPreview);
|
|
} else {
|
|
content.textContent = `Preview not available for this file type: ${file.name}.`;
|
|
}
|
|
};
|
|
|
|
previewContainer.appendChild(controls);
|
|
previewContainer.appendChild(content);
|
|
document.body.appendChild(previewContainer);
|
|
|
|
updatePreviewContent();
|
|
}
|