PageSourceSearch

https://senohrad.sk/sw.js

js senohrad.sk collected 2026-09-25 07:56:05 UTC 7,620 bytes, 230 lines download raw bytes

1/**
2 * Service Worker pre Multiobec PWA
3 *
4 * Stratégie:
5 * - IDSK assety (CSS/JS/fonty): Cache First — dlhodobo stabilné
6 * - Tenant ikony a obrázky: Cache First s network fallback
7 * - HTML stránky: Network First s cache fallback (offline podpora)
8 * - API/dynamické: Network Only
9 *
10 * Cache sa automaticky čistí pri zmene verzie (CACHE_VERSION).
11 * Verzia sa bumpne pri deploji alebo pri tenant refresh.
12 */
13
14var CACHE_VERSION = 'v2';
15var STATIC_CACHE = 'multiobec-static-' + CACHE_VERSION;
16var PAGES_CACHE = 'multiobec-pages-' + CACHE_VERSION;
17var IMAGES_CACHE = 'multiobec-images-' + CACHE_VERSION;
18
19// Statické assety — precachujú sa pri inštalácii
20var PRECACHE_URLS = [
21    '/',
22    '/offline',
23    '/assets/idsk/idsk-frontend.css',
24    '/assets/idsk/idsk-frontend.js',
25    '/assets/idsk/fonts/SourceSansPro-Regular.woff',
26    '/assets/idsk/fonts/SourceSansPro-Bold.woff',
27    '/assets/idsk/fonts/SourceSansPro-Semibold.woff'
28];
29
30// ── INSTALL ──────────────────────────────────────────────────
31self.addEventListener('install', function(event) {
32    event.waitUntil(
33        caches.open(STATIC_CACHE).then(function(cache) {
34            return cache.addAll(PRECACHE_URLS);
35        }).then(function() {
36            // Okamžite aktivuj — nečakaj na zatvorenie starých tabov
37            return self.skipWaiting();
38        })
39    );
40});
41
42// ── ACTIVATE ─────────────────────────────────────────────────
43self.addEventListener('activate', function(event) {
44    // Vymaž staré cache (iná verzia)
45    event.waitUntil(
46        caches.keys().then(function(cacheNames) {
47            return Promise.all(
48                cacheNames.filter(function(name) {
49                    return name.startsWith('multiobec-') &&
50                        name !== STATIC_CACHE &&
51                        name !== PAGES_CACHE &&
52                        name !== IMAGES_CACHE;
53                }).map(function(name) {
54                    return caches.delete(name);
55                })
56            );
57        }).then(function() {
58            // Prevezmeme kontrolu nad všetkými otvorenými tabmi
59            return self.clients.claim();
60        })
61    );
62});
63
64// ── FETCH ────────────────────────────────────────────────────
65self.addEventListener('fetch', function(event) {
66    var request = event.request;
67
68    // Len GET requesty
69    if (request.method !== 'GET') {
70        return;
71    }
72
73    var url = new URL(request.url);
74
75    // Ignoruj externé URL (fonty z CDN atď. — nemali by byť, ale pre istotu)
76    if (url.origin !== location.origin) {
77        return;
78    }
79
80    // ── Stratégia podľa typu requestu ──
81
82    // 1. Statické assety — Cache First
83    if (isStaticAsset(url.pathname)) {
84        event.respondWith(cacheFirst(request, STATIC_CACHE));
85        return;
86    }
87
88    // 2. Obrázky — Cache First
89    if (isImage(url.pathname)) {
90        event.respondWith(cacheFirst(request, IMAGES_CACHE));
91        return;
92    }
93
94    // 3. Manifest — vždy network, necachujeme cez SW (PHP+Redis+ETag stačí)
95    if (url.pathname === '/manifest' || url.pathname === '/manifest.json') {
96        return; // necháme browser fetchnúť normálne
97    }
98
99    // 4. HTML stránky — Network First s offline fallback
100    if (request.headers.get('Accept') && request.headers.get('Accept').indexOf('text/html') !== -1) {
101        event.respondWith(networkFirstWithOffline(request));
102        return;
103    }
104});
105
106// ── Cache stratégie ──────────────────────────────────────────
107
108/**
109 * Cache First — najprv cache, ak nie je → network → uloží do cache
110 */
111function cacheFirst(request, cacheName) {
112    return caches.match(request).then(function(cached) {
113        if (cached) {
114            return cached;
115        }
116        return fetch(request).then(function(response) {
117            if (response.ok) {
118                var clone = response.clone();
119                caches.open(cacheName).then(function(cache) {
120                    cache.put(request, clone);
121                });
122            }
123            return response;
124        });
125    });
126}
127
128/**
129 * Network First — najprv sieť, ak zlyhá → cache
130 */
131function networkFirst(request, cacheName) {
132    return fetch(request).then(function(response) {
133        if (response.ok) {
134            var clone = response.clone();
135            caches.open(cacheName).then(function(cache) {
136                cache.put(request, clone);
137            });
138        }
139        return response;
140    }).catch(function() {
141        return caches.match(request);
142    });
143}
144
145/**
146 * Network First s offline fallback — pre HTML stránky
147 * Ak sieť zlyhá a stránka nie je v cache → zobrazí /offline
148 */
149function networkFirstWithOffline(request) {
150    return fetch(request).then(function(response) {
151        if (response.ok) {
152            var clone = response.clone();
153            caches.open(PAGES_CACHE).then(function(cache) {
154                cache.put(request, clone);
155            });
156        }
157        return response;
158    }).catch(function() {
159        return caches.match(request).then(function(cached) {
160            if (cached) {
161                return cached;
162            }
163            // Offline fallback stránka
164            return caches.match('/offline');
165        });
166    });
167}
168
169// ── Helpers ──────────────────────────────────────────────────
170
171function isStaticAsset(pathname) {
172    return /\.(css|js|woff|woff2|ttf|eot)$/.test(pathname) ||
173        pathname.startsWith('/assets/');
174}
175
176function isImage(pathname) {
177    return /\.(png|jpg|jpeg|gif|webp|svg|ico)$/.test(pathname) ||
178        pathname.startsWith('/icons/') ||
179        pathname.startsWith('/uploads/');
180}
181
182// ── Push notifikácie (Phase 2 — pripravené pre budúce použitie) ──
183
184self.addEventListener('push', function(event) {
185    if (!event.data) return;
186
187    var data = {};
188    try {
189        data = event.data.json();
190    } catch (e) {
191        data = { title: 'Nová správa', body: event.data.text() };
192    }
193
194    var options = {
195        body: data.body || '',
196        icon: data.icon || '/icons/icon-192x192.png',
197        badge: data.badge || '/icons/icon-72x72.png',
198        tag: data.tag || 'multiobec-notification',
199        data: {
200            url: data.url || '/'
201        }
202    };
203
204    event.waitUntil(
205        self.registration.showNotification(data.title || 'Oznámenie', options)
206    );
207});
208
209self.addEventListener('notificationclick', function(event) {
210    event.notification.close();
211
212    var url = event.notification.data && event.notification.data.url
213        ? event.notification.data.url
214        : '/';
215
216    event.waitUntil(
217        self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function(clients) {
218            // Ak je už otvorený tab s touto stránkou, focusni ho
219            for (var i = 0; i < clients.length; i++) {
220                if (clients[i].url === url && 'focus' in clients[i]) {
221                    return clients[i].focus();
222                }
223            }
224            // Inak otvor nový tab
225            if (self.clients.openWindow) {
226                return self.clients.openWindow(url);
227            }
228        })
229    );
230});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.