Three merge-fallout bugs that combined to leave the services grid empty
and most UI inert:
1. error-handler.js was bundled into onboarding.js (loaded 3rd), but
globals.js in core.js (loaded 1st) does `const errorHandler = new
ErrorHandler()` at top level. ErrorHandler was undefined when core.js
ran -> ReferenceError -> globals.js stopped, so window.APPS,
_showTotpOverlay, loadServices, etc. were never set, and init.js
blew up on every call into core's exports.
Moved error-handler.js to the start of the core.js bundle so the
class is on window before any other script touches it.
2. setup-wizard.js also declared `const errorHandler = new ErrorHandler()`
at top level. Classic scripts share the document's top-level lexical
environment, so this collided with globals.js's declaration ->
redeclaration SyntaxError in features.js. Removed setup-wizard.js's
copy; it picks up the global one.
3. tooltip-definitions.js closed its `(function(window){...})(window);`
IIFE at line ~171 ("Validation module loaded"), then the TOOLTIP_
DEFINITIONS array, getter helpers, window.TooltipDefinitions export,
and final `debug(...)` log all sat at top level — outside the IIFE,
where `debug` was no longer in scope. Removed the early close and
added one at EOF so the whole file is in one IIFE.
119 lines
3.5 KiB
JavaScript
119 lines
3.5 KiB
JavaScript
const CACHE = 'dashcaddy-shell-48970e1876';
|
|
const PRECACHE = [
|
|
'/',
|
|
'/index.html',
|
|
'/css/themes.css',
|
|
'/css/dashboard.css',
|
|
'/css/driver.min.css',
|
|
'/css/onboarding.css',
|
|
'/dist/core.js',
|
|
'/dist/features.js',
|
|
'/dist/init.js',
|
|
'/dist/onboarding.js',
|
|
'/assets/fonts.css',
|
|
'/assets/site.webmanifest',
|
|
'/assets/favicon.svg',
|
|
'/assets/dashcaddy-favicon.ico',
|
|
'/assets/icon-192.png',
|
|
'/assets/icon-512.png',
|
|
'/assets/apple-touch-icon.png',
|
|
'/assets/dashcaddy-logo-dark.png',
|
|
'/assets/dashcaddy-logo-light.png',
|
|
'/assets/sami7777-logo.png',
|
|
'/assets/fonts/sami-grotesk/SamiGrotesk-Regular.woff2',
|
|
'/assets/fonts/sami-grotesk/SamiGrotesk-Medium.woff2',
|
|
'/assets/fonts/sami-grotesk/SamiGrotesk-Bold.woff2',
|
|
'/assets/fonts/DSEG7Classic-Bold.woff2',
|
|
'/assets/weather/clear-day.svg',
|
|
'/assets/weather/clear-night.svg',
|
|
'/assets/weather/partly-cloudy-day.svg',
|
|
'/assets/weather/partly-cloudy-night.svg',
|
|
'/assets/weather/cloudy.svg',
|
|
'/assets/weather/fog.svg',
|
|
'/assets/weather/drizzle.svg',
|
|
'/assets/weather/rain.svg',
|
|
'/assets/weather/sleet.svg',
|
|
'/assets/weather/snow.svg',
|
|
'/assets/weather/thunderstorm.svg',
|
|
'/assets/weather/wind.svg'
|
|
];
|
|
|
|
function isNavigationRequest(request) {
|
|
return request.mode === 'navigate';
|
|
}
|
|
|
|
function isStaticAsset(pathname) {
|
|
return pathname.startsWith('/assets/')
|
|
|| pathname.startsWith('/css/')
|
|
|| pathname.startsWith('/dist/');
|
|
}
|
|
|
|
async function networkFirst(request, preloadResponsePromise) {
|
|
const cache = await caches.open(CACHE);
|
|
try {
|
|
const preloadResponse = preloadResponsePromise ? await preloadResponsePromise : null;
|
|
if (preloadResponse) {
|
|
cache.put(request, preloadResponse.clone()).catch(() => {});
|
|
return preloadResponse;
|
|
}
|
|
const response = await fetch(request);
|
|
cache.put(request, response.clone()).catch(() => {});
|
|
return response;
|
|
} catch (_) {
|
|
return caches.match(request) || caches.match('/index.html');
|
|
}
|
|
}
|
|
|
|
async function staleWhileRevalidate(request) {
|
|
const cache = await caches.open(CACHE);
|
|
const cached = await cache.match(request);
|
|
|
|
const networkPromise = fetch(request)
|
|
.then((response) => {
|
|
cache.put(request, response.clone()).catch(() => {});
|
|
return response;
|
|
})
|
|
.catch(() => null);
|
|
|
|
if (cached) return cached;
|
|
return networkPromise.then((response) => response || Response.error());
|
|
}
|
|
|
|
self.addEventListener('install', (event) => {
|
|
self.skipWaiting();
|
|
event.waitUntil(
|
|
caches.open(CACHE).then((cache) =>
|
|
cache.addAll(PRECACHE.map((url) => new Request(url, { cache: 'reload' })))
|
|
)
|
|
);
|
|
});
|
|
|
|
self.addEventListener('activate', (event) => {
|
|
event.waitUntil((async () => {
|
|
const keys = await caches.keys();
|
|
await Promise.all(keys.filter((key) => key !== CACHE).map((key) => caches.delete(key)));
|
|
if ('navigationPreload' in self.registration) {
|
|
await self.registration.navigationPreload.enable();
|
|
}
|
|
await self.clients.claim();
|
|
})());
|
|
});
|
|
|
|
self.addEventListener('fetch', (event) => {
|
|
const { request } = event;
|
|
if (request.method !== 'GET') return;
|
|
|
|
const url = new URL(request.url);
|
|
if (url.origin !== self.location.origin) return;
|
|
if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/probe/')) return;
|
|
|
|
if (isNavigationRequest(request) || url.pathname === '/' || url.pathname.endsWith('/index.html')) {
|
|
event.respondWith(networkFirst(request, event.preloadResponse));
|
|
return;
|
|
}
|
|
|
|
if (isStaticAsset(url.pathname)) {
|
|
event.respondWith(staleWhileRevalidate(request));
|
|
}
|
|
});
|