1self.addEventListener("install", (event) => { 2 // Force the waiting service worker to become the active service worker. 3 self.skipWaiting(); 4}); 5 6const showLocalNotification = (payload, swRegistration) => { 7 const defTitle = 'Default title'; 8 const defOptions = { 9 body: "", 10 icon: "https://cdn.cases.media/image/original/apple-touch-icon-512x512-26.png", 11 badge: "https://cdn.cases.media/image/original/android-chrome-badge-97x97-maskable.png" 12 } 13 14 let options = Object.assign({}, defOptions, payload.options); 15 let title = payload.title || defTitle; 16 17 // Close same notification 18 if (options && options.data && options.tag && options.data.total) { 19 return swRegistration.getNotifications() 20 .then((notifications) => { 21 let maxTotal = 0; 22 23 for (let notification of notifications) { 24 if (!notification.data || !notification.tag || !notification.data.total) continue; 25 if (notification.tag !== options.tag) continue; 26 27 maxTotal = maxTotal > notification.data.total ? maxTotal : notification.data.total; 28 29 if (notification.data.total < options.data.total) { 30 notification.close(); 31 } 32 } 33 34 // Show notification only if total is greater then previous one 35 if (maxTotal < options.data.total) { 36 return swRegistration.showNotification(title, options) 37 } 38 }); 39 } 40 41 return swRegistration.showNotification(title, options) 42} 43 44const determineBadgeCount = (payload) => { 45 if (!payload || !payload.options || !payload.options.data) return undefined; 46 return payload.options.data.badgeCount; 47} 48 49self.addEventListener('push', function (event) { 50 if (event.data) { 51 try { 52 let promises = []; 53 let data = event.data.json(); 54 55 if (self.navigator && 'setAppBadge' in self.navigator) { 56 const badgeCount = determineBadgeCount(data); 57 58 if (typeof badgeCount !== 'undefined') { 59 // Promise to set the badge 60 promises.push(self.navigator.setAppBadge(badgeCount)); 61 } 62 } 63 64 // Promise to show a notification 65 promises.push(showLocalNotification(data, self.registration)); 66 67 event.waitUntil(Promise.all(promises)); 68 } catch (e) { 69 console.log(e) 70 } 71 } 72}) 73 74self.addEventListener('notificationclick', function (event) { 75 if (!event.notification.data || !event.notification.data.url) return true; 76 77 const urlToOpen = new URL(event.notification.data.url, self.location.origin).href; 78 79 const promiseChain = clients.matchAll({ 80 type: 'window', 81 includeUncontrolled: true 82 }) 83 .then(async (windowClients) => { 84 // If the PWA is already running (including backgrounded iOS mode), 85 // try to bring the existing window forward and navigate it. 86 const clientToFocus = windowClients.find((client) => client.visibilityState === 'visible') || windowClients[0]; 87 88 if (clientToFocus) { 89 try { 90 const isSamePage = clientToFocus.url === urlToOpen; 91 if (isSamePage) { 92 await clientToFocus.focus(); 93 return; 94 } 95 96 const navigatedClient = await clientToFocus.navigate(urlToOpen); 97 await (navigatedClient || clientToFocus).focus(); 98 return; 99 } catch (error) { 100 // Navigate/focus can fail on some platforms for backgrounded clients. 101 // Fall through to openWindow as a reliable fallback. 102 } 103 } 104 105 await clients.openWindow(urlToOpen); 106 }); 107 108 event.waitUntil(promiseChain); 109 event.notification.close(); 110})
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.