diff --git a/js/pacosako_ui.js b/js/pacosako_ui.js index d9bf8f1..4730948 100644 --- a/js/pacosako_ui.js +++ b/js/pacosako_ui.js @@ -18,6 +18,8 @@ import escape from 'lodash/escape'; import jBox from 'jbox'; import 'jbox/dist/jBox.all.css'; +import {Workbox, messageSW} from 'workbox-window'; + /* "Waterdrop" by Porphyr (freesound.org/people/Porphyr) / CC BY 3.0 (creativecommons.org/licenses/by/3.0) */ import Waterdrop from '../wav/191678__porphyr__waterdrop.wav'; @@ -803,14 +805,68 @@ $(function (){ } } - try { - navigator.serviceWorker.register('sw.js').catch(disableNotify); + if ('serviceWorker' in navigator) { + let confirmBox = null; - if (Notification.permission === 'denied') { + Promise.resolve().then(async () => { + const wb = new Workbox('sw.js'); + + function showSkipWaitingPrompt(event) { + if (confirmBox) { + confirmBox.close({ ignoreDelay: true }); + } + + confirmBox = new jBox('Confirm', { + attach: null, + content: "A new version is available. Update the page?", + confirmButton: `Update`, + cancelButton: 'Not now', + closeOnConfirm: false, + confirm() { + /* The SW should signal us to reload, but do it after 20s regardless. */ + setTimeout(() => { window.location.reload(); }, 20000); + messageSW(event.sw, {type: 'SKIP_WAITING'}); + $('.update-confirm-button').text('Updating…'); + }, + onCloseComplete() { + this.destroy(); + }, + }); + + confirmBox.open(); + } + + wb.addEventListener('installed', (event) => { + try { + if (Notification.permission === 'denied') { + disableNotify(); + } + } catch (err) { + disableNotify(); + } + }); + + wb.addEventListener('controlling', (event) => { + if (event.isUpdate) { + window.location.reload(); + } + }); + + wb.addEventListener('waiting', showSkipWaitingPrompt); + wb.addEventListener('externalwaiting', showSkipWaitingPrompt); + + const registration = await wb.register(); + + if ('update' in registration) { + /* Check for updates every 4h without reloading the page. */ + setInterval(() => { registration.update(); }, 4*3600*1000); + } else { + console.log('service worker update method not supported, disabling update checks'); + } + }).catch((err) => { + console.error('failed to register the service worker', err); disableNotify(); - } - } catch (err) { - disableNotify(); + }); } const LS_KEY_NOTIFY = 'pacosako/notify'; @@ -1166,9 +1222,6 @@ $(function (){ } }; - /* force page reload after four hours to keep client code up to date */ - window.setTimeout(function(){ location.reload(); }, 4*3600*1000); - const foundId = location.hash.match(/^#\/([0-9a-f]{16}\b)/); if (foundId) { switchGameId(foundId[1]); diff --git a/package-lock.json b/package-lock.json index a7274bd..be98029 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "paco_sako", - "version": "0.2.0", + "version": "0.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0ed8768..300f57c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "paco_sako", - "version": "0.3.0", + "version": "0.4.0", "description": "Online version of the Paco Ŝako chess variation", "browser": "index.js", "scripts": { @@ -33,7 +33,8 @@ "workbox-precaching": "^5.1.3", "workbox-routing": "^5.1.3", "workbox-strategies": "^5.1.3", - "workbox-webpack-plugin": "^5.1.3" + "workbox-webpack-plugin": "^5.1.3", + "workbox-window": "^5.1.3" }, "dependencies": {} } diff --git a/sw.js b/sw.js index f42288d..9303307 100644 --- a/sw.js +++ b/sw.js @@ -8,3 +8,9 @@ registerRoute( new RegExp('^https://fonts\\.googleapis\\.com/|https://fonts\\.gstatic\\.com/'), new StaleWhileRevalidate() ); + +addEventListener('message', (event) => { + if (event.data && event.data.type === 'SKIP_WAITING') { + skipWaiting(); + } +});