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 + "¬es=" + 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=([^&]+)¬es=(.+)$/; 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.