PageSourceSearch

https://www.betting-forum.com/service_worker.js

js betting-forum.com collected 2026-09-24 09:11:32 UTC 6,000 bytes, 307 lines download raw bytes

1'use strict'
2
3// ################################## CONSTANTS #################################
4
5const CACHE_NAME = 'xf-offline'
6const CACHE_ROUTE = 'index.php?sw/cache.json'
7const OFFLINE_ROUTE = 'index.php?sw/offline'
8
9const supportPreloading = false
10
11// ############################### EVENT LISTENERS ##############################
12
13self.addEventListener('install', event =>
14{
15	self.skipWaiting()
16
17	event.waitUntil(createCache())
18})
19
20self.addEventListener('activate', event =>
21{
22	self.clients.claim()
23
24	event.waitUntil(
25		new Promise(resolve =>
26		{
27			if (self.registration.navigationPreload)
28			{
29				self.registration.navigationPreload[supportPreloading ? 'enable' : 'disable']()
30			}
31
32			resolve()
33		}),
34	)
35})
36
37self.addEventListener('message', event =>
38{
39	const clientId = event.source.id
40	const message = event.data
41	if (typeof message !== 'object' || message === null)
42	{
43		console.error('Invalid message:', message)
44		return
45	}
46
47	recieveMessage(clientId, message.type, message.payload)
48})
49
50self.addEventListener('fetch', event =>
51{
52	const request = event.request
53	const accept = request.headers.get('accept')
54
55	if (
56		request.mode !== 'navigate' ||
57		request.method !== 'GET' ||
58		(accept && !accept.includes('text/html'))
59	)
60	{
61		return
62	}
63
64	// bypasses for: HTTP basic auth issues, file download issues (iOS), common ad blocker issues
65	if (request.url.match(/\/admin\.php|\/install\/|\/download($|&|\?)|[/?]attachments\/|google-ad|adsense/))
66	{
67		if (supportPreloading && event.preloadResponse)
68		{
69			event.respondWith(event.preloadResponse)
70		}
71
72		return
73	}
74
75	const response = Promise.resolve(event.preloadResponse)
76		.then(r => r || fetch(request))
77
78	event.respondWith(
79		response
80			.catch(error => caches.open(getCacheName())
81				.then(cache => cache.match(OFFLINE_ROUTE))),
82	)
83})
84
85self.addEventListener('push', event =>
86{
87	if (!(self.Notification && self.Notification.permission === 'granted'))
88	{
89		return
90	}
91
92	let data
93
94	try
95	{
96		data = event.data.json()
97	}
98	catch (e)
99	{
100		console.warn('Received push notification but payload not in the expected format.', e)
101		console.warn('Received data:', event.data.text())
102		return
103	}
104
105	if (!data || !data.title || !data.body)
106	{
107		console.warn('Received push notification but no payload data or required fields missing.', data)
108		return
109	}
110
111	const options = {
112		body: data.body,
113		dir: data.dir || 'ltr',
114		data: data,
115	}
116	if (data.badge)
117	{
118		options.badge = data.badge
119	}
120	if (data.icon)
121	{
122		options.icon = data.icon
123	}
124
125	const notificationPromise = self.registration.showNotification(data.title, options)
126
127	if ('setAppBadge' in self.navigator && 'clearAppBadge' in self.navigator)
128	{
129		let newCount = parseInt(String(data.total_unread).replace(/[,. ]/g, ''))
130
131		if (newCount)
132		{
133			self.navigator.setAppBadge(newCount)
134		}
135		else
136		{
137			self.navigator.clearAppBadge()
138		}
139	}
140
141	event.waitUntil(notificationPromise)
142})
143
144self.addEventListener('notificationclick', event =>
145{
146	const notification = event.notification
147	notification.close()
148
149	const url = notification.data.url
150	if (!url)
151	{
152		return
153	}
154
155	const urlToOpen = new URL(url, self.location.origin).href
156
157	const promiseChain = clients
158		.matchAll({
159			type: 'window',
160			includeUncontrolled: true,
161		})
162		.then(windowClients =>
163		{
164			let matchingClient = null
165
166			for (const windowClient of windowClients)
167			{
168				if (windowClient.url === urlToOpen && 'navigate' in windowClient)
169				{
170					matchingClient = windowClient
171					break
172				}
173			}
174
175			if (matchingClient)
176			{
177				return matchingClient.navigate(urlToOpen).then(client =>
178				{
179					if (client)
180					{
181						client.focus()
182					}
183					else
184					{
185						return clients.openWindow(urlToOpen)
186					}
187				})
188			}
189			else
190			{
191				return clients.openWindow(urlToOpen)
192			}
193		})
194
195	event.waitUntil(promiseChain)
196})
197
198// ################################## MESSAGING #################################
199
200function sendMessage (clientId, type, payload)
201{
202	if (typeof type !== 'string' || type === '')
203	{
204		console.error('Invalid message type:', type)
205		return
206	}
207
208	if (typeof payload === 'undefined')
209	{
210		payload = {}
211	}
212	else if (typeof payload !== 'object' || payload === null)
213	{
214		console.error('Invalid message payload:', payload)
215		return
216	}
217
218	clients.get(clientId)
219		.then(client =>
220		{
221			client.postMessage({
222				type: type,
223				payload: payload,
224			})
225		})
226		.catch(error =>
227		{
228			console.error('An error occurred while sending a message:', error)
229		})
230}
231
232const messageHandlers = {}
233
234function recieveMessage (clientId, type, payload)
235{
236	if (typeof type !== 'string' || type === '')
237	{
238		console.error('Invalid message type:', type)
239		return
240	}
241
242	if (typeof payload !== 'object' || payload === null)
243	{
244		console.error('Invalid message payload:', payload)
245		return
246	}
247
248	const handler = messageHandlers[type]
249	if (typeof handler === 'undefined')
250	{
251		console.error('No handler available for message type:', type)
252		return
253	}
254
255	handler(clientId, payload)
256}
257
258// ################################### CACHING ##################################
259
260function getCacheName ()
261{
262	const match = self.location.pathname.match(/^\/(.*)\/[^/]+$/)
263	let cacheModifier
264	if (match && match[1].length)
265	{
266		cacheModifier = match[1].replace(/[^a-zA-Z0-9_-]/g, '')
267	}
268	else
269	{
270		cacheModifier = ''
271	}
272
273	return CACHE_NAME + (cacheModifier.length ? '-' : '') + cacheModifier
274}
275
276function createCache ()
277{
278	const cacheName = getCacheName()
279
280	return caches.delete(cacheName)
281		.then(() => caches.open(cacheName))
282		.then(cache => fetch(CACHE_ROUTE)
283			.then(response => response.json())
284			.then(response =>
285			{
286				const key = response.key || null
287				const files = response.files || []
288				files.push(OFFLINE_ROUTE)
289
290				return cache.addAll(files)
291					.then(() => key)
292			}))
293		.catch(error =>
294		{
295			console.error('There was an error setting up the cache:', error)
296		})
297}
298
299function updateCacheKey (clientId, key)
300{
301	sendMessage(clientId, 'updateCacheKey', { 'key': key })
302}
303
304messageHandlers.updateCache = (clientId, payload) =>
305{
306	createCache()
307}

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.