/** * GoingsOn — Query State Helper * * Phase 7 Tier 4 — every filter / sort / view-mode setting that changes what * the user sees must be mirrored to `location.search` so reload, deep-link, * and back-button preserve the state (see docs/design-system.md § Filter & * view state in the URL). One helper, one set of conventions. * * Conventions: * - Writes use `history.replaceState` so each filter change doesn't push a * new history entry. The back button still works for view navigation * (which uses router.js's pushState). * - Empty values are removed from the URL — defaults render as a clean path. * - On view-switch, `router.js#navigate(path)` writes only the new path, * wiping the previous view's query. Each view restores its own state on * load via `read(name)`. */ (function() { 'use strict'; /** * Read a single query-string value by name. Returns null if absent or empty. */ function read(name) { const v = new URLSearchParams(location.search).get(name); return v == null || v === '' ? null : v; } /** * Read multiple keys at once. Returns an object; absent keys are omitted. */ function readMany(names) { const params = new URLSearchParams(location.search); const out = {}; for (const n of names) { const v = params.get(n); if (v != null && v !== '') out[n] = v; } return out; } /** * Write a single value. Removes the key when value is null / undefined / empty / false. * Uses replaceState — does not push history. */ function write(name, value) { const params = new URLSearchParams(location.search); if (value == null || value === '' || value === false) { params.delete(name); } else if (value === true) { params.set(name, '1'); } else { params.set(name, String(value)); } const qs = params.toString(); const path = location.pathname + (qs ? '?' + qs : ''); try { history.replaceState({ path }, '', path); } catch (_) { /* ignore — file:// or sandboxed contexts */ } } /** * Batch-write. Same key removal rules as `write`. */ function writeMany(obj) { const params = new URLSearchParams(location.search); for (const [name, value] of Object.entries(obj)) { if (value == null || value === '' || value === false) { params.delete(name); } else if (value === true) { params.set(name, '1'); } else { params.set(name, String(value)); } } const qs = params.toString(); const path = location.pathname + (qs ? '?' + qs : ''); try { history.replaceState({ path }, '', path); } catch (_) { /* ignore */ } } /** * Remove a list of keys. */ function clear(names) { const params = new URLSearchParams(location.search); for (const n of names) params.delete(n); const qs = params.toString(); const path = location.pathname + (qs ? '?' + qs : ''); try { history.replaceState({ path }, '', path); } catch (_) { /* ignore */ } } GoingsOn.queryState = { read, readMany, write, writeMany, clear }; })();