Files
hub/public/boot.js
T
nmemmertandClaude Sonnet 5.5 54d18594a3 Accessibility settings, deferred scripts, and offline reading of tasks, notes, recipes, calendar and contacts
Keeps saved episodes and shares when the app updates (they were being deleted with the old shell cache).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 10:23:38 -04:00

51 lines
3.5 KiB
JavaScript

'use strict';
// ---- Boot
(async () => {
try { cfg = { ...cfg, ...(await (await fetch('/api/config')).json()) }; } catch {}
const loadedBuild = cfg.build;
// When a new version is deployed, an open page keeps running the old one. Tell the person, and offer a reload.
const checkForUpdate = async () => {
try {
const c = await (await fetch('/api/config', { cache: 'no-store' })).json();
if (c.build && loadedBuild && c.build !== loadedBuild && !document.getElementById('upd')) {
const b = document.createElement('div'); b.id = 'upd';
b.innerHTML = 'A new version of NE Hub is available. <button class="btn" id="updgo">Reload</button>';
document.body.appendChild(b); document.getElementById('updgo').onclick = () => location.reload();
}
} catch {}
};
document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') checkForUpdate(); });
setInterval(checkForUpdate, 10 * 60e3);
await loadMe();
await loadSettings();
if (typeof themeStart === 'function') themeStart();
sgStart(); if (typeof chStart === 'function') chStart(); if (typeof kidStart === 'function') kidStart(); if (typeof devStart === 'function') devStart(); if (typeof simpleStart === 'function') simpleStart();
addEventListener('hashchange', route);
restorePlayer();
route();
shareCheck();
// Unread mail and tasks due (the badge): checked on a timer only while the app is on screen, and again the moment you come back to it.
const badgePoll = () => { mailPoll(); taskPoll(); };
let lastBadge = Date.now(); badgePoll();
setInterval(() => { if (document.visibilityState === 'visible') { lastBadge = Date.now(); badgePoll(); } }, 2 * 60e3);
document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible' && Date.now() - lastBadge > 30e3) { lastBadge = Date.now(); badgePoll(); } });
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').catch(() => {});
// tell the service worker who is signed in, so what it saves for offline use is kept for that person only
const who = () => navigator.serviceWorker.ready.then(r => (r.active || navigator.serviceWorker.controller || {}).postMessage && (r.active || navigator.serviceWorker.controller).postMessage({ type: 'who', id: ME ? ME.id : '' })).catch(() => {});
who(); navigator.serviceWorker.addEventListener('controllerchange', who);
}
// offline: say so once, and that what is on screen is the last saved copy
{ const note = () => { const el = document.getElementById('offnote') || Object.assign(document.createElement('div'), { id: 'offnote', role: 'status' }); el.textContent = 'You are offline. Showing what was last saved; changes need a connection.'; el.hidden = navigator.onLine; if (!el.isConnected) document.body.appendChild(el); };
addEventListener('offline', note); addEventListener('online', note); if (!navigator.onLine) note(); }
})();
// Keyboard (desktop): space play/pause, arrows seek, N/P next/previous.
addEventListener('keydown', e => {
const tag = e.target.tagName || '', k = e.key;
if (e.metaKey || e.ctrlKey || e.altKey || !cur() || document.body.classList.contains('onvideo') || /^(INPUT|TEXTAREA|SELECT)$/.test(tag) || (k === ' ' && /^(BUTTON|A)$/.test(tag))) return;
if (k === ' ') { e.preventDefault(); toggle(); }
else if (k === 'ArrowRight') pl.a.currentTime += 10; else if (k === 'ArrowLeft') pl.a.currentTime = Math.max(0, pl.a.currentTime - 10);
else if (k === 'n' || k === 'N') next(); else if (k === 'p' || k === 'P') prev();
});