aboutsummaryrefslogtreecommitdiffstats
path: root/templates
diff options
context:
space:
mode:
authorMatthew Somerville <matthew@mysociety.org>2019-12-19 09:23:21 +0000
committerMatthew Somerville <matthew@mysociety.org>2020-02-14 10:38:49 +0000
commit0e80a90bebc12fe381892386f9ffd751edb38d7c (patch)
tree50f5ac13f745f6142c9b6cab726dacda2fb447fe /templates
parent43290e5f733b4e88c6b4e5467b7e446a416a4682 (diff)
Initial service worker.
This basic service worker behaves identically to the existing appcache - some static scripts and CSS are cached, any HTML offline instead returns a static HTML page that knows how to show data on stored problems out of localStorage (stored there when /my/planned was visited online). Inspect form submissions will be captured and can be synced back when online. Once feature parity is established, we will then remove appcache, switch from using localStorage to the cache API, and hopefully move all offline support into the service worker.
Diffstat (limited to 'templates')
-rw-r--r--templates/web/base/common_header_tags.html8
-rw-r--r--templates/web/base/offline/fallback.html12
-rw-r--r--templates/web/base/offline/service_worker.html62
3 files changed, 82 insertions, 0 deletions
diff --git a/templates/web/base/common_header_tags.html b/templates/web/base/common_header_tags.html
index d54d97297..279f561df 100644
--- a/templates/web/base/common_header_tags.html
+++ b/templates/web/base/common_header_tags.html
@@ -16,6 +16,14 @@
(function(a){a=a.documentElement;a.className=a.className.replace(/\bno-js\b/,"js");var b=-1<a.className.indexOf("ie8");b=Modernizr.mq("(min-width: 48em)")||b?"desktop":"mobile";"IntersectionObserver"in window&&(a.className+=" lazyload");"mobile"==b&&(a.className+=' mobile[% " map-fullscreen only-map map-reporting" IF page == "around" %]')})(document);
</script>
+<script nonce="[% csp_nonce %]">
+if ('serviceWorker' in navigator) {
+ window.addEventListener('load', function() {
+ navigator.serviceWorker.register('/service-worker.js');
+ });
+}
+</script>
+
[% IF robots %]
<meta name="robots" content="[% robots %]">
[% ELSIF c.config.STAGING_SITE %]
diff --git a/templates/web/base/offline/fallback.html b/templates/web/base/offline/fallback.html
new file mode 100644
index 000000000..b8e1ee9b9
--- /dev/null
+++ b/templates/web/base/offline/fallback.html
@@ -0,0 +1,12 @@
+[% SET bodyclass = "fullwidthpage offlinepage" ~%]
+[% INCLUDE 'header.html' %]
+
+<h1>[% loc('Offline') %]</h1>
+
+<p>[% loc('Sorry, we don’t have a good enough connection to fetch that page.') %]</p>
+
+<ul class="item-list item-list--reports" id="offline_list"></ul>
+
+<div id="offline_clear"></div>
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/base/offline/service_worker.html b/templates/web/base/offline/service_worker.html
new file mode 100644
index 000000000..1005e959b
--- /dev/null
+++ b/templates/web/base/offline/service_worker.html
@@ -0,0 +1,62 @@
+[%
+SET bodyclass = "offlinepage"; # For selection of scripts
+PROCESS 'common_scripts.html';
+SET offline_html = version('../templates/web/base/offline/fallback.html', '/offline/fallback');
+SET scripts_seen = {};
+
+~%]
+
+const requiredOffline = [
+ "[% version('/cobrands/' _ c.cobrand.asset_moniker _ '/base.css') %]",
+ "[% version('/cobrands/' _ c.cobrand.asset_moniker _ '/layout.css') %]",
+ "[% version('/vendor/OpenLayers/theme/default/style.css') %]",
+ "[% version('/vendor/fancybox/jquery.fancybox-1.3.4.css') %]",
+ [%
+ FOR script IN scripts;
+ NEXT IF scripts_seen.${script};
+ scripts_seen.${script} = 1;
+ ~%]
+ "[%- script %]",
+ [% END %]
+ "[% offline_html %]"
+];
+
+const staticCache = 'static';
+
+addEventListener('install', function(evt) {
+ evt.waitUntil(precache());
+});
+
+async function precache() {
+ const cache = await caches.open(staticCache);
+ return cache.addAll(requiredOffline);
+}
+
+addEventListener('fetch', fetchEvent => {
+ const request = fetchEvent.request;
+ const url = new URL(request.url);
+
+ if (request.method !== "GET" || url.origin !== location.origin) {
+ return;
+ }
+
+ fetchEvent.respondWith(async function() {
+ if (request.mode === 'navigate') {
+ const fetchPromise = fetch(request);
+
+ try {
+ return await fetchPromise;
+ }
+ catch {
+ let cached = await caches.match("[% offline_html %]");
+ return cached || offlineResponse();
+ }
+ } else {
+ const responseFromCache = await caches.match(request);
+ return responseFromCache || fetch(request);
+ }
+ }());
+});
+
+var offlineResponse = () =>
+ new Response('Service Unavailable', { status: 503, statusText: 'Service Unavailable', headers: { 'Content-Type': 'text/html' }}); \ No newline at end of file