"use strict"; (function() { var pendingRegistration = null; var busy = false; var $ = function(id) { return document.getElementById(id); }; function formatSize(value) { var units = ["B", "KiB", "MiB", "GiB"]; var size = Number(value); var index = 0; while (size >= 1024 && index < units.length - 1) { size /= 1024; index++; } return size.toFixed(index ? 1 : 0) + " " + units[index]; } function setStatus(message, error) { $("status").textContent = message; $("status").classList.toggle("error", Boolean(error)); } async function api(path, options) { var response = await fetch(path, Object.assign({cache: "no-store"}, options || {})); var value; try { value = await response.json(); } catch (_) { value = null; } if (!response.ok) throw new Error("Management request failed."); return value; } async function copyUrl(url) { await navigator.clipboard.writeText(url); setStatus("Share URL copied.", false); } function actionButton(label, handler, className) { var button = document.createElement("button"); button.type = "button"; button.textContent = label; if (className) button.className = className; button.addEventListener("click", handler); return button; } function render(rows) { var body = $("drops"); body.textContent = ""; $("empty").classList.toggle("hidden", rows.length !== 0); rows.forEach(function(row) { var tr = document.createElement("tr"); [row.name, row.type || "application/octet-stream", formatSize(row.size), new Date(row.expiresAt * 1000).toLocaleString()].forEach(function(value) { var td = document.createElement("td"); td.textContent = value; tr.appendChild(td); }); var actions = document.createElement("td"); actions.className = "actions"; actions.appendChild(actionButton("Copy", function() { copyUrl(row.readUrl).catch(function() { setStatus("Unable to copy the share URL.", true); }); })); actions.appendChild(actionButton("Open", function() { window.open(row.readUrl, "_blank", "noopener,noreferrer"); })); actions.appendChild(actionButton("Delete", async function() { if (!window.confirm("Permanently delete " + row.name + "?")) return; try { await api("/manage/api/v1/drops/" + row.id, {method: "DELETE"}); await load(); setStatus("Drop deleted.", false); } catch (_) { setStatus("Delete failed.", true); } }, "danger")); tr.appendChild(actions); body.appendChild(tr); }); } async function load() { var value = await api("/manage/api/v1/list", { method: "POST", headers: {"Content-Type": "application/json"}, body: "{}" }); render(Array.isArray(value.drops) ? value.drops : []); } async function register(result) { await api("/manage/api/v1/register", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({readUrl: result.readUrl, deleteCapability: result.deleteCapability}) }); pendingRegistration = null; $("retry").classList.add("hidden"); await load(); } $("upload-form").addEventListener("submit", async function(event) { event.preventDefault(); if (busy) return; var file = $("file").files[0]; if (!file) return setStatus("Select a file.", true); busy = true; $("upload").disabled = true; $("progress").style.width = "0"; setStatus("Encrypting and uploading...", false); try { var result = await NeoDropCrypto.upload(file, { base: location.origin, profile: Number($("profile").value), onProgress: function(value) { $("progress").style.width = Math.round(value * 100) + "%"; } }); pendingRegistration = result; setStatus("Upload complete. Registering encrypted catalog entry...", false); try { await register(result); $("upload-form").reset(); setStatus("Encrypted drop uploaded and registered.", false); } catch (_) { $("retry").classList.remove("hidden"); setStatus("Upload succeeded, but catalog registration must be retried in this tab.", true); } } catch (error) { if (error.name !== "AbortError") setStatus(error.message || "Encrypted upload failed.", true); } finally { busy = false; $("upload").disabled = false; } }); $("retry").addEventListener("click", async function() { if (!pendingRegistration || busy) return; busy = true; try { await register(pendingRegistration); setStatus("Catalog registration completed.", false); } catch (_) { setStatus("Catalog registration failed; retry from this tab.", true); } finally { busy = false; } }); $("refresh").addEventListener("click", function() { load().then(function() { setStatus("Managed drops refreshed.", false); }) .catch(function() { setStatus("Unable to load managed drops.", true); }); }); load().catch(function() { setStatus("Unable to load managed drops.", true); }); }());