const boxPanel = document.querySelector(".box-panel[data-box-id]");
const boxStatus = document.querySelector(".box-statusbar span:first-child");
const boxAddress = document.querySelector("#box-address");
const boxExpiryMeta = document.querySelector(".box-meta[data-expires-at]");
const boxExpiryText = document.querySelector("#box-expiry-text");
const contextMenu = document.querySelector("#box-context-menu");
const docPopup = document.querySelector("#doc-popup");
const docPopupTitle = document.querySelector("#doc-popup-title");
const docPopupBody = document.querySelector("#doc-popup-body");
const docPopupClose = document.querySelector("#doc-popup-close");
const modalBackdrop = document.querySelector("#modal-backdrop");
const toast = document.querySelector("#toast");
const zipOnly = boxPanel && boxPanel.dataset.zipOnly === "true";
let contextFile = null;
let lastStatusSignature = "";
function htmlEscape(value) {
return String(value || "")
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
function showToast(message, type = "info") {
window.WarpBoxUI.toast(message, type, { target: toast });
}
function openPopup(title, html, options = {}) {
window.WarpBoxUI.openPopup(title, html, {
...options,
popup: docPopup,
title: docPopupTitle,
body: docPopupBody,
backdrop: modalBackdrop,
});
}
function closePopup() {
window.WarpBoxUI.closePopup({ popup: docPopup, backdrop: modalBackdrop });
}
function currentExpiryDate() {
const value = boxExpiryMeta?.dataset.expiresAt || "";
if (!value) return null;
const date = new Date(value);
return Number.isNaN(date.getTime()) ? null : date;
}
function formatDuration(ms) {
if (ms <= 0) return "expired";
const totalSeconds = Math.ceil(ms / 1000);
const days = Math.floor(totalSeconds / 86400);
const hours = Math.floor((totalSeconds % 86400) / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
if (days) return `${days}d ${hours}h ${minutes}m`;
if (hours) return `${hours}h ${minutes}m ${seconds}s`;
if (minutes) return `${minutes}m ${seconds}s`;
return `${seconds}s`;
}
function updateExpiryCountdown() {
if (!boxExpiryText || !boxExpiryMeta) return;
const expiry = currentExpiryDate();
if (!expiry) {
boxExpiryText.textContent = "Expires after one-time download";
return;
}
boxExpiryText.textContent = `Expires in ${formatDuration(expiry.getTime() - Date.now())}`;
boxExpiryText.title = `Expires at ${expiry.toLocaleString()}`;
}
function closeContextMenu() {
contextMenu?.classList.remove("is-visible");
contextMenu?.setAttribute("aria-hidden", "true");
}
function showContextMenu(file, x, y) {
if (!contextMenu) return;
contextFile = file;
contextMenu.style.left = `${Math.min(x, window.innerWidth - 190)}px`;
contextMenu.style.top = `${Math.min(y, window.innerHeight - 98)}px`;
contextMenu.classList.add("is-visible");
contextMenu.setAttribute("aria-hidden", "false");
}
function fileData(item) {
return {
id: item.dataset.fileId || "",
name: item.dataset.name || item.querySelector(".box-file-name")?.textContent || "",
size: item.dataset.size || "",
mime: item.dataset.mime || "",
status: item.dataset.status || "",
statusLabel: item.querySelector(".box-file-meta")?.textContent || "",
downloadPath: item.dataset.downloadPath || item.getAttribute("href") || "",
thumbnail: item.dataset.thumbnail || "",
canDownload: item.getAttribute("aria-disabled") !== "true" && item.getAttribute("href") !== "#",
};
}
function downloadFile(item) {
const data = fileData(item);
if (!data.canDownload) {
showToast(zipOnly ? "Individual file downloads are disabled for one-time boxes. Use Download Zip." : "This file is not ready for download yet.", "warning");
return;
}
window.location.href = data.downloadPath;
setTimeout(refreshBoxStatus, 900);
}
function previewURL(data) {
return data.canDownload ? data.downloadPath : "";
}
async function previewFile(item) {
const data = fileData(item);
if (zipOnly) {
showToast("Previews are disabled for one-time boxes. Use Download Zip.", "warning");
return;
}
const url = previewURL(data);
if (!url) {
showToast("This file is not ready to preview yet.", "warning");
return;
}
const mime = data.mime.toLowerCase();
const name = htmlEscape(data.name);
if (mime.startsWith("image/")) {
openPopup(`${data.name} preview`, ``, { preview: true });
return;
}
if (mime.startsWith("video/")) {
openPopup(`${data.name} preview`, ``, { preview: true });
return;
}
if (mime.startsWith("audio/")) {
openPopup(`${data.name} preview`, ``, { preview: true });
return;
}
if (mime === "application/pdf") {
openPopup(`${data.name} preview`, ``, { preview: true });
return;
}
if (mime.startsWith("text/") || /\.(txt|md|json|csv|log|html|css|js)$/i.test(data.name)) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error("Preview failed");
const text = await response.text();
openPopup(`${data.name} preview`, `
${htmlEscape(text.slice(0, 120000))}`, { preview: true });
} catch (_) {
showToast("The browser could not load a text preview.", "error");
}
return;
}
showToast("This file type cannot be previewed in the browser.", "warning");
}
function showProperties(item) {
const data = fileData(item);
const url = data.downloadPath ? new URL(data.downloadPath, window.location.origin).toString() : "Not ready";
openPopup(`${data.name} Properties`, `
Clipboard access failed. Copy this URL manually.
`); } }); docPopupClose?.addEventListener("click", closePopup); modalBackdrop?.addEventListener("click", closePopup); document.addEventListener("keydown", (event) => { if (event.key === "Escape") { closePopup(); closeContextMenu(); } }); updateExpiryCountdown(); setInterval(updateExpiryCountdown, 1000); if (boxPanel) { const pollMS = Number.parseInt(boxPanel.dataset.pollMs, 10) || 5000; startStagedPolling(pollMS); }