combo/combo/apps/pwa/templates/combo/service-worker.js

184 lines
5.0 KiB
JavaScript

{% load combo gadjo static thumbnail %}
/* global self, caches, fetch, URL, Response */
'use strict';
const applicationServerPublicKey = {{ pwa_vapid_publik_key|as_json|safe }};
function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
var config = {
version: 'v{{ version }}',
staticCacheItems: [
'/__pwa__/offline/',
{% if pwa_settings.application_icon %}
{% thumbnail pwa_settings.application_icon '512x512' crop='center' format='PNG' as im %}
'{{ im.url }}'
{% endthumbnail %}
{% endif %}
],
cachePathPattern: /^\/static\/.*/,
handleFetchPathPattern: /.*/,
offlinePage: '/__pwa__/offline/'
};
function cacheName (key, opts) {
return `${opts.version}-${key}`;
}
function addToCache (cacheKey, request, response) {
if (response.ok && cacheKey !== null) {
var copy = response.clone();
caches.open(cacheKey).then( cache => {
cache.put(request, copy);
});
}
return response;
}
function fetchFromCache (event) {
return caches.match(event.request).then(response => {
if (!response) {
throw Error(`${event.request.url} not found in cache`);
}
return response;
});
}
function offlineResponse (resourceType, opts) {
if (resourceType === 'content') {
return caches.match(opts.offlinePage);
}
return undefined;
}
self.addEventListener('install', event => {
function onInstall (event, opts) {
var cacheKey = cacheName('static', opts);
return caches.open(cacheKey)
.then(cache => cache.addAll(opts.staticCacheItems));
}
event.waitUntil(
onInstall(event, config).then( () => self.skipWaiting() )
);
});
self.addEventListener('activate', event => {
function onActivate (event, opts) {
return caches.keys()
.then(cacheKeys => {
var oldCacheKeys = cacheKeys.filter(key => key.indexOf(opts.version) !== 0);
var deletePromises = oldCacheKeys.map(oldKey => caches.delete(oldKey));
return Promise.all(deletePromises);
});
}
event.waitUntil(
onActivate(event, config)
.then( () => self.clients.claim() )
);
});
self.addEventListener('fetch', event => {
function shouldHandleFetch (event, opts) {
var request = event.request;
var url = new URL(request.url);
var criteria = {
matchesPathPattern: opts.handleFetchPathPattern.test(url.pathname),
isGETRequest : request.method === 'GET',
isFromMyOrigin : url.origin === self.location.origin
};
var failingCriteria = Object.keys(criteria)
.filter(criteriaKey => !criteria[criteriaKey]);
return !failingCriteria.length;
}
function onFetch (event, opts) {
var request = event.request;
var url = new URL(request.url);
var acceptHeader = request.headers.get('Accept');
var resourceType = 'static';
var cacheKey;
if (acceptHeader.indexOf('text/html') !== -1) {
resourceType = 'content';
} else if (acceptHeader.indexOf('image') !== -1) {
resourceType = 'image';
}
cacheKey = null;
if (opts.cachePathPattern.test(url.pathname)) {
cacheKey = cacheName(resourceType, opts);
}
/* always network first */
event.respondWith(
fetch(request)
.then(response => addToCache(cacheKey, request, response))
.catch(() => fetchFromCache(event))
.catch(() => offlineResponse(resourceType, opts))
);
}
if (shouldHandleFetch(event, config)) {
onFetch(event, config);
}
});
self.addEventListener('push', event => {
console.log('[Service Worker] Push Received.');
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
var message = JSON.parse(event.data.text());
const title = message.summary;
const options = {
body: message.body,
data: {"url": message.url},
badge: {{ pwa_notification_badge_url|as_json|safe }},
icon: {{ pwa_notification_icon_url|as_json|safe }}
};
event.waitUntil(self.registration.showNotification(title, options));
});
self.addEventListener('notificationclick', function(event) {
var url = event.notification.data.url;
event.notification.close();
if (url) {
event.waitUntil(
clients.openWindow(url)
);
}
});
self.addEventListener('pushsubscriptionchange', event => {
console.log('[Service Worker]: \'pushsubscriptionchange\' event fired.');
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
event.waitUntil(
self.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
.then(function(newSubscription) {
console.log('[Service Worker] New subscription: ', newSubscription);
combo_pwa_update_subscription_on_server(newSubscription);
})
);
});