globalThis.Wegwichtel ??= {}; (function (ns) { 'use strict'; const LOCAL_REFERENCE = 5 * 1024 * 1024; let initialized = false; let lastError = ''; let refreshTask = null; function format(bytes) { return `${(bytes / 1000000).toLocaleString(ns.I18n.language, { maximumFractionDigits: 1 })} MB`; } function localBytes() { const storage = globalThis.localStorage; if (!storage) return null; let bytes = 0; for (let index = 0; index < storage.length; index += 1) { const key = storage.key(index); if (key != null) bytes += 2 * (key.length + (storage.getItem(key) || '').length); } return bytes; } function show(selector, usage, quota, text) { for (const panel of document.querySelectorAll('[data-storage-usage]')) { const meter = panel.querySelector(`[data-storage-${selector}-meter]`); const label = panel.querySelector(`[data-storage-${selector}-text]`); if (meter) { meter.hidden = !quota; if (quota) { meter.max = quota; meter.value = Math.min(usage, quota); } } if (label) label.textContent = text; } } function siteDescription(usage, quota, known) { if (!known) return ns.I18n.t("storage-usage.der.freie.platz.konnte.nicht.gemessen.werden"); const warning = usage / quota >= .9 ? ns.I18n.t("storage-usage.fast.voll.entferne.inhalte.die.du.nicht") : ''; return ns.I18n.t("storage-usage.app.bilder.und.ton.des.verfugbaren.platzes", { value1: Math.round(usage / quota * 100), value2: format(Math.max(0, quota - usage)), value3: warning }); } function localDescription(local) { if (local == null) return ns.I18n.t("storage-usage.texte.und.einstellungen.konnen.hier.gerade.nicht"); const warning = local >= LOCAL_REFERENCE * .9 ? ns.I18n.t("storage-usage.der.balken.ist.fast.voll.grosse.bilder") : ''; return ns.I18n.t("storage-usage.texte.und.einstellungen.ungefahr.belegt.der.balken", { value1: format(local), value2: warning }); } async function refresh() { if (refreshTask) return refreshTask; refreshTask = (async () => { let estimate = null; try { estimate = await navigator.storage?.estimate?.(); } catch { /* Display unknown rather than a guessed quota. */ } const usage = estimate?.usage; const quota = estimate?.quota; const known = Number.isFinite(usage) && Number.isFinite(quota) && quota > 0; show('site', usage, known ? quota : null, siteDescription(usage, quota, known)); let local = null; try { local = localBytes(); } catch { /* Storage can be blocked by browser settings. */ } show('local', local, local == null ? null : LOCAL_REFERENCE, localDescription(local)); for (const panel of document.querySelectorAll('[data-storage-usage]')) { const warning = panel.querySelector('[data-storage-warning]'); if (warning) { warning.hidden = !lastError; warning.textContent = lastError; } } })().finally(() => { refreshTask = null; }); return refreshTask; } function reportError(error) { let current = error; while (current) { if (current.name === 'QuotaExceededError') { lastError = ns.I18n.t("storage-usage.der.platz.ist.voll.entferne.gespeicherte.strecken"); break; } current = current.cause; } void refresh(); } function initialize() { if (initialized) return; initialized = true; document.addEventListener('wegwichtel:local-routes-changed', () => { lastError = ''; void refresh(); }); document.addEventListener('wegwichtel:storage-error', event => reportError(event.detail)); document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') void refresh(); }); globalThis.addEventListener?.('storage', () => { void refresh(); }); globalThis.addEventListener?.('focus', () => { void refresh(); }); for (const button of document.querySelectorAll('[data-storage-refresh]')) button.addEventListener('click', () => { void refresh(); }); void refresh(); } ns.StorageUsage = Object.freeze({ initialize, refresh, reportError }); }(globalThis.Wegwichtel));