diff --git a/index.html b/index.html index 355f2a809..a8042c894 100644 --- a/index.html +++ b/index.html @@ -4,13 +4,13 @@ Hextris - + - + @@ -18,10 +18,10 @@ - + - + @@ -31,8 +31,9 @@ + - + diff --git a/js/assets.json b/js/assets.json new file mode 100644 index 000000000..4eae4f85b --- /dev/null +++ b/js/assets.json @@ -0,0 +1,31 @@ +{ +"cache": + [ + "index.html", + "vendor/hammer.min.js", + "vendor/js.cookie.js", + "vendor/jsonfn.min.js", + "vendor/keypress.min.js", + "vendor/jquery.js", + "js/save-state.js", + "js/view.js", + "js/wavegen.js", + "js/math.js", + "js/Block.js", + "js/Hex.js", + "js/Text.js", + "js/comboTimer.js", + "js/checking.js", + "js/update.js", + "js/render.js", + "js/input.js", + "js/main.js", + "js/initialization.js", + "https://fonts.googleapis.com/css?family=Exo+2", + "style/fa/css/font-awesome.min.css", + "style/style.css", + "style/rrssb.css", + "vendor/rrssb.min.js", + "vendor/sweet-alert.min.js" + ] +} \ No newline at end of file diff --git a/js/main.js b/js/main.js index 90101759b..9336755fa 100644 --- a/js/main.js +++ b/js/main.js @@ -374,3 +374,68 @@ function showHelp() { $("#openSideBar").fadeIn(150,"linear"); $('#helpScreen').fadeToggle(150, "linear"); } + +// ask browser if it supports service workers, if it does, register it. +if ('serviceWorker' in navigator) { + window.addEventListener('load', function() { + navigator.serviceWorker.register('./sw.js').then(function(reg) { + console.log('SW registered successfully'); + + if(!navigator.serviceWorker.controller) { + return; + } + + if(reg.waiting) { + notifySWUpdates(reg.waiting); + } + + if(reg.installing) { + trackSWStates(reg.installing); + } + + reg.addEventListener('updatefound', function() { + trackSWStates(reg.installing); + }) + + var reloading; + navigator.serviceWorker.addEventListener('controllerchange', function() { + if(reloading) return; + window.location.reload(); + reloading = true; + }); + + }, function(err) { + console.log('SW registration failed'); + }); + + }); +} + +// notify user of game update available, +// when user clicks button service worker updates with new cache and page reloads. +function notifySWUpdates(reg) { + console.log('There is a new Service Worker available'); + let SW_Button = document.createElement('button'); + SW_Button.innerHTML = 'Update Available'; + let doc_body = document.getElementsByTagName('body')[0]; + doc_body.appendChild(SW_Button); + SW_Button.style.backgroundColor = 'blue'; + SW_Button.style.color = '#fff'; + SW_Button.style.position = 'fixed'; + SW_Button.style.bottom = '0px'; + SW_Button.style.right = '0px'; + SW_Button.style.padding = '5px 10px'; + SW_Button.addEventListener('click', function() { + console.log(reg); + reg.postMessage({activate: 'true'}); + }); +} + +// tracks service worker state and activates notification function when installed. +function trackSWStates(reg) { + reg.addEventListener('statechange', function() { + if(this.state == 'installed') { + notifySWUpdates(reg); + } + }); +} \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 000000000..1b14630b6 --- /dev/null +++ b/manifest.json @@ -0,0 +1,11 @@ +{ + "background_color": "#ecf0f1", + "display": "standalone", + "icons": [], + "name": "Hextris", + "short_name": "Hextris", + "description": "Fast paced HTML5 puzzle game inspired by Tetris!", + "start_url": "/", + "scope": "/", + "theme_color": "#ecf0f1" +} \ No newline at end of file diff --git a/sw.js b/sw.js new file mode 100644 index 000000000..686f09ef0 --- /dev/null +++ b/sw.js @@ -0,0 +1,77 @@ +var CACHE_NAME = 'hextris-v3'; + +// install service worker on first install and load cache assets. +self.addEventListener('install', function(event) { + event.waitUntil( + caches.open(CACHE_NAME).then(function(cache) { + fetch('js/assets.json').then(function(response) { + return response.json(); + }).catch(function(err) { + console.log('json fetch err:', err); + }).then(function(assetManifest) { + let cacheFiles = assetManifest.cache; + cache.addAll(cacheFiles); + }).catch(function(err) { + console.log('problem adding to cache:', err); + }) + }) + ); +}); + +// respond to fetch requests by browser using service worker. +self.addEventListener('fetch', function(event) { + const requestUrl = new URL(event.request.url); + + if (requestUrl.origin === location.origin) { + event.respondWith(getNetworkResponse(event.request)); + return; + } + + event.respondWith(fetch(event.request)); +}); + +// If asset exists in cache, respond with cache, +// otherwise respond from network after putting asset in cache. +function getNetworkResponse(request) { + return caches.open(CACHE_NAME).then(cache => { + return cache.match(request).then(response => { + if (response) return response; + + if(request.cache === 'only-if-cached') { + return fetch(request, {mode: "same-origin"}).then(networkResponse => { + cache.put(request, networkResponse.clone()); + return networkResponse; + }) + } else { + return fetch(request).then(networkResponse => { + cache.put(request, networkResponse.clone()); + return networkResponse; + }) + } + }); + }); +}; + +// Delete any unused old caches when a new service worker is activated +self.addEventListener('activate', function(event) { + event.waitUntil( + Promise.all([ + clients.claim(), + caches.keys().then(function(cacheNames) { + cacheNames.filter(function(cacheName) { + if(cacheName.startsWith('hextris') && cacheName !== CACHE_NAME) { + caches.delete(cacheName); + } + }) + }) + ] + ) + ) +}); + +// listen to messages and skip waiting state of service worker +// this basically activates service worker when notification recieved. +self.addEventListener('message', function(event) { + if(event.data.activate == 'true'); + self.skipWaiting(); +}); \ No newline at end of file