const OFFLINE_URL = 'lib/pwa/offline.html'; importScripts("vendor/npm-asset/dexie/dist/dexie.min.js") const staticAssets = [ '.', 'themes/base_files/css/tiki_base.css', 'vendor_bundled/vendor/bower-asset/fontawesome/css/all.css', 'themes/default/css/default.css', 'img/tiki/Tiki_WCG.png', 'tiki-index.php', 'lib/jquery_tiki/iconsets.js', 'lib/tiki-js.js', 'lib/jquery_tiki/tiki-jquery.js', 'tiki-listpages.php', 'vendor/npm-asset/dexie/dist/dexie.min.js', 'lib/jquery_tiki/tiki-trackers.js', OFFLINE_URL, ]; const cacheName = 'pages-cache-v1'; var db = new Dexie("post_cache"); db.version(1).stores({ messages: 'name,value', post_cache: 'key,request,timestamp', }); self.addEventListener('install', event => { event.waitUntil( caches.open(cacheName) .then(cache => cache.addAll(staticAssets)) .then(self.skipWaiting()) ); }); self.addEventListener('activate', event => { const currentCaches = [cacheName]; event.waitUntil( caches.keys().then(cacheNames => { return cacheNames.filter(cacheName => !currentCaches.includes(cacheName)); }).then(cachesToDelete => { return Promise.all(cachesToDelete.map(cacheToDelete => { return caches.delete(cacheToDelete); })); }).then(() => self.clients.claim()) ); }); // The fetch handler serves responses for same-origin resources from a cache. // If no response is found, it populates the runtime cache with the response // from the network before returning it to the page. self.addEventListener('fetch', event => { function normalizeRequest(url) { if (url.includes("tiki-view_tracker_item.php") || url.includes("tiki-ajax_services.php")) { url = url.replace(/&from=.*/, ""); } return url; } // Skip cross-origin requests, like those for Google Analytics. if (event.request.url.startsWith(self.location.origin) && event.request.method === "GET" && event.request.url.indexOf("logout") === -1) { let request = event.request; let url = normalizeRequest(request.url); event.respondWith( caches.match(url).then(cachedResponse => { return caches.open(cacheName).then(cache => { return fetch(event.request).then(response => { // Put a copy of the response in the runtime cache. return cache.put(event.request, response.clone()).then(() => { return response; }); }).catch(error => { console.warn(cachedResponse, url) if (cachedResponse) { return cachedResponse; } return caches.match(OFFLINE_URL); }); }).catch(error => { return caches.match(OFFLINE_URL); }); }).catch(error => { return caches.match(OFFLINE_URL); }) ); } else if ((event.request.method === "POST" || event.request.method === "PUT") && event.request.url.indexOf("logout") === -1) { event.respondWith( fetch(event.request.clone()) .then(function (response) { return response; }) .catch(function () { return cachePut(event, db.post_cache).then(function (resp) { //save request to be done later return caches.match(event.request.url).then(cachedResponse => { return db.messages.put({"name": "show-warning", "value": true}).then(function () { let body; var init = { "status": 200, "statusText": "You are offline" }; if (cachedResponse) { console.warn("fetch", event.request.url) body = cachedResponse.body } else { let url = normalizeRequest(event.request.referrer); console.warn("fetch", url) return caches.match(url).then(cachedResponse => { console.warn("cache", cachedResponse) if (cachedResponse) body = cachedResponse.body return new Response(body, init); }) } return new Response(body, init); }); }); }); }) ); } else { console.error(event.request); } }); /** * Serializes a Request into a plain JS object. * * @param request * @returns Promise */ function serializeRequest(request) { var serialized = { url: request.url, headers: serializeHeaders(request.headers), method: request.method, mode: request.mode, credentials: request.credentials, cache: request.cache, redirect: request.redirect, referrer: request.referrer }; // Only if method is not `GET` or `HEAD` is the request allowed to have body. if (request.method !== 'GET' && request.method !== 'HEAD') { return request.clone().text().then(function (body) { serialized.body = body; return Promise.resolve(serialized); }); } return Promise.resolve(serialized); } /** * Saves the response for the given request eventually overriding the previous version * * @param data * @returns Promise */ function cachePut(event, store) { var request = event.request.clone(); return serializeRequest(request.clone()).then(function (data) { var entry = { key: Date.now(), request: data, timestamp: Date.now() }; return store.put(entry).then(value => { return store.get(entry.key).then(function () { }) }) }); } /** * Serializes headers into a plain JS object * * @param headers * @returns object */ function serializeHeaders(headers) { var serialized = {}; // `for(... of ...)` is ES6 notation but current browsers supporting SW, support this // notation as well and this is the only way of retrieving all the headers. for (var entry of headers.entries()) { serialized[entry[0]] = entry[1]; } return serialized; }