Files
simple/frontend/sw.js
T
catarrh 2a03c74941 cards: group the form into SCP80/SCP81 fieldsets, close the RU i18n gaps (v2.2.19)
- The card create/edit form now surrounds the SCP80 parameters (KIc/KID,
  SPI1/SPI2, TAR, counter, keys) with a bordered <fieldset> labelled
  'SCP80 (GSM 03.48, ETSI TS 102 225)' and the PSK pair (with the listener
  explanation) with one labelled 'SCP81 (HTTP OTA)'; the name/ICCID row and
  the list stay outside the groups.
- i18n: the SCP81 PSK note is translated now, plus the keys an audit found
  missing from the RU dictionary (Start, Clear, Loading..., Working...,
  APDU hex, CAP file (max 48 kB), Install from .cap, Card reader server is
  not connected, KIc/KID required messages, Memory (GET DATA FF21), the two
  no-secured-packet alerts, Select, event notification to the card?).
- Tests: html.test.js guards both fieldsets, their legends and that the PSK
  note and fields live inside the SCP81 group (401 frontend tests).
- Docs: help EN+RU Cards intro. SW cache otaman-v186.
2026-09-19 00:15:18 +03:00

70 lines
1.8 KiB
JavaScript

const CACHE = 'otaman-v186';
const URLS = [
'index.html',
'help.html',
'help-ru.html',
'style.css',
'sim.png',
'favicon.svg',
'icon-192.png',
'icon-512.png',
'manifest.json',
'des-bundle.js',
'aes-bundle.js',
'sim.svg',
'sim_anim.svg',
'nosim.svg',
];
self.addEventListener('install', e => {
e.waitUntil(
caches.open(CACHE).then(c => c.addAll(URLS))
);
self.skipWaiting();
});
self.addEventListener('activate', e => {
e.waitUntil(
caches.keys().then(keys =>
Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k)))
).then(() => clients.claim())
);
});
const OFFLINE_RESPONSE = new Response('Offline: page not cached', {
status: 503,
statusText: 'Offline',
headers: { 'Content-Type': 'text/plain' },
});
self.addEventListener('fetch', e => {
if (!e.request.url.startsWith('http')) return;
const path = new URL(e.request.url).pathname;
if (path.startsWith('/api/')) return; // live data, never cache
if (e.request.method !== 'GET') return;
const isNavigate = e.request.mode === 'navigate';
const isSwScript = path.endsWith('/sw.js');
if (isNavigate) {
e.respondWith(
fetch(e.request).then(res => {
const clone = res.clone();
caches.open(CACHE).then(c => c.put(e.request, clone));
return res;
}).catch(() =>
caches.match(e.request)
.then(r => r || caches.match('index.html'))
.then(r => r || OFFLINE_RESPONSE)
)
);
} else if (isSwScript) {
e.respondWith(fetch(e.request).catch(() => OFFLINE_RESPONSE));
} else {
e.respondWith(
caches.match(e.request).then(r => r || fetch(e.request).then(res => {
const clone = res.clone();
caches.open(CACHE).then(c => c.put(e.request, clone));
return res;
}))
);
}
});