Files
WarpBox/static/js/upload/state.js

161 lines
6.2 KiB
JavaScript

const SETTINGS_KEY = "warpbox.upload.settings.v1";
const el = {
form: document.querySelector("#upload-form"),
fileInput: document.querySelector("#file-upload"),
dropSurface: document.querySelector("#drop-surface"),
dropzone: document.querySelector("#dropzone"),
fileList: document.querySelector("#file-list"),
queueLabel: document.querySelector("#queue-label"),
queueSize: document.querySelector("#queue-size"),
limitHint: document.querySelector("#limit-hint"),
boxSpaceText: document.querySelector("#box-space-text"),
boxSpaceBar: document.querySelector("#box-space-bar"),
overallBar: document.querySelector("#overall-bar"),
overallPercent: document.querySelector("#overall-percent"),
shareLink: document.querySelector("#share-link"),
copyButton: document.querySelector("#copy-button"),
startButton: document.querySelector("#start-button"),
statusText: document.querySelector("#status-text"),
toast: document.querySelector("#toast"),
terminal: document.querySelector("#terminal-box"),
copyCurlButton: document.querySelector("#copy-curl-button"),
docPopup: document.querySelector("#doc-popup"),
modalBackdrop: document.querySelector("#modal-backdrop"),
docPopupTitle: document.querySelector("#doc-popup-title"),
docPopupBody: document.querySelector("#doc-popup-body"),
docPopupClose: document.querySelector("#doc-popup-close"),
expiry: document.querySelector("#expiry-select"),
password: document.querySelector("#password-input"),
optionsForm: document.querySelector("#box-options-form"),
maxViews: document.querySelector("#max-views"),
boxName: document.querySelector("#box-name"),
customSlug: document.querySelector("#custom-slug"),
downloadPage: document.querySelector("#download-page"),
allowZip: document.querySelector("#allow-zip"),
allowPreview: document.querySelector("#allow-preview"),
keepFilenames: document.querySelector("#keep-filenames"),
privateBox: document.querySelector("#private-box"),
apiKeyMode: document.querySelector("#api-key-mode"),
apiKeyInput: document.querySelector("#api-key-input"),
apiKeyRow: document.querySelector("#api-key-row"),
apiKeyState: document.querySelector("#api-key-state"),
};
const uploadsEnabled = el.form?.dataset.uploadsEnabled === "true";
const defaultRetention = el.form?.dataset.defaultRetention || "10s";
const maxFileBytes = numberFromDataset(el.form?.dataset.maxFileBytes);
const maxBoxBytes = numberFromDataset(el.form?.dataset.maxBoxBytes);
const oneTimeRetentionKey = "one-time";
let files = [];
let shareUrl = "";
let uploadLocked = false;
let statusTimer = null;
let pendingDuplicateFiles = [];
let apiKeyTimer = null;
let completedImpactKeys = new Set();
let overallImpactDone = false;
function numberFromDataset(value) {
const number = Number.parseInt(value || "0", 10);
return Number.isFinite(number) && number > 0 ? number : 0;
}
function formatBytes(bytes) {
if (!bytes) return "0 B";
const units = ["B", "KB", "MB", "GB", "TB"];
let value = bytes;
let unit = 0;
while (value >= 1024 && unit < units.length - 1) {
value /= 1024;
unit += 1;
}
return `${value.toFixed(value >= 10 || unit === 0 ? 0 : 1)} ${units[unit]}`;
}
const htmlEscape = window.WarpBoxUI.htmlEscape;
function shellQuote(value) {
return `'${String(value).replaceAll("'", "'\\''")}'`;
}
function totalBytes() {
return files.reduce((sum, item) => sum + item.file.size, 0);
}
function uploadedBytes() {
return files.reduce((sum, item) => sum + item.loaded, 0);
}
function overallProgress() {
const total = totalBytes();
return total ? Math.round((uploadedBytes() / total) * 100) : 0;
}
function oversizedFiles() {
return maxFileBytes ? files.filter((item) => item.file.size > maxFileBytes) : [];
}
function isOverBoxQuota() {
return maxBoxBytes ? totalBytes() > maxBoxBytes : false;
}
function hasQuotaError() {
return isOverBoxQuota() || oversizedFiles().length > 0;
}
function normalizedFileName(name) {
return String(name || "").trim().toLowerCase();
}
function splitNameForIncrement(name) {
const value = String(name || "file");
const dot = value.lastIndexOf(".");
if (dot > 0 && dot < value.length - 1) return [value.slice(0, dot), value.slice(dot)];
return [value, ""];
}
function nextIncrementedFileName(name, usedNames) {
const [base, ext] = splitNameForIncrement(name);
let index = 2;
let candidate = `${base} (${index})${ext}`;
while (usedNames.has(normalizedFileName(candidate))) {
index += 1;
candidate = `${base} (${index})${ext}`;
}
usedNames.add(normalizedFileName(candidate));
return candidate;
}
function makeQueuedFile(file, displayName = file.name) {
return {
file,
displayName,
loaded: 0,
uploaded: false,
failed: false,
error: "",
row: null,
boxID: "",
boxFile: null,
previewURL: file.type?.startsWith("image/") ? URL.createObjectURL(file) : "",
};
}
function iconForFile(file) {
const filename = file.name || "";
const mimeType = file.type || "";
const extension = filename.includes(".") ? filename.slice(filename.lastIndexOf(".")).toLowerCase() : "";
if (extension === ".exe") return "/static/img/icons/Program Files Icons - PNG/MSONSEXT.DLL_14_6-0.png";
if (mimeType.startsWith("image/")) return "/static/img/sprites/bitmap.png";
if (mimeType.startsWith("video/") || mimeType.startsWith("audio/")) return "/static/img/icons/netshow_notransm-1.png";
if (mimeType.startsWith("text/") || extension === ".md") return "/static/img/sprites/notepad_file-1.png";
if (mimeType.includes("zip") || mimeType.includes("compressed") || [".rar", ".7z", ".tar", ".gz"].includes(extension)) return "/static/img/icons/Windows Icons - PNG/zipfldr.dll_14_101-0.png";
if ([".ttf", ".otf", ".woff", ".woff2"].includes(extension)) return "/static/img/sprites/font.png";
if (extension === ".pdf") return "/static/img/sprites/journal.png";
if ([".html", ".css", ".js"].includes(extension)) return "/static/img/sprites/frame_web-0.png";
return "/static/img/icons/Windows Icons - PNG/ole2.dll_14_DEFICON.png";
}