From 5cdffcbd1b49bb1327b3f55f166f09159e86870b Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:22:51 +0330 Subject: [PATCH] Import source: app/public/service-worker Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- app/public/service-worker.js | 92 ++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 app/public/service-worker.js diff --git a/app/public/service-worker.js b/app/public/service-worker.js new file mode 100644 index 0000000..81389d5 --- /dev/null +++ b/app/public/service-worker.js @@ -0,0 +1,92 @@ +const CACHE_NAME = 'teknav-v5'; +const ASSETS_TO_CACHE = [ + '/', + '/index.html', + '/manifest.json', + '/favicon.png' +]; + +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME) + .then((cache) => cache.addAll(ASSETS_TO_CACHE)) + .then(() => self.skipWaiting()) + ); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys() + .then((keys) => Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)))) + .then(() => self.clients.claim()) + ); +}); + +self.addEventListener('fetch', (event) => { + const { request } = event; + if (request.method !== 'GET') return; + const url = new URL(request.url); + + if (url.origin === location.origin && (url.pathname.startsWith('/article/') || url.pathname === '/' || url.pathname === '/articles')) { + event.respondWith( + fetch(request) + .then((response) => { + const copy = response.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(request, copy)); + return response; + }) + .catch(() => caches.match(request).then((cached) => cached || caches.match('/index.html'))) + ); + return; + } + + if (url.origin === location.origin && url.pathname.startsWith('/api/articles')) { + event.respondWith(fetch(request)); + return; + } + + if (request.headers.get('Accept')?.includes('text/html')) { + event.respondWith( + fetch(request) + .then((response) => { + const copy = response.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(request, copy)); + return response; + }) + .catch(() => caches.match(request).then((cached) => cached || caches.match('/index.html'))) + ); + return; + } + + event.respondWith(caches.match(request).then((response) => response || fetch(request))); +}); + +self.addEventListener('push', (event) => { + const data = event.data ? event.data.json() : { title: 'تکناو', body: '', url: '/', icon: '/icons/icon-192x192.png' }; + event.waitUntil( + self.registration.showNotification(data.title, { + body: data.body, + icon: data.icon || '/icons/icon-192x192.png', + badge: '/icons/badge-72x72.png', + dir: 'rtl', + lang: 'fa', + data: { url: data.url || '/' }, + }) + ); +}); + +self.addEventListener('notificationclick', (event) => { + event.notification.close(); + const targetUrl = (event.notification.data && event.notification.data.url) || '/'; + event.waitUntil( + clients.matchAll({ type: 'window', includeUncontrolled: true }).then((list) => { + for (const client of list) { + if ('focus' in client) { + client.navigate(targetUrl); + return client.focus(); + } + } + return clients.openWindow(targetUrl); + }) + ); +});