Global variables consolidated into the ‘state’ object
This commit is contained in:
@@ -1,14 +1,16 @@
|
|||||||
(() => {
|
(() => {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
let AppConfig = null;
|
|
||||||
let ErrorTimeout = null;
|
|
||||||
let Files = {};
|
|
||||||
const DEFAULT_DROPZONE_TEXT = "Drag & drop files here or click to select";
|
const DEFAULT_DROPZONE_TEXT = "Drag & drop files here or click to select";
|
||||||
const UI = {};
|
const state = {
|
||||||
|
config: null,
|
||||||
|
files: {},
|
||||||
|
ui: {},
|
||||||
|
errorTimeout: null,
|
||||||
|
};
|
||||||
|
|
||||||
async function appLoop() {
|
async function appLoop() {
|
||||||
if (AppConfig === null) {
|
if (state.config === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,22 +36,22 @@
|
|||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
console.error("HTTP error:", res.status);
|
console.error("HTTP error:", res.status);
|
||||||
}
|
}
|
||||||
AppConfig = await res.json();
|
state.config = await res.json();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to load config:", err);
|
console.error("Failed to load config:", err);
|
||||||
AppConfig = null;
|
state.config = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchFiles() {
|
async function fetchFiles() {
|
||||||
if (AppConfig.Modes.Sinkhole) {
|
if (state.config.Modes.Sinkhole) {
|
||||||
clearFileList();
|
clearFileList();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const files = await fetchFileList();
|
const files = await fetchFileList();
|
||||||
Files = {};
|
state.files = {};
|
||||||
clearFileList();
|
clearFileList();
|
||||||
renderFileList(files);
|
renderFileList(files);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -58,7 +60,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function fetchFileList() {
|
async function fetchFileList() {
|
||||||
const res = await fetch(AppConfig.Endpoints.Files, { cache: "no-store" });
|
const res = await fetch(state.config.Endpoints.Files, {
|
||||||
|
cache: "no-store",
|
||||||
|
});
|
||||||
if (!res.ok) throw new Error("HTTP " + res.status);
|
if (!res.ok) throw new Error("HTTP " + res.status);
|
||||||
return res.json();
|
return res.json();
|
||||||
}
|
}
|
||||||
@@ -69,7 +73,7 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
AppConfig.Endpoints.FilesDelete.replace(
|
state.config.Endpoints.FilesDelete.replace(
|
||||||
":filename",
|
":filename",
|
||||||
encodeURIComponent(file.Name)
|
encodeURIComponent(file.Name)
|
||||||
),
|
),
|
||||||
@@ -89,20 +93,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addEventListeners() {
|
function addEventListeners() {
|
||||||
UI.dropzone.addEventListener("click", () => UI.fileInput.click());
|
state.ui.dropzone.addEventListener("click", () =>
|
||||||
UI.fileInput.addEventListener("change", () => {
|
state.ui.fileInput.click()
|
||||||
if (UI.fileInput.files.length > 0) uploadFiles(UI.fileInput.files);
|
);
|
||||||
|
state.ui.fileInput.addEventListener("change", () => {
|
||||||
|
if (state.ui.fileInput.files.length > 0)
|
||||||
|
uploadFiles(state.ui.fileInput.files);
|
||||||
});
|
});
|
||||||
UI.dropzone.addEventListener("dragover", (e) => {
|
state.ui.dropzone.addEventListener("dragover", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
UI.dropzone.style.borderColor = "#0fff50";
|
state.ui.dropzone.style.borderColor = "#0fff50";
|
||||||
});
|
});
|
||||||
UI.dropzone.addEventListener("dragleave", () => {
|
state.ui.dropzone.addEventListener("dragleave", () => {
|
||||||
UI.dropzone.style.borderColor = "#888";
|
state.ui.dropzone.style.borderColor = "#888";
|
||||||
});
|
});
|
||||||
UI.dropzone.addEventListener("drop", (e) => {
|
state.ui.dropzone.addEventListener("drop", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
UI.dropzone.style.borderColor = "#888";
|
state.ui.dropzone.style.borderColor = "#888";
|
||||||
if (e.dataTransfer.files.length > 0) uploadFiles(e.dataTransfer.files);
|
if (e.dataTransfer.files.length > 0) uploadFiles(e.dataTransfer.files);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -164,14 +171,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearFileList() {
|
function clearFileList() {
|
||||||
if (UI.fileList) UI.fileList.innerHTML = "";
|
if (state.ui.fileList) state.ui.fileList.innerHTML = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDownloadLink(file) {
|
function createDownloadLink(file) {
|
||||||
const size = humanReadableSize(file.Size);
|
const size = humanReadableSize(file.Size);
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.className = "download-link";
|
link.className = "download-link";
|
||||||
link.href = AppConfig.Endpoints.FilesGet.replace(
|
link.href = state.config.Endpoints.FilesGet.replace(
|
||||||
":filename",
|
":filename",
|
||||||
encodeURIComponent(file.Name)
|
encodeURIComponent(file.Name)
|
||||||
);
|
);
|
||||||
@@ -190,10 +197,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function finishUpload(success) {
|
function finishUpload(success) {
|
||||||
UI.overallProgressContainer.style.display = "none";
|
state.ui.overallProgressContainer.style.display = "none";
|
||||||
UI.overallProgress.value = 0;
|
state.ui.overallProgress.value = 0;
|
||||||
UI.overallStatus.textContent = "";
|
state.ui.overallStatus.textContent = "";
|
||||||
UI.currentFileName.textContent = "";
|
state.ui.currentFileName.textContent = "";
|
||||||
fetchFiles();
|
fetchFiles();
|
||||||
if (success) {
|
if (success) {
|
||||||
showSuccess("Upload successful");
|
showSuccess("Upload successful");
|
||||||
@@ -201,16 +208,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getUIElements() {
|
function getUIElements() {
|
||||||
UI.currentFileName = document.getElementById("currentFileName");
|
state.ui.currentFileName = document.getElementById("currentFileName");
|
||||||
UI.dropzone = document.getElementById("dropzone");
|
state.ui.dropzone = document.getElementById("dropzone");
|
||||||
UI.fileInput = document.getElementById("fileInput");
|
state.ui.fileInput = document.getElementById("fileInput");
|
||||||
UI.fileList = document.getElementById("file-list");
|
state.ui.fileList = document.getElementById("file-list");
|
||||||
UI.overallProgress = document.getElementById("overallProgress");
|
state.ui.overallProgress = document.getElementById("overallProgress");
|
||||||
UI.overallStatus = document.getElementById("overallStatus");
|
state.ui.overallStatus = document.getElementById("overallStatus");
|
||||||
UI.overallProgressContainer = document.getElementById(
|
state.ui.overallProgressContainer = document.getElementById(
|
||||||
"overallProgressContainer"
|
"overallProgressContainer"
|
||||||
);
|
);
|
||||||
UI.sinkholeModeInfo = document.getElementById("sinkholeModeInfo");
|
state.ui.sinkholeModeInfo = document.getElementById("sinkholeModeInfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
function humanReadableSize(bytes) {
|
function humanReadableSize(bytes) {
|
||||||
@@ -232,26 +239,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initUIProgress() {
|
function initUIProgress() {
|
||||||
UI.overallProgressContainer.style.display = "block";
|
state.ui.overallProgressContainer.style.display = "block";
|
||||||
UI.overallProgress.value = 0;
|
state.ui.overallProgress.value = 0;
|
||||||
UI.overallStatus.textContent = "";
|
state.ui.overallStatus.textContent = "";
|
||||||
UI.currentFileName.textContent = "";
|
state.ui.currentFileName.textContent = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFileList(files) {
|
function renderFileList(files) {
|
||||||
if (!UI.fileList) return;
|
if (!state.ui.fileList) return;
|
||||||
|
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
Files[file.Name] = true;
|
state.files[file.Name] = true;
|
||||||
|
|
||||||
const li = document.createElement("li");
|
const li = document.createElement("li");
|
||||||
li.appendChild(createDownloadLink(file));
|
li.appendChild(createDownloadLink(file));
|
||||||
|
|
||||||
if (!AppConfig.Modes.Readonly) {
|
if (!state.config.Modes.Readonly) {
|
||||||
li.appendChild(createDeleteLink(file));
|
li.appendChild(createDeleteLink(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
UI.fileList.appendChild(li);
|
state.ui.fileList.appendChild(li);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,15 +307,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showMessage(msg, type, duration = 2000) {
|
function showMessage(msg, type, duration = 2000) {
|
||||||
UI.dropzone.innerHTML = msg;
|
state.ui.dropzone.innerHTML = msg;
|
||||||
UI.dropzone.classList.add(type);
|
state.ui.dropzone.classList.add(type);
|
||||||
|
|
||||||
if (ErrorTimeout) clearTimeout(ErrorTimeout);
|
if (state.errorTimeout) clearTimeout(state.errorTimeout);
|
||||||
|
|
||||||
ErrorTimeout = setTimeout(() => {
|
state.errorTimeout = setTimeout(() => {
|
||||||
UI.dropzone.innerHTML = DEFAULT_DROPZONE_TEXT;
|
state.ui.dropzone.innerHTML = DEFAULT_DROPZONE_TEXT;
|
||||||
UI.dropzone.classList.remove(type);
|
state.ui.dropzone.classList.remove(type);
|
||||||
ErrorTimeout = null;
|
state.errorTimeout = null;
|
||||||
}, duration);
|
}, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,18 +324,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateUI() {
|
function updateUI() {
|
||||||
if (AppConfig.Modes.Readonly) {
|
if (state.config.Modes.Readonly) {
|
||||||
UI.dropzone.style.display = "none";
|
state.ui.dropzone.style.display = "none";
|
||||||
} else {
|
} else {
|
||||||
UI.dropzone.style.display = "block";
|
state.ui.dropzone.style.display = "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AppConfig.Modes.Sinkhole) {
|
if (state.config.Modes.Sinkhole) {
|
||||||
UI.fileList.style.display = "none";
|
state.ui.fileList.style.display = "none";
|
||||||
UI.sinkholeModeInfo.style.display = "block";
|
state.ui.sinkholeModeInfo.style.display = "block";
|
||||||
} else {
|
} else {
|
||||||
UI.fileList.style.display = "block";
|
state.ui.fileList.style.display = "block";
|
||||||
UI.sinkholeModeInfo.style.display = "none";
|
state.ui.sinkholeModeInfo.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +360,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const file = files[currentIndex];
|
const file = files[currentIndex];
|
||||||
UI.currentFileName.textContent = file.name;
|
state.ui.currentFileName.textContent = file.name;
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
@@ -386,7 +393,7 @@
|
|||||||
uploadNext();
|
uploadNext();
|
||||||
});
|
});
|
||||||
|
|
||||||
xhr.open("POST", AppConfig.Endpoints.Upload);
|
xhr.open("POST", state.config.Endpoints.Upload);
|
||||||
xhr.send(form);
|
xhr.send(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +403,7 @@
|
|||||||
|
|
||||||
function updateProgressUI(totalUploaded, totalSize, startTime) {
|
function updateProgressUI(totalUploaded, totalSize, startTime) {
|
||||||
const percent = (totalUploaded / totalSize) * 100;
|
const percent = (totalUploaded / totalSize) * 100;
|
||||||
UI.overallProgress.value = percent;
|
state.ui.overallProgress.value = percent;
|
||||||
|
|
||||||
const elapsed = (Date.now() - startTime) / 1000;
|
const elapsed = (Date.now() - startTime) / 1000;
|
||||||
const speed = totalUploaded / elapsed;
|
const speed = totalUploaded / elapsed;
|
||||||
@@ -407,7 +414,7 @@
|
|||||||
const min = Math.floor(etaSec / 60);
|
const min = Math.floor(etaSec / 60);
|
||||||
const sec = Math.floor(etaSec % 60);
|
const sec = Math.floor(etaSec % 60);
|
||||||
|
|
||||||
UI.overallStatus.textContent =
|
state.ui.overallStatus.textContent =
|
||||||
`${percent.toFixed(1)}% (${(totalSize / 1024 / 1024).toFixed(
|
`${percent.toFixed(1)}% (${(totalSize / 1024 / 1024).toFixed(
|
||||||
1
|
1
|
||||||
)} MB total) — ` +
|
)} MB total) — ` +
|
||||||
@@ -423,7 +430,7 @@
|
|||||||
showError("Invalid filename: .upload");
|
showError("Invalid filename: .upload");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (safeName in Files) {
|
if (safeName in state.files) {
|
||||||
showError("File already exists: " + f.name);
|
showError("File already exists: " + f.name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user