350 lines
12 KiB
HTML
350 lines
12 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en">
|
|
<head>
|
|
<title>File Manager</title>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<!--<link href="/css/global-style.css" rel="stylesheet">-->
|
|
<link href="/css/nav.css" rel="stylesheet">
|
|
|
|
<style>
|
|
/* --- Modern Styles --- */
|
|
:root {
|
|
--primary-color: #007bff;
|
|
--primary-hover: #0056b3;
|
|
--background-color: #f4f7f6;
|
|
--card-background: #ffffff;
|
|
--text-color: #333;
|
|
--border-color: #ddd;
|
|
--border-radius: 8px;
|
|
--box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
background-color: var(--background-color);
|
|
color: var(--text-color);
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.main-container {
|
|
max-width: 800px;
|
|
margin: 2rem auto;
|
|
padding: 0 1rem;
|
|
}
|
|
|
|
h1 {
|
|
text-align: center;
|
|
color: var(--primary-color);
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
/* Card styles to replace fieldset */
|
|
.card {
|
|
background-color: var(--card-background);
|
|
border-radius: var(--border-radius);
|
|
box-shadow: var(--box-shadow);
|
|
padding: 1.5rem;
|
|
margin-bottom: 1.5rem;
|
|
border: 1px solid var(--border-color);
|
|
}
|
|
|
|
.card-header {
|
|
font-size: 1.2rem;
|
|
font-weight: bold;
|
|
margin: -1.5rem -1.5rem 1.5rem -1.5rem;
|
|
padding: 1rem 1.5rem;
|
|
border-bottom: 1px solid var(--border-color);
|
|
background-color: #f9f9f9;
|
|
border-top-left-radius: var(--border-radius);
|
|
border-top-right-radius: var(--border-radius);
|
|
}
|
|
|
|
/* Dropdown style for File List */
|
|
details.card > summary {
|
|
font-size: 1.2rem;
|
|
font-weight: bold;
|
|
cursor: pointer;
|
|
list-style: none; /* Hide default arrow */
|
|
padding: 0;
|
|
margin: 0 0 1rem 0;
|
|
}
|
|
|
|
details.card > summary::-webkit-details-marker {
|
|
display: none; /* Hide default arrow for Chrome/Safari */
|
|
}
|
|
|
|
details.card > summary::before {
|
|
content: '▶';
|
|
margin-right: 0.5rem;
|
|
font-size: 0.8em;
|
|
transition: transform 0.2s ease-in-out;
|
|
}
|
|
|
|
details[open] > summary::before {
|
|
transform: rotate(90deg);
|
|
}
|
|
|
|
/* Form element styling */
|
|
.form-group {
|
|
display: flex;
|
|
gap: 1rem;
|
|
align-items: center;
|
|
}
|
|
|
|
/* (CHANGED) select and input[type=file] now share properties */
|
|
select, input[type="file"] {
|
|
flex-grow: 1; /* Allows the element to fill available space */
|
|
padding: 0.75rem;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: var(--border-radius);
|
|
font-size: 1rem;
|
|
background-color: #fff;
|
|
}
|
|
|
|
/* Specific tweak for file input padding to look aligned */
|
|
input[type="file"] {
|
|
padding: 0.65rem;
|
|
}
|
|
|
|
input[type="submit"] {
|
|
padding: 0.75rem 1.5rem;
|
|
border: none;
|
|
border-radius: var(--border-radius);
|
|
background-color: var(--primary-color);
|
|
color: white;
|
|
font-size: 1rem;
|
|
font-weight: bold;
|
|
cursor: pointer;
|
|
transition: background-color 0.2s ease-in-out;
|
|
}
|
|
|
|
input[type="submit"]:hover {
|
|
background-color: var(--primary-hover);
|
|
}
|
|
|
|
/* File List Table */
|
|
.file-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.file-table th, .file-table td {
|
|
padding: 0.75rem;
|
|
text-align: left;
|
|
border-bottom: 1px solid var(--border-color);
|
|
}
|
|
|
|
.file-table th {
|
|
background-color: #f2f2f2;
|
|
}
|
|
|
|
.file-table tr:nth-child(even) {
|
|
background-color: #f9f9f9;
|
|
}
|
|
|
|
.fs-info {
|
|
margin-bottom: 1rem;
|
|
color: #555;
|
|
font-style: italic;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="navbar"></div>
|
|
<div class="main-container">
|
|
<h1>File Manager</h1>
|
|
|
|
<details class="card">
|
|
<summary>File List</summary>
|
|
<p class="fs-info">Total: {{FS_TOTAL_BYTES}}, Used: {{FS_USED_BYTES}}, Available: {{FS_FREE_BYTES}}</p>
|
|
<table class="file-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Listing:</th>
|
|
<th>Size:</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{LISTED_FILES}}
|
|
</tbody>
|
|
</table>
|
|
</details>
|
|
|
|
<div class="card">
|
|
<div class="card-header">File Upload</div>
|
|
<form action="/upload" method="POST" enctype="multipart/form-data">
|
|
<div class="form-group">
|
|
<select name="dir-path" id="dir-path" title="Select directory">
|
|
<option value="" disabled selected>Select file destination</option>
|
|
{{DIR_LIST}}
|
|
</select>
|
|
</div>
|
|
<div class="form-group" style="margin-top: 1rem;">
|
|
<input type="file" id="upload-file" name="upload-file">
|
|
<input type="submit" id="submit-upload" value="Upload" onclick="return validateFormUpload()">
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header">Edit File</div>
|
|
<form action="/files/edit" method="GET">
|
|
<div class="form-group">
|
|
<select name="edit-path" id="edit-path">
|
|
<option value="choose">Select file to edit</option>
|
|
<option value="new">New text file</option>
|
|
{{EDIT-DEL_FILES}}
|
|
</select>
|
|
<input type="submit" id="submit-edit" value="Edit" onclick="return validateFormEdit()">
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header">Delete File</div>
|
|
<form action="/files/delete" method="GET">
|
|
<div class="form-group">
|
|
<select name="delete-path" id="delete-path">
|
|
<option value="choose">Select file to delete</option>
|
|
{{EDIT-DEL_FILES}}
|
|
</select>
|
|
<input type="submit" id="submit-delete" value="Delete" onclick="return validateFormDelete()">
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
fetch('/www/navbar.html')
|
|
.then(response => response.text())
|
|
.then(data => {
|
|
document.getElementById('navbar').innerHTML = data;
|
|
});
|
|
|
|
function validateFormEdit() {
|
|
var allowedExtensions = "{{ALLOWED_EXTENSIONS_EDIT}}";
|
|
var editSelectValue = document.getElementById('edit-path').value;
|
|
if (editSelectValue == "new") {
|
|
return true;
|
|
}
|
|
if (editSelectValue == "choose") {
|
|
alert("You have not chosen a file!");
|
|
return false;
|
|
}
|
|
var dotIndex = editSelectValue.lastIndexOf(".") + 1;
|
|
var editSelectValueExtension = editSelectValue.substring(dotIndex);
|
|
var extIndex = allowedExtensions.indexOf(editSelectValueExtension);
|
|
if (extIndex == -1) {
|
|
alert("Editing of this file type is not supported!");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function validateFormDelete() {
|
|
var deleteSelectValue = document.getElementById('delete-path').value;
|
|
if (deleteSelectValue == "choose") { // Simplified check
|
|
alert("You have not chosen a file!");
|
|
return false;
|
|
}
|
|
return true; // Let server handle validation if needed
|
|
}
|
|
|
|
function confirmFormat() {
|
|
var text = 'Pressing the "OK" button immediately deletes all data from the File System and restarts the device!';
|
|
return confirm(text);
|
|
}
|
|
|
|
function validateFormUpload() {
|
|
var inputElement = document.getElementById('upload-file');
|
|
var files = inputElement.files;
|
|
if (files.length == 0) {
|
|
alert("You have not chosen a file!");
|
|
return false;
|
|
}
|
|
// Check if the placeholder is still selected
|
|
var dirPath = document.getElementById('dir-path').value;
|
|
if (dirPath === "") {
|
|
alert("Please select a file destination!");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// The rest of your upload progress script remains the same...
|
|
const fileInput = document.getElementById('update-file');
|
|
const progressBar = document.getElementById('firm-progress');
|
|
const progressLabel = document.getElementById('lbl-firm-progress');
|
|
const submitButton = document.getElementById('submit-update-local');
|
|
|
|
// Check if these elements exist before adding listener to avoid errors
|
|
if(submitButton) {
|
|
submitButton.addEventListener('click', uploadFile);
|
|
}
|
|
|
|
function uploadFile(event) {
|
|
event.preventDefault(); // Prevent the default form submission
|
|
const file = fileInput.files[0];
|
|
const url = '/update'; // Replace with the actual upload URL
|
|
|
|
if (!file) {
|
|
alert('Please select a file first.');
|
|
return;
|
|
}
|
|
|
|
// File Checks
|
|
if (!file.name.toLowerCase().endsWith('.bin')) {
|
|
alert('Please select a file with the ".bin" extension.');
|
|
return;
|
|
}
|
|
if (!file.name.toLowerCase().startsWith('fwata') && !file.name.toLowerCase().startsWith('lfsata')) {
|
|
alert('Please select a file with a filename starting with "fwata" or "lfsata".');
|
|
return;
|
|
}
|
|
const maxSizeBytes = 2.7 * 1024 * 1024; // 2.7Mb in bytes
|
|
if (file.size > maxSizeBytes) {
|
|
alert('Please select a file with a size not exceeding 2.7Mb.');
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData();
|
|
formData.append('file-size', file.size);
|
|
formData.append('update-file', file);
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.upload.addEventListener('progress', (event) => {
|
|
if (event.lengthComputable) {
|
|
const progressPercent = Math.round((event.loaded * 100) / event.total);
|
|
progressBar.value = progressPercent;
|
|
progressLabel.innerHTML = progressBar.value + "%";
|
|
}
|
|
});
|
|
xhr.onreadystatechange = function () {
|
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
if (xhr.status === 200) {
|
|
alert('Upload completed!');
|
|
progressLabel.innerHTML = "Completed!";
|
|
} else if (xhr.status === 500) {
|
|
alert('Upload aborted by the server.');
|
|
progressLabel.innerHTML = "Aborted!";
|
|
} else {
|
|
alert('An error occurred during the upload.');
|
|
progressLabel.innerHTML = "Error!";
|
|
}
|
|
submitButton.disabled = false;
|
|
progressBar.value = 0;
|
|
progressLabel.innerHTML = "";
|
|
}
|
|
};
|
|
xhr.open('POST', url, true);
|
|
xhr.send(formData);
|
|
submitButton.disabled = true;
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |