parent
926c786705
commit
b7b00ad722
@ -513,13 +513,6 @@ void CrossPointWebServer::handleUpload() {
|
|||||||
Serial.printf("[%lu] [WEB] [UPLOAD] START: %s to path: %s\n", millis(), uploadFileName.c_str(), uploadPath.c_str());
|
Serial.printf("[%lu] [WEB] [UPLOAD] START: %s to path: %s\n", millis(), uploadFileName.c_str(), uploadPath.c_str());
|
||||||
Serial.printf("[%lu] [WEB] [UPLOAD] Free heap: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEB] [UPLOAD] Free heap: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
// Validate file extension
|
|
||||||
if (!isEpubFile(uploadFileName)) {
|
|
||||||
uploadError = "Only .epub files are allowed";
|
|
||||||
Serial.printf("[%lu] [WEB] [UPLOAD] REJECTED - not an epub file\n", millis());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create file path
|
// Create file path
|
||||||
String filePath = uploadPath;
|
String filePath = uploadPath;
|
||||||
if (!filePath.endsWith("/")) filePath += "/";
|
if (!filePath.endsWith("/")) filePath += "/";
|
||||||
|
|||||||
@ -3,15 +3,15 @@
|
|||||||
CrossPoint E-Reader • Open Source
|
CrossPoint E-Reader • Open Source
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Upload Modal -->
|
<!-- Upload Modal -->
|
||||||
<div class="modal-overlay" id="uploadModal">
|
<div class="modal-overlay" id="uploadModal">
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<button class="modal-close" onclick="closeUploadModal()">×</button>
|
<button class="modal-close" onclick="closeUploadModal()">×</button>
|
||||||
<h3>📤 Upload eBook</h3>
|
<h3>📤 Upload file</h3>
|
||||||
<div class="upload-form">
|
<div class="upload-form">
|
||||||
<p class="file-info">Select an .epub file to upload to <strong id="uploadPathDisplay"></strong></p>
|
<p class="file-info">Select a file to upload to <strong id="uploadPathDisplay"></strong></p>
|
||||||
<input type="file" id="fileInput" accept=".epub" onchange="validateFile()">
|
<input type="file" id="fileInput" onchange="validateFile()">
|
||||||
<button id="uploadBtn" class="upload-btn" onclick="uploadFile()" disabled>Upload</button>
|
<button id="uploadBtn" class="upload-btn" onclick="uploadFile()" disabled>Upload</button>
|
||||||
<div id="progress-container">
|
<div id="progress-container">
|
||||||
<div id="progress-bar"><div id="progress-fill"></div></div>
|
<div id="progress-bar"><div id="progress-fill"></div></div>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- New Folder Modal -->
|
<!-- New Folder Modal -->
|
||||||
<div class="modal-overlay" id="folderModal">
|
<div class="modal-overlay" id="folderModal">
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Delete Confirmation Modal -->
|
<!-- Delete Confirmation Modal -->
|
||||||
<div class="modal-overlay" id="deleteModal">
|
<div class="modal-overlay" id="deleteModal">
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
@ -50,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Modal functions
|
// Modal functions
|
||||||
function openUploadModal() {
|
function openUploadModal() {
|
||||||
@ -58,7 +58,7 @@
|
|||||||
document.getElementById('uploadPathDisplay').textContent = currentPath === '/' ? '/ 🏠' : currentPath;
|
document.getElementById('uploadPathDisplay').textContent = currentPath === '/' ? '/ 🏠' : currentPath;
|
||||||
document.getElementById('uploadModal').classList.add('open');
|
document.getElementById('uploadModal').classList.add('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeUploadModal() {
|
function closeUploadModal() {
|
||||||
document.getElementById('uploadModal').classList.remove('open');
|
document.getElementById('uploadModal').classList.remove('open');
|
||||||
document.getElementById('fileInput').value = '';
|
document.getElementById('fileInput').value = '';
|
||||||
@ -67,18 +67,18 @@
|
|||||||
document.getElementById('progress-fill').style.width = '0%';
|
document.getElementById('progress-fill').style.width = '0%';
|
||||||
document.getElementById('progress-fill').style.backgroundColor = '#27ae60';
|
document.getElementById('progress-fill').style.backgroundColor = '#27ae60';
|
||||||
}
|
}
|
||||||
|
|
||||||
function openFolderModal() {
|
function openFolderModal() {
|
||||||
const currentPath = document.getElementById('currentPath').value;
|
const currentPath = document.getElementById('currentPath').value;
|
||||||
document.getElementById('folderPathDisplay').textContent = currentPath === '/' ? '/ 🏠' : currentPath;
|
document.getElementById('folderPathDisplay').textContent = currentPath === '/' ? '/ 🏠' : currentPath;
|
||||||
document.getElementById('folderModal').classList.add('open');
|
document.getElementById('folderModal').classList.add('open');
|
||||||
document.getElementById('folderName').value = '';
|
document.getElementById('folderName').value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeFolderModal() {
|
function closeFolderModal() {
|
||||||
document.getElementById('folderModal').classList.remove('open');
|
document.getElementById('folderModal').classList.remove('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close modals when clicking overlay
|
// Close modals when clicking overlay
|
||||||
document.querySelectorAll('.modal-overlay').forEach(function(overlay) {
|
document.querySelectorAll('.modal-overlay').forEach(function(overlay) {
|
||||||
overlay.addEventListener('click', function(e) {
|
overlay.addEventListener('click', function(e) {
|
||||||
@ -87,58 +87,40 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function validateFile() {
|
function validateFile() {
|
||||||
const fileInput = document.getElementById('fileInput');
|
const fileInput = document.getElementById('fileInput');
|
||||||
const uploadBtn = document.getElementById('uploadBtn');
|
const uploadBtn = document.getElementById('uploadBtn');
|
||||||
const file = fileInput.files[0];
|
const file = fileInput.files[0];
|
||||||
|
uploadBtn.disabled = !file;
|
||||||
if (file) {
|
|
||||||
const fileName = file.name.toLowerCase();
|
|
||||||
if (!fileName.endsWith('.epub')) {
|
|
||||||
alert('Only .epub files are allowed!');
|
|
||||||
fileInput.value = '';
|
|
||||||
uploadBtn.disabled = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uploadBtn.disabled = false;
|
|
||||||
} else {
|
|
||||||
uploadBtn.disabled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function uploadFile() {
|
function uploadFile() {
|
||||||
const fileInput = document.getElementById('fileInput');
|
const fileInput = document.getElementById('fileInput');
|
||||||
const file = fileInput.files[0];
|
const file = fileInput.files[0];
|
||||||
const currentPath = document.getElementById('currentPath').value;
|
const currentPath = document.getElementById('currentPath').value;
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
alert('Please select a file first!');
|
alert('Please select a file first!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName = file.name.toLowerCase();
|
|
||||||
if (!fileName.endsWith('.epub')) {
|
|
||||||
alert('Only .epub files are allowed!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
|
|
||||||
const progressContainer = document.getElementById('progress-container');
|
const progressContainer = document.getElementById('progress-container');
|
||||||
const progressFill = document.getElementById('progress-fill');
|
const progressFill = document.getElementById('progress-fill');
|
||||||
const progressText = document.getElementById('progress-text');
|
const progressText = document.getElementById('progress-text');
|
||||||
const uploadBtn = document.getElementById('uploadBtn');
|
const uploadBtn = document.getElementById('uploadBtn');
|
||||||
|
|
||||||
progressContainer.style.display = 'block';
|
progressContainer.style.display = 'block';
|
||||||
uploadBtn.disabled = true;
|
uploadBtn.disabled = true;
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
// Include path as query parameter since multipart form data doesn't make
|
// Include path as query parameter since multipart form data doesn't make
|
||||||
// form fields available until after file upload completes
|
// form fields available until after file upload completes
|
||||||
xhr.open('POST', '/upload?path=' + encodeURIComponent(currentPath), true);
|
xhr.open('POST', '/upload?path=' + encodeURIComponent(currentPath), true);
|
||||||
|
|
||||||
xhr.upload.onprogress = function(e) {
|
xhr.upload.onprogress = function(e) {
|
||||||
if (e.lengthComputable) {
|
if (e.lengthComputable) {
|
||||||
const percent = Math.round((e.loaded / e.total) * 100);
|
const percent = Math.round((e.loaded / e.total) * 100);
|
||||||
@ -146,7 +128,7 @@
|
|||||||
progressText.textContent = 'Uploading: ' + percent + '%';
|
progressText.textContent = 'Uploading: ' + percent + '%';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onload = function() {
|
xhr.onload = function() {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
progressText.textContent = 'Upload complete!';
|
progressText.textContent = 'Upload complete!';
|
||||||
@ -159,39 +141,39 @@
|
|||||||
uploadBtn.disabled = false;
|
uploadBtn.disabled = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onerror = function() {
|
xhr.onerror = function() {
|
||||||
progressText.textContent = 'Upload failed - network error';
|
progressText.textContent = 'Upload failed - network error';
|
||||||
progressFill.style.backgroundColor = '#e74c3c';
|
progressFill.style.backgroundColor = '#e74c3c';
|
||||||
uploadBtn.disabled = false;
|
uploadBtn.disabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.send(formData);
|
xhr.send(formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFolder() {
|
function createFolder() {
|
||||||
const folderName = document.getElementById('folderName').value.trim();
|
const folderName = document.getElementById('folderName').value.trim();
|
||||||
const currentPath = document.getElementById('currentPath').value;
|
const currentPath = document.getElementById('currentPath').value;
|
||||||
|
|
||||||
if (!folderName) {
|
if (!folderName) {
|
||||||
alert('Please enter a folder name!');
|
alert('Please enter a folder name!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate folder name (no special characters except underscore and hyphen)
|
// Validate folder name (no special characters except underscore and hyphen)
|
||||||
const validName = /^[a-zA-Z0-9_\-]+$/.test(folderName);
|
const validName = /^[a-zA-Z0-9_\-]+$/.test(folderName);
|
||||||
if (!validName) {
|
if (!validName) {
|
||||||
alert('Folder name can only contain letters, numbers, underscores, and hyphens.');
|
alert('Folder name can only contain letters, numbers, underscores, and hyphens.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('name', folderName);
|
formData.append('name', folderName);
|
||||||
formData.append('path', currentPath);
|
formData.append('path', currentPath);
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open('POST', '/mkdir', true);
|
xhr.open('POST', '/mkdir', true);
|
||||||
|
|
||||||
xhr.onload = function() {
|
xhr.onload = function() {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
@ -199,14 +181,14 @@
|
|||||||
alert('Failed to create folder: ' + xhr.responseText);
|
alert('Failed to create folder: ' + xhr.responseText);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onerror = function() {
|
xhr.onerror = function() {
|
||||||
alert('Failed to create folder - network error');
|
alert('Failed to create folder - network error');
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.send(formData);
|
xhr.send(formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete functions
|
// Delete functions
|
||||||
function openDeleteModal(name, path, isFolder) {
|
function openDeleteModal(name, path, isFolder) {
|
||||||
document.getElementById('deleteItemName').textContent = (isFolder ? '📁 ' : '📄 ') + name;
|
document.getElementById('deleteItemName').textContent = (isFolder ? '📁 ' : '📄 ') + name;
|
||||||
@ -214,22 +196,22 @@
|
|||||||
document.getElementById('deleteItemType').value = isFolder ? 'folder' : 'file';
|
document.getElementById('deleteItemType').value = isFolder ? 'folder' : 'file';
|
||||||
document.getElementById('deleteModal').classList.add('open');
|
document.getElementById('deleteModal').classList.add('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDeleteModal() {
|
function closeDeleteModal() {
|
||||||
document.getElementById('deleteModal').classList.remove('open');
|
document.getElementById('deleteModal').classList.remove('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmDelete() {
|
function confirmDelete() {
|
||||||
const path = document.getElementById('deleteItemPath').value;
|
const path = document.getElementById('deleteItemPath').value;
|
||||||
const itemType = document.getElementById('deleteItemType').value;
|
const itemType = document.getElementById('deleteItemType').value;
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('path', path);
|
formData.append('path', path);
|
||||||
formData.append('type', itemType);
|
formData.append('type', itemType);
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open('POST', '/delete', true);
|
xhr.open('POST', '/delete', true);
|
||||||
|
|
||||||
xhr.onload = function() {
|
xhr.onload = function() {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
@ -238,12 +220,12 @@
|
|||||||
closeDeleteModal();
|
closeDeleteModal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onerror = function() {
|
xhr.onerror = function() {
|
||||||
alert('Failed to delete - network error');
|
alert('Failed to delete - network error');
|
||||||
closeDeleteModal();
|
closeDeleteModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.send(formData);
|
xhr.send(formData);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user