aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/viewer/js/ui.js
diff options
context:
space:
mode:
authorgodosa <godosa@godosa.eu>2026-10-07 00:14:38 +0200
committergodosa <godosa@godosa.eu>2026-10-07 00:14:38 +0200
commit3443c1c65e9f1753e1e656b35d08416c1fa298f2 (patch)
tree4e43236f460145a4d75d1b4616dcb7aa6ef08f51 /viewer/js/ui.js
downloadworldmap-viewer-3443c1c65e9f1753e1e656b35d08416c1fa298f2.tar.gz
worldmap-viewer-3443c1c65e9f1753e1e656b35d08416c1fa298f2.zip
worldmap-viewer: initial public history
Diffstat (limited to 'viewer/js/ui.js')
-rw-r--r--viewer/js/ui.js33
1 files changed, 33 insertions, 0 deletions
diff --git a/viewer/js/ui.js b/viewer/js/ui.js
new file mode 100644
index 0000000..82a0505
--- /dev/null
+++ b/viewer/js/ui.js
@@ -0,0 +1,33 @@
+// ui.js — small DOM helpers (text only via append/textContent, never innerHTML)
+export const $ = (sel, root = document) => root.querySelector(sel);
+
+const SVG_NS = 'http://www.w3.org/2000/svg';
+export const el = (tag, attrs = {}, ...kids) => fill(document.createElement(tag), attrs, kids);
+export const svg = (tag, attrs = {}, ...kids) => fill(document.createElementNS(SVG_NS, tag), attrs, kids);
+
+function fill(e, attrs, kids) {
+ for (const [k, v] of Object.entries(attrs)) {
+ if (typeof v === 'function' && k.startsWith('on')) e.addEventListener(k.slice(2), v);
+ else if (v !== undefined && v !== null && v !== false) e.setAttribute(k, v === true ? '' : String(v));
+ }
+ for (const k of kids.flat()) if (k !== undefined && k !== null && k !== false) e.append(k);
+ return e;
+}
+
+let toastTimer;
+export function toast(msg, kind = 'error') {
+ const t = $('#toast');
+ t.textContent = msg;
+ t.className = `show ${kind}`;
+ clearTimeout(toastTimer);
+ toastTimer = setTimeout(() => { t.className = ''; }, 5000);
+}
+
+export async function api(url, { method = 'GET', body } = {}) {
+ const r = await fetch(url, { method, headers: body === undefined ? {} : { 'Content-Type': 'application/json' },
+ body: body === undefined ? undefined : JSON.stringify(body) });
+ if (r.status === 204) return null;
+ const data = await r.json().catch(() => ({}));
+ if (!r.ok) throw new Error(data.error || `${r.status} ${r.statusText}`);
+ return data;
+}