diff options
| author | godosa <godosa@godosa.eu> | 2026-10-07 00:14:38 +0200 |
|---|---|---|
| committer | godosa <godosa@godosa.eu> | 2026-10-07 00:14:38 +0200 |
| commit | 3443c1c65e9f1753e1e656b35d08416c1fa298f2 (patch) | |
| tree | 4e43236f460145a4d75d1b4616dcb7aa6ef08f51 /viewer/js/ui.js | |
| download | worldmap-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.js | 33 |
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; +} |
