PageSourceSearch

https://scoutstracker.ca/test/common/client.js?ver=%25VER%25

js scoutstracker.ca collected 2026-09-25 23:54:49 UTC 8,569 bytes, 268 lines download raw bytes

1/**
2 * This file sets up the functions that dynamically load "service-worker.js", which does all the application caching
3 */
4
5/* global CACHE_VERSION, updateCodeVersion */		// eslint-disable-line no-unused-vars
6
7/**
8 * Implementation must be identical to that used in service-worker.js
9 */
10function getCacheContext()
11{
12    return (location.href.match( /\/test\// ) ? "/test" : "") + "/" + location.href.match( /([\w-]+)[/][^/]*$/ )[1];
13}
14
15/* exported unregisterServiceWorker */
16function unregisterServiceWorker()
17{
18    if ( navigator.serviceWorker === undefined )
19    {
20	console.log( "[client] No serviceWorker" );
21        return;			// nothing to do
22    }
23
24    navigator.serviceWorker.getRegistrations().then( function( registrations ) {
25	for ( const registration of registrations )
26	{
27	    console.log( "[client] ServiceWorker " + registration.scope + " unregistered" );
28
29	    registration.unregister().then( function() {
30		if ( self.clients !== undefined )
31		    return self.clients.matchAll();
32		else
33		{
34		    console.log( "[client] No clients" );
35		    return Promise.reject( new Error( "[client] No clients" ) );
36		}
37	    }).then( function( clients ) {
38		clients.forEach( (client) => {
39		    if ( client.url && "navigate" in client )
40		    {
41			console.log( "[client] Navigating to " + client.url );
42			client.navigate( client.url );
43		    }
44		});
45	    });
46	}
47    });
48}
49
50function _reloadAfterCacheActivation( version, notes )
51{
52    // Now we want to give a) reload the window so we pick up the latest resources and b) give the client a chance
53    // to display a notification. However, Firefox and Edge dismiss any popups after a reload, so we have to use a
54    // URI paramater to indicate that we're reloading as a result of patch, and then detect that URI parameter upon
55    // load and pop up a notification
56    try {
57	localStorage.setItem( "patch-version", version );
58	localStorage.setItem( "patch-releasenotes", notes );
59
60	window.setTimeout( function() { window.location.reload( true ); }, 500 );
61    }
62    catch ( e )
63    {
64	console.warn( "[client] Couldn't set localStorage" );
65	const urlNew = window.location.href.replace( /#.+/, "") + (window.location.href.match( /[?]/ ) ? "&" : "?") + "patched=" + version + "&notes=" + notes.replace( /#/, "#" );
66	window.setTimeout( function() { window.location.href = urlNew; }, 500 );
67    }
68
69}
70
71function handleMessage( event )
72{
73    //console.log( "[client][message] Received", JSON.stringify( event.data ) );
74
75    if ( event.data.topic == null )
76	console.error( "[client][message] No topic" );
77    else if ( event.data.topic == "setCacheVersion" )		// the service-worker sends this to everyone when it updates
78    {
79	try {
80	    setCacheDetails( event.data.version, event.data.releasenotes );	// make available to other files
81	} catch ( e ) {
82	    // this can happen after a reload
83	}
84	_reloadAfterCacheActivation( event.data.version, event.data.releasenotes );
85    }
86    else if ( event.data.topic == "getCacheVersion" )		// we asked for this information
87    {
88	try {
89	    setCacheDetails( event.data.version, event.data.releasenotes );	// make available to other files
90	} catch ( e ) {
91	    console.error( e );
92	}
93    }
94    else
95	console.error( `[client][message] Unrecognized topic ${event.data.topic}` );
96}
97
98function sendMessage( serviceWorker, message )
99{
100    return new Promise( ( resolve /*, reject */ ) => {
101	const messageChannel = new MessageChannel();
102
103	messageChannel.port1.onmessage = function( event ) {
104	    handleMessage( event );
105	    resolve( `Received a reply from the ServiceWorker: ${event.data}` );
106	};
107
108	serviceWorker.postMessage( message, [messageChannel.port2] );
109    });
110}
111
112function updateCacheUI()
113{
114    // Firefox and Edge run the registration code before the document is fully loaded,
115    // so it's possible that updateCodeVersion isn't yet defined.  Keep trying until we succeed.
116    try {
117	updateCodeVersion( true, getCacheDetails() );
118    } catch ( e ) {
119	window.setTimeout( updateCacheUI, 500 );
120    }
121}
122
123function setCacheDetails( version, releasenotes )
124{
125    CACHE_VERSION = version;
126
127//try {
128//self.clients.matchAll().forEach( (client) => { console.log( `[client] url: ${client.url}` ); } );	// eslint-disable-line no-unused-vars
129//} catch ( e ) {
130//console.error( "[client] couldn't access clients" );
131//}
132    if ( version )
133	localStorage.setItem( "cache-version", version );
134    else
135	localStorage.removeItem( "cache-version" );
136
137    if ( releasenotes )
138	localStorage.setItem( "cache-releasenotes", releasenotes );
139    else
140	localStorage.removeItem( "cache-releasenotes" );
141
142    if ( version )
143	updateCacheUI();
144}
145
146/* exported getCacheDetails */
147function getCacheDetails()
148{
149    return { version: localStorage.getItem( "cache-version" ), notes: localStorage.getItem( "cache-releasenotes" ) };
150}
151
152function displayNotification( strMessage, options )
153{
154    if ( Notification.permission == "granted" )
155    {
156	if ( options === undefined )
157	    options = {};
158	if ( options.icon === undefined && typeof NOTIFICATION_ICON != "undefined" )		// typically defined in <script> element of index.html
159	    options.icon = NOTIFICATION_ICON;		// eslint-disable-line no-undef
160	if ( options.badge === undefined && typeof NOTIFICATION_BADGE != "undefined" )		// typically defined in <script> element of index.html
161	    options.icon = NOTIFICATION_BADGE;		// eslint-disable-line no-undef
162	if ( options.vibrate === undefined )
163	    options.vibrate = [ 100, 50, 100 ];
164	if ( options.timestamp === undefined )
165	    options.timestamp = Date.now();
166
167	navigator.serviceWorker.getRegistration().then( function( reg ) {
168	    reg.showNotification( strMessage, options );
169	});
170    }
171}
172
173function showPatchNotification( version, notes )
174{
175    // try to notify the user
176    const options = {
177	body: "For more information about what's in this update, go to \"Help\" | \"Release Notes\".",
178	tag: "patched",
179	renotify: false
180    };
181
182    if ( notes && Notification.maxActions > 0 )
183    {
184	options.body =  "For more information about what's in this update, click \"Release Notes\" below.";
185	options.actions = [
186	    {
187		action: "release-notes-" + notes,
188		title: "Release Notes"
189	    }
190	];
191    }
192
193    if ( Notification.permission !== "granted" ) 	// prompt the user for permission
194    {
195	Notification.requestPermission( function( status ) {
196	    console.log( `[notification] Notification permission status: ${status}` );
197	});
198    }
199    else
200	displayNotification( "Software Updated" + (version ? ` to v${version}` : ""), options );
201}
202
203if ( navigator.serviceWorker !== undefined )
204{
205    navigator.serviceWorker.register( getCacheContext() + "/service-worker.js", { scope: getCacheContext() + "/" } )
206	.then( function( registration ) {
207	    console.info( "[client] The service worker has been registered for scope: ", registration );
208	    setCacheDetails( null, null );		// clear the details, and wait for a getCacheVersion message to update
209
210	    if ( registration.active )
211		sendMessage( registration.active, { topic: "getCacheVersion" } );
212	});
213
214    navigator.serviceWorker.addEventListener( "controllerchange", function( /* event */ ) {
215	console.log( "[client][controllerchange] A 'controllerchange' event has happened within navigator.serviceWorker" );
216
217	navigator.serviceWorker.controller.addEventListener( "statechange", function() {
218	    //console.log( `[controllerchange][statechange] A 'statechange' has occurred: ${this.state}` );
219
220	    if ( this.state === "activated" )
221		; // do something or report this fact?
222	});
223    });
224
225    navigator.serviceWorker.addEventListener( "message", (event) => {
226	handleMessage( event );
227    });
228}
229
230let isParsed = false;
231try
232{
233    if ( localStorage.getItem( "patch-version" ) )
234    {
235	const version = localStorage.getItem( "patch-version" );
236	const notes = localStorage.getItem( "patch-releasenotes" );
237	localStorage.removeItem( "patch-version" );		// scrub
238	localStorage.removeItem( "patch-releasenotes" );		// scrub
239
240	//console.log( "[client] Found patch properties" );
241
242	showPatchNotification( version, notes );
243	isParsed = true;
244    }
245}
246catch ( e )
247{
248    //console.warn( "[client] Couldn't get localStorage", e );
249}
250
251if ( ! isParsed )
252{
253    const REGEX_PATCH = /[?&]patched=([^&]+)&notes=(.+)$/;
254    if ( location.href.match( REGEX_PATCH ) )
255    {
256	const version = RegExp.$1;
257	const notes = RegExp.$2;
258
259	//console.log( "[client] Found patch parameters" );
260
261	const urlClean = location.href.replace( REGEX_PATCH, "" );
262	if ( location.href != urlClean )
263	{
264	    window.history.pushState( null, null, urlClean );
265	    showPatchNotification( version, notes );
266	}
267    }
268}

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.