This commit is contained in:
maurice committed 2026-11-14 18:25:54 +01:00
1 parent b444b5759d
commit a3067b011d
8 files changed
+123 -110

No files matched your search

+29 -75
View File
@@ -6,12 +6,13 @@ let notes = [];
let editing = null;
function notify(message, error = false) {
$("status").textContent = message;
$("status").dataset.error = String(error);
$("status").hidden = false;
const target = $("share-result").open ? $("result-feedback") : $("status");
target.textContent = message;
target.dataset.error = String(error);
target.hidden = false;
}
async function api(path, { method = "GET", body, accept = "text/plain", includeHeaders = false } = {}, auth = authorization) {
async function api(path, { method = "GET", body, accept = "text/plain" } = {}, auth = authorization) {
const headers = { Accept: accept };
if (auth) headers.Authorization = auth;
const response = await fetch(path, { method, body, headers, credentials: "omit", cache: "no-store" });
@@ -26,8 +27,7 @@ async function api(path, { method = "GET", body, accept = "text/plain", includeH
};
throw new Error(messages[response.status] || `The request failed (${response.status}). Please try again.`);
}
const data = accept === "application/json" ? await response.json() : await response.text();
return includeHeaders ? { data, headers: response.headers } : data;
return accept === "application/json" ? response.json() : response.text();
}
async function busy(button, action) {
@@ -96,7 +96,10 @@ function renderNotes() {
for (const note of filtered) {
const row = document.createElement("tr");
const name = cell(row, "");
name.append(action(note.id, () => openEntry(note), "link-button"));
const link = document.createElement("a");
link.href = sharePath(note.id, isUrl(note));
link.textContent = note.id;
name.append(link);
const type = document.createElement("small");
type.textContent = isUrl(note) ? "Short link" : note.language || "Plain text";
name.append(type);
@@ -154,7 +157,7 @@ function resetEditor() {
editing = null;
$("language").querySelector("[data-current]")?.remove();
$("editor-form").reset();
$("share-result").hidden = true;
$("share-result").close();
updateEditor();
}
@@ -199,53 +202,6 @@ function reference(value, url) {
return { id, url };
}
async function openPaste(id) {
$("preview").replaceChildren();
$("preview").hidden = true;
const highlighted = $("open-format").value === "html";
const { data: content, headers } = await api(sharePath(id, false), {
accept: highlighted ? "text/html" : "text/plain",
includeHeaders: true,
});
const counter = document.createElement("p");
counter.className = "badge view-counter";
counter.textContent = `Views: ${headers.get("x-paste-views")} / ${headers.get("x-paste-max-views") ?? "∞"}`;
$("preview").append(counter);
if (highlighted) {
const page = new DOMParser().parseFromString(content, "text/html");
const code = page.querySelector("main pre");
if (!code) throw new Error("The server returned an unexpected preview.");
$("preview").append(document.importNode(code, true));
} else {
const pre = document.createElement("pre");
pre.textContent = content;
$("preview").append(pre);
}
$("preview").hidden = false;
await loadNotes();
notify(`Opened ${id}. This read counts as a view.`);
}
async function openEntry(note) {
$("open-id").value = note.id;
$("open-kind").value = isUrl(note) ? "url" : "note";
updateOpen();
showPanel("open");
if (isUrl(note)) {
window.open(sharePath(note.id, true), "_blank", "noopener,noreferrer");
notify("The short link opens in a new tab. Refresh your collection to update its view count.");
} else {
await openPaste(note.id);
}
}
function updateOpen() {
const url = $("open-kind").value === "url";
$("format-field").hidden = url;
$("open-submit").textContent = url ? "Follow short link ↗" : "Open paste";
$("preview").hidden = true;
}
$("login-form").addEventListener("submit", event => {
event.preventDefault();
busy(event.submitter, async () => {
@@ -272,8 +228,6 @@ $("logout").addEventListener("click", () => {
$("login-form").reset();
$("logout").hidden = true;
$("session-label").textContent = "Anonymous";
$("preview").replaceChildren();
$("preview").hidden = true;
resetEditor();
renderNotes();
notify("Signed out.");
@@ -282,6 +236,7 @@ $("logout").addEventListener("click", () => {
$("editor-form").addEventListener("submit", event => {
event.preventDefault();
busy(event.submitter, async () => {
const current = editing;
const url = $("kind").value === "url";
const body = new URLSearchParams();
body.set(url ? "href" : "content", $("content").value);
@@ -290,22 +245,27 @@ $("editor-form").addEventListener("submit", event => {
if ($("max-views").value !== "") body.set("max_views", $("max-views").value);
const requested = $("custom-id").value.trim();
let path = url ? "/to" : $("once").checked ? "/once" : "";
if (editing) path = sharePath(editing.id, url);
if (current) path = sharePath(current.id, url);
else path = requested ? `${path}/${encodeURIComponent(requested)}` : path || "/";
const result = await api(path, { method: editing ? "PUT" : "POST", body });
const id = editing ? editing.id : result;
const result = await api(path, { method: current ? "PUT" : "POST", body });
const id = current ? current.id : result;
const link = new URL(sharePath(id, url), location.origin).href;
$("share-url").value = link;
$("share-link").href = link;
$("result-title").textContent = editing ? "Changes saved" : "Your share is ready";
$("share-result").hidden = false;
$("result-title").textContent = current ? "Changes saved" : "Your share is ready";
const message = `${current ? "Updated" : "Created"} ${id}.${requested && requested !== id ? " The requested ID was unavailable, so a new one was generated." : ""}`;
$("result-feedback").textContent = message;
$("result-feedback").dataset.error = "false";
$("result-feedback").hidden = false;
$("share-result").showModal();
$("share-url").focus();
$("share-url").select();
await loadNotes();
if (editing) {
if (current && editing === current) {
editing = notes.find(note => note.id === id) || editing;
$("expires").value = "";
updateEditor();
}
notify(`${editing ? "Updated" : "Created"} ${id}.${requested && requested !== id ? " The requested ID was unavailable, so a new one was generated." : ""}`);
});
});
@@ -322,17 +282,12 @@ $("copy-url").addEventListener("click", event => busy(event.currentTarget, async
$("open-form").addEventListener("submit", event => {
event.preventDefault();
busy(event.submitter, async () => {
try {
const ref = reference($("open-id").value, $("open-kind").value === "url");
$("open-kind").value = ref.url ? "url" : "note";
updateOpen();
if (ref.url) {
window.open(sharePath(ref.id, true), "_blank", "noopener,noreferrer");
notify("The short link opens in a new tab. Following it counts as a view.");
} else {
await openPaste(ref.id);
}
});
location.assign(sharePath(ref.id, ref.url));
} catch (error) {
notify(error.message, true);
}
});
for (const link of document.querySelectorAll("[data-panel]")) {
@@ -344,7 +299,6 @@ for (const link of document.querySelectorAll("[data-panel]")) {
$("kind").addEventListener("change", updateEditor);
$("once").addEventListener("change", updateEditor);
$("new-note").addEventListener("click", resetEditor);
$("open-kind").addEventListener("change", updateOpen);
$("search").addEventListener("input", renderNotes);
$("refresh").addEventListener("click", event => busy(event.currentTarget, loadNotes));
window.addEventListener("hashchange", () => showPanel(location.hash.slice(1)));