From e42995047ca05f51c12d8b4eabda557f851832f3 Mon Sep 17 00:00:00 2001
From: Jaifroid
Date: Sun, 9 Jan 2022 09:19:51 +0000
Subject: [PATCH] Enable Service Worker mode in Firefox extension via PWA
workaround #764 (#771)
---
.github/workflows/CI.yml | 10 +
docker/dockerfile-moz-extension.pwa | 12 +
docker/index.nginx.html | 19 ++
index.html | 6 +-
manifest.json | 2 +
scripts/Publish-Implementation.ps1 | 133 +++++++++++
scripts/create_all_packages.sh | 3 +-
scripts/test_duplicate_values.sh | 30 +++
scripts/test_pwa_server.sh | 14 ++
service-worker.js | 241 ++++++++++++++-----
www/index.html | 19 +-
www/js/app.js | 359 ++++++++++++++++++++--------
www/js/init.js | 96 ++++----
www/js/lib/settingsStore.js | 20 +-
www/js/lib/uiUtil.js | 75 +++++-
15 files changed, 825 insertions(+), 214 deletions(-)
create mode 100644 docker/dockerfile-moz-extension.pwa
create mode 100644 docker/index.nginx.html
create mode 100644 scripts/Publish-Implementation.ps1
create mode 100644 scripts/test_duplicate_values.sh
create mode 100644 scripts/test_pwa_server.sh
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 2d532d3af..8a2322470 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -24,6 +24,16 @@ jobs:
# Clone the repo and checkout the commit for which the workflow was triggered
- uses: actions/checkout@v2
+ - name: Test integrity of app parameters
+ shell: bash
+ run: |
+ # Check that values of assetsCache and appVersion are correctly duplicated
+ chmod +x ./scripts/test_duplicate_values.sh
+ ./scripts/test_duplicate_values.sh
+ # Check that PWAServer is correctly set in app.js
+ chmod +x ./scripts/test_pwa_server.sh
+ ./scripts/test_pwa_server.sh
+
# Install Node.js LTS
- uses: actions/setup-node@v2
with:
diff --git a/docker/dockerfile-moz-extension.pwa b/docker/dockerfile-moz-extension.pwa
new file mode 100644
index 000000000..1c6030062
--- /dev/null
+++ b/docker/dockerfile-moz-extension.pwa
@@ -0,0 +1,12 @@
+FROM nginx:latest
+
+EXPOSE 80
+
+RUN mkdir /usr/share/nginx/html/current/
+COPY ./docker/index.nginx.html /usr/share/nginx/html/index.html
+COPY ./manifest.json /usr/share/nginx/html/current/
+COPY ./service-worker.js /usr/share/nginx/html/current/
+COPY ./index.html /usr/share/nginx/html/current/
+COPY ./CHANGELOG.md /usr/share/nginx/html/current/
+COPY ./LICENSE-GPLv3.txt /usr/share/nginx/html/current/
+COPY ./www /usr/share/nginx/html/current/www/
diff --git a/docker/index.nginx.html b/docker/index.nginx.html
new file mode 100644
index 000000000..aa55382fc
--- /dev/null
+++ b/docker/index.nginx.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ Redirection to index.html
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.html b/index.html
index 8f95c4631..bb99a238d 100644
--- a/index.html
+++ b/index.html
@@ -1,8 +1,12 @@
+
-Redirection to index.html
+ Redirection to index.html
+
+
+
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
index 2bb140bc4..0003747ab 100644
--- a/manifest.json
+++ b/manifest.json
@@ -32,6 +32,8 @@
"id": "kiwix-html5-unlisted@kiwix.org"
}
},
+
+ "web_accessible_resources": ["www/index.html"],
"background": {
"scripts": ["webextension/backgroundscript.js"]
diff --git a/scripts/Publish-Implementation.ps1 b/scripts/Publish-Implementation.ps1
new file mode 100644
index 000000000..f07d9e3cf
--- /dev/null
+++ b/scripts/Publish-Implementation.ps1
@@ -0,0 +1,133 @@
+# This is a utility script which helps developers choose sensible values for publishing the implementation of this app
+# to GitHub Pages, or to eh docker container. It is useful for testing and developing code in a specific branch. It checks
+# app.js and service-worker.js for consistency, and checks that the underlying branch of a PR has been checked out
+# (rather than the PR itself). It then calls the GitHub REST API for dispatching the workflow using the provided values.
+#
+# IMPORTANT: Ensure that your personal github token is in your local copy of the '/scripts' directory, saved as 'github_token'.
+#
+# You may run this script with commandline switches -machine_name (this could be 'dev'), -target (either 'ghpages' or 'docker'),
+# the -branch_name, and -dryrun (this will show the changes that would be made if run without the -dryrun switch).
+# Alternatively, if you do not provide these values, you will be prompted with sensible defaults.
+
+# Prevents execution with unrecognized switches
+[CmdletBinding()]
+param (
+ [string]$machine_name = "",
+ [string]$target = "",
+ [string]$branch_name = "",
+ [switch]$dryrun = $false
+)
+
+# Provide parameters
+$release_uri = 'https://api.github.com/repos/kiwix/kiwix-js/actions/workflows/publish-extension.yaml/dispatches'
+
+$app_params = Select-String 'appVersion' "$PSScriptRoot\..\www\js\app.js" -List
+$serviceworker = Select-String 'appVersion' "$PSScriptRoot\..\service-worker.js" -List
+$suggested_build = ''
+$app_tag = ''
+if ($app_params -match 'params\[[''"]appVersion[''"]]\s*=\s*[''"]([^''"]+)') {
+ $app_tag = $matches[1]
+ $suggested_build = 'dev-' + $app_tag
+} else {
+ "*** WARNING: App version is incorrectly set in app.js.`nPlease correct before continuing.`n"
+ exit
+}
+$sw_tag = ''
+if ($serviceworker -match 'appVersion\s*=\s*[''"]([^''"]+)') {
+ $sw_tag = $matches[1]
+ if ($sw_tag -ne $app_tag) {
+ "*** WARNING: The version in app.js [$app_tag] does not match the version in service-worker.js [$sw_tag]! ***"
+ "Please correct before continuing.`n"
+ exit
+ } else {
+ "`nVersion in app.js: $app_tag"
+ "Version in service-worker.js: $sw_tag`n"
+ }
+} else {
+ "*** WARNING: App version is incorrectly set in service-worker.js.`nPlease correct before continuing.`n"
+ exit
+}
+
+if (Test-Path $PSScriptRoot/github_token -PathType Leaf) {
+ $github_token = Get-Content -Raw "$PSScriptRoot/github_token"
+} else {
+ Write-Warning "Missing file github_token! Please add it to $PSScriptRoot to run this script.`n"
+ $github_token = $false
+}
+
+if ($machine_name -eq "") {
+ if (-Not $dryrun) {
+ $dryrun_check = Read-Host "Is this a dry run? [Y/N]"
+ $dryrun = -Not ( $dryrun_check -imatch 'n' )
+ If ($dryrun) {
+ "[DRYRUN]: Initiating dry run..."
+ }
+ }
+ ""
+ if ($target -eq "") {
+ $target = Read-Host "Which implementation (ghpages or docker) do you wish to update? Enter to accept suggested [ghpages]"
+ }
+ $machine_name = Read-Host "Give the name to use for the implementation, or Enter to accept suggested name [$suggested_build]"
+ ""
+ if (-Not $machine_name) {
+ $machine_name = $suggested_build
+ $warning_message = "Please note that ""$app_tag"" will appear in the app as the appVersion. If you want to change that, press Ctrl-C`nand re-run this script entering a build number matching 9.9.9."
+ } elseif ($machine_name -match '^[\d.]+') {
+ $warning_message = "*** Please be aware that you have entered a release tag [$machine_name], and so it will be used as the appVersion of the container`n" +
+ "and will be visible to users. If this is NOT want you want, press Ctrl-C to abort this script, and re-run with the suggested build number."
+ }
+ if ($warning_message) { Write-Warning $warning_message }
+}
+
+if (-Not $target) {
+ $target = "ghpages"
+}
+
+if ($branch_name -eq "") {
+ $suggested_branch = &{ git branch --show-current }
+ $branch_name = Read-Host "`nGive the branch name to use of the implementation, or Enter to accept [$suggested_branch]"
+ if (-Not $branch_name) { $branch_name = $suggested_branch }
+ if ($branch_name -imatch '^pr/\d+') {
+ ""
+ Write-Warning "You appear to have indicated a PR. Please check out the underlying branch to use this script,`nor else run it again and give the branch name at the prompt.`n"
+ return
+ }
+}
+
+"`nMachine name set to: $machine_name"
+"Target set to: $target"
+"Branch name set to: $branch_name"
+
+if (-Not $dryrun -and -Not $github_token) {
+ "`nSupply token to continue.`n"
+ exit
+}
+
+# Set up dispatch_params object - for API see https://docs.github.com/en/rest/reference/actions#create-a-workflow-dispatch-event
+$dispatch_params = @{
+ Uri = $release_uri
+ Method = 'POST'
+ Headers = @{
+ 'Authorization' = "token $github_token"
+ 'Accept' = 'application/vnd.github.v3+json'
+ }
+ Body = @{
+ 'ref' = $branch_name
+ 'inputs' = @{
+ 'version' = $machine_name
+ 'target' = $target
+ }
+ } | ConvertTo-Json
+ ContentType = "application/json"
+}
+
+$dispatch_f = ($dispatch_params | Format-List | Out-String);
+"`nDispatch parameters:`n$dispatch_f"
+
+# Post to the release server
+if (-Not $dryrun) {
+ Invoke-RestMethod @dispatch_params
+ "`nCheck for any error message above. An empty dispatch is normal, and indicates that the command was accepted.`n"
+} else {
+ "[DRYRUN]: Complete.`n"
+}
diff --git a/scripts/create_all_packages.sh b/scripts/create_all_packages.sh
index e33984ad8..224d37ad1 100755
--- a/scripts/create_all_packages.sh
+++ b/scripts/create_all_packages.sh
@@ -58,7 +58,8 @@ else
sed -i -e "s/$VERSION_TO_REPLACE/$MAJOR_NUMERIC_VERSION/" tmp/manifest.json
fi
sed -i -e "s/$VERSION_TO_REPLACE/$VERSION/" tmp/manifest.webapp
-sed -i -e "s/$VERSION_TO_REPLACE/$VERSION/" tmp/www/index.html
+sed -i -e "s/$VERSION_TO_REPLACE/$VERSION/" tmp/service-worker.js
+sed -i -e "s/$VERSION_TO_REPLACE/$VERSION/" tmp/www/js/app.js
mkdir -p build
rm -rf build/*
diff --git a/scripts/test_duplicate_values.sh b/scripts/test_duplicate_values.sh
new file mode 100644
index 000000000..a705c3868
--- /dev/null
+++ b/scripts/test_duplicate_values.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# This bash script tests whether app.js and service-worker.js have the same value for appVersion and for ASSETS_CACHE.
+
+# Find the repo dir (it's the parent of the dir that contains this script)
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+REPO_DIR="$(dirname "$SCRIPT_DIR")"
+
+# Check values in files
+cd $REPO_DIR
+SW_VERSION="$(grep 'appVersion\s=' service-worker.js | sed -E "s/[^[:digit:]]+([^\"']+).*/\1/")"
+APP_VERSION="$(grep 'params\[.appVersion' www/js/app.js | sed -E "s/[^[:digit:]]+([^\"']+).*/\1/")"
+echo "service-worker.js : $SW_VERSION"
+echo "app.js : $APP_VERSION"
+if [ $SW_VERSION == $APP_VERSION ] ; then
+ echo "Both values of 'appVersion' are identical"
+else
+ echo "ERROR! Please ensure values for 'appVersion' in app.js and service-worker.js are identical!"
+ exit 1
+fi
+SW_ASSETS_CACHE="$( grep 'ASSETS_CACHE\s=' service-worker.js | sed -E "s/[^']+'([^']+).*/\1/")"
+APP_ASSETS_CACHE="$(grep 'ASSETS_CACHE\s=' www/js/app.js | sed -E "s/[^']+'([^']+).*/\1/")"
+echo "service-worker.js : $SW_ASSETS_CACHE"
+echo "app.js : $APP_ASSETS_CACHE"
+if [ $SW_ASSETS_CACHE == $APP_ASSETS_CACHE ] ; then
+ echo "Both values of 'ASSETS_CACHE' are identical"
+else
+ echo "ERROR! Please ensure values for 'ASSETS_CACHE' in app.js and service-worker.js are identical!"
+ exit 1
+fi
\ No newline at end of file
diff --git a/scripts/test_pwa_server.sh b/scripts/test_pwa_server.sh
new file mode 100644
index 000000000..6010dcecc
--- /dev/null
+++ b/scripts/test_pwa_server.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# This bash script tests whether PWAServer has been set correctly in app.js
+
+SERVER=$(grep -E '^[^/]+params.+?PWAServer.+?http' ./www/js/app.js)
+echo "The PWAServer is set to $SERVER"
+SERVER_COUNT=$(grep -o 'PWAServer' <<< "$SERVER" | wc -l)
+echo "$SERVER_COUNT server(s) are set in app.js"
+if [[ $SERVER_COUNT > 1 || ! $SERVER =~ 'kiwix.org' ]]; then
+ echo "WARNING: The value of params['PWAServer'] is incorrectly set in app.js!"
+ exit 1
+else
+ echo "PWAServer is correctly set in app.js"
+fi
diff --git a/service-worker.js b/service-worker.js
index 0b19654ec..6271db7b8 100644
--- a/service-worker.js
+++ b/service-worker.js
@@ -23,22 +23,40 @@
*/
'use strict';
+/**
+ * App version number - ENSURE IT MATCHES VALUE IN app.js
+ * DEV: Changing this will cause the browser to recognize that the Service Worker has changed, and it will
+ * download and install a new copy; we have to hard code this here because it is needed before any other file
+ * is cached in APP_CACHE
+ */
+const appVersion = '3.3-WIP';
+
/**
* The name of the Cache API cache in which assets defined in regexpCachedContentTypes will be stored
- * The value is defined in app.js and will be passed to Service Worker on initialization (to avoid duplication)
+ * The value is sometimes needed here before it can be passed from app.js, so we have to duplicate it
* @type {String}
*/
-var CACHE_NAME;
+// DEV: Ensure this matches the name defined in app.js
+const ASSETS_CACHE = 'kiwixjs-assetsCache';
/**
- * A global Boolean that governs whether CACHE_NAME will be used
+ * The name of the application cache to use for caching online code so that it can be used offline
+ * The cache name is made up of the prefix below and the appVersion: this is necessary so that when
+ * the app is updated, a new cache is created. The new cache will start being used after the user
+ * restarts the app, when we will also delete the old cache.
+ * @type {String}
+ */
+const APP_CACHE = 'kiwixjs-appCache-' + appVersion;
+
+/**
+ * A global Boolean that governs whether ASSETS_CACHE will be used
* Caching is on by default but can be turned off by the user in Configuration
* @type {Boolean}
*/
var useCache = true;
/**
- * A regular expression that matches the Content-Types of assets that may be stored in CACHE_NAME
+ * A regular expression that matches the Content-Types of assets that may be stored in ASSETS_CACHE
* Add any further Content-Types you wish to cache to the regexp, separated by '|'
* @type {RegExp}
*/
@@ -50,63 +68,156 @@ var regexpCachedContentTypes = /text\/css|text\/javascript|application\/javascri
* 'example-extension' is included to show how to add another schema if necessary
* @type {RegExp}
*/
-var regexpExcludedURLSchema = /^(?:chrome-extension|example-extension):/i;
+var regexpExcludedURLSchema = /^(?:file|chrome-extension|example-extension):/i;
/**
* Pattern for ZIM file namespace: see https://wiki.openzim.org/wiki/ZIM_file_format#Namespaces
* In our case, there is also the ZIM file name used as a prefix in the URL
* @type {RegExp}
*/
-var regexpZIMUrlWithNamespace = /(?:^|\/)([^/]+\/)([-ABCIJMUVWX])\/(.+)/;
+const regexpZIMUrlWithNamespace = /(?:^|\/)([^/]+\/)([-ABCIJMUVWX])\/(.+)/;
-self.addEventListener('install', function (event) {
- event.waitUntil(self.skipWaiting());
+/**
+ * The list of files that the app needs in order to run entirely from offline code
+ */
+let precacheFiles = [
+ ".", // This caches the redirect to www/index.html, in case a user launches the app from its root directory
+ "manifest.json",
+ "service-worker.js",
+ "www/css/app.css",
+ "www/css/bootstrap.css",
+ "www/css/kiwixJS_invert.css",
+ "www/css/kiwixJS_mwInvert.css",
+ "www/css/transition.css",
+ "www/img/icons/kiwix-256.png",
+ "www/img/icons/kiwix-32.png",
+ "www/img/icons/kiwix-60.png",
+ "www/img/spinner.gif",
+ "www/img/Icon_External_Link.png",
+ "www/index.html",
+ "www/article.html",
+ "www/main.html",
+ "www/js/app.js",
+ "www/js/init.js",
+ "www/js/lib/abstractFilesystemAccess.js",
+ "www/js/lib/arrayFromPolyfill.js",
+ "www/js/lib/bootstrap.bundle.js",
+ "www/js/lib/filecache.js",
+ "www/js/lib/jquery-3.2.1.slim.js",
+ "www/js/lib/promisePolyfill.js",
+ "www/js/lib/require.js",
+ "www/js/lib/settingsStore.js",
+ "www/js/lib/uiUtil.js",
+ "www/js/lib/utf8.js",
+ "www/js/lib/util.js",
+ "www/js/lib/xzdec_wrapper.js",
+ "www/js/lib/zstddec_wrapper.js",
+ "www/js/lib/zimArchive.js",
+ "www/js/lib/zimArchiveLoader.js",
+ "www/js/lib/zimDirEntry.js",
+ "www/js/lib/zimfile.js",
+ "www/js/lib/fontawesome/fontawesome.js",
+ "www/js/lib/fontawesome/solid.js",
+ "www/js/lib/xzdec-asm.js",
+ "www/js/lib/zstddec-asm.js",
+ "www/js/lib/xzdec-wasm.js",
+ "www/js/lib/xzdec-wasm.wasm",
+ "www/js/lib/zstddec-wasm.js",
+ "www/js/lib/zstddec-wasm.wasm"
+];
+
+// Process install event
+self.addEventListener("install", function (event) {
+ console.debug("[SW] Install Event processing");
+ // DEV: We can't skip waiting because too many params are loaded at an early stage from the old file before the new one can activate...
+ // self.skipWaiting();
+ // We try to circumvent the browser's cache by adding a header to the Request, and it ensures all files are explicitly versioned
+ var requests = precacheFiles.map(function (urlPath) {
+ return new Request(urlPath + '?v' + appVersion, { cache: 'no-cache' });
+ });
+ if (!regexpExcludedURLSchema.test(requests[0].url)) event.waitUntil(
+ caches.open(APP_CACHE).then(function (cache) {
+ return Promise.all(
+ requests.map(function (request) {
+ return fetch(request).then(function (response) {
+ // Fail on 404, 500 etc
+ if (!response.ok) throw Error('Could not fetch ' + request.url);
+ return cache.put(request.url.replace(/\?v[^?/]+$/, ''), response);
+ }).catch(function (err) {
+ console.error('There was an error pre-caching files', err);
+ });
+ })
+ );
+ })
+ );
});
+// Allow sw to control current page
self.addEventListener('activate', function (event) {
// "Claiming" the ServiceWorker is necessary to make it work right away,
// without the need to reload the page.
// See https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim
event.waitUntil(self.clients.claim());
+ console.debug('[SW] Claiming clients for current page');
+ // Check all the cache keys, and delete any old caches
+ event.waitUntil(
+ caches.keys().then(function (keyList) {
+ return Promise.all(keyList.map(function (key) {
+ console.debug('[SW] Current cache key is ' + key);
+ if (key !== APP_CACHE && key !== ASSETS_CACHE) {
+ console.debug('[SW] App updated to version ' + appVersion + ': deleting old cache');
+ return caches.delete(key);
+ }
+ }));
+ })
+ );
});
-var outgoingMessagePort = null;
-var fetchCaptureEnabled = false;
+let outgoingMessagePort = null;
+let fetchCaptureEnabled = false;
self.addEventListener('fetch', function (event) {
- if (fetchCaptureEnabled &&
- regexpZIMUrlWithNamespace.test(event.request.url) &&
- event.request.method === "GET") {
-
- // The ServiceWorker will handle this request either from CACHE_NAME or from app.js
-
- event.respondWith(
- // First see if the content is in the cache
- fromCache(event.request).then(
- function (response) {
- // The response was found in the cache so we respond with it
+ // Only cache GET requests
+ if (event.request.method !== "GET") return;
+ // Remove any querystring before requesting from the cache
+ var rqUrl = event.request.url.replace(/\?[^?]+$/i, '');
+ // Select cache depending on request format
+ var cache = /\.zim\//i.test(rqUrl) ? ASSETS_CACHE : APP_CACHE;
+ if (cache === ASSETS_CACHE && !fetchCaptureEnabled) return;
+ event.respondWith(
+ // First see if the content is in the cache
+ fromCache(cache, rqUrl).then(function (response) {
+ // The response was found in the cache so we respond with it
+ return response;
+ }, function () {
+ // The response was not found in the cache so we look for it in the ZIM
+ // and add it to the cache if it is an asset type (css or js)
+ if (cache === ASSETS_CACHE && regexpZIMUrlWithNamespace.test(rqUrl)) {
+ return fetchRequestFromZIM(event).then(function (response) {
+ // Add css or js assets to ASSETS_CACHE (or update their cache entries) unless the URL schema is not supported
+ if (regexpCachedContentTypes.test(response.headers.get('Content-Type')) &&
+ !regexpExcludedURLSchema.test(event.request.url)) {
+ event.waitUntil(updateCache(ASSETS_CACHE, event.request, response.clone()));
+ }
return response;
- },
- function () {
- // The response was not found in the cache so we look for it in the ZIM
- // and add it to the cache if it is an asset type (css or js)
- return fetchRequestFromZIM(event).then(function (response) {
- // Add css or js assets to CACHE_NAME (or update their cache entries) unless the URL schema is not supported
- if (regexpCachedContentTypes.test(response.headers.get('Content-Type')) &&
- !regexpExcludedURLSchema.test(event.request.url)) {
- event.waitUntil(updateCache(event.request, response.clone()));
- }
- return response;
- }).catch(function (msgPortData, title) {
- console.error('Invalid message received from app.js for ' + title, msgPortData);
- return msgPortData;
- });
- }
- )
- );
- }
- // If event.respondWith() isn't called because this wasn't a request that we want to handle,
- // then the default request/response behavior will automatically be used.
+ }).catch(function (msgPortData, title) {
+ console.error('Invalid message received from app.js for ' + title, msgPortData);
+ return msgPortData;
+ });
+ } else {
+ // It's not an asset, or it doesn't match a ZIM URL pattern, so we should fetch it with Fetch API
+ return fetch(event.request).then(function (response) {
+ // If request was successful, add or update it in the cache, but be careful not to cache the ZIM archive itself!
+ if (!regexpExcludedURLSchema.test(rqUrl) && !/\.zim\w{0,2}$/i.test(rqUrl)) {
+ event.waitUntil(updateCache(APP_CACHE, event.request, response.clone()));
+ }
+ return response;
+ }).catch(function (error) {
+ console.debug("[SW] Network request failed and no cache.", error);
+ });
+ }
+ })
+ );
});
self.addEventListener('message', function (event) {
@@ -123,13 +234,15 @@ self.addEventListener('message', function (event) {
if (event.data.action.useCache) {
// Turns caching on or off (a string value of 'on' turns it on, any other string turns it off)
useCache = event.data.action.useCache === 'on';
- if (useCache) CACHE_NAME = event.data.cacheName;
- console.log('[SW] Caching was turned ' + event.data.action.useCache);
+ console.debug('[SW] Caching was turned ' + event.data.action.useCache);
+ }
+ if (event.data.action === 'getCacheNames') {
+ event.ports[0].postMessage({ 'app': APP_CACHE, 'assets': ASSETS_CACHE });
}
if (event.data.action.checkCache) {
// Checks and returns the caching strategy: checkCache key should contain a sample URL string to test
testCacheAndCountAssets(event.data.action.checkCache).then(function (cacheArr) {
- event.ports[0].postMessage({ 'type': cacheArr[0], 'description': cacheArr[1], 'count': cacheArr[2] });
+ event.ports[0].postMessage({ type: cacheArr[0], name: cacheArr[1], description: cacheArr[2], count: cacheArr[3] });
});
}
}
@@ -208,51 +321,53 @@ function removeUrlParameters(url) {
}
/**
- * Looks up a Request in CACHE_NAME and returns a Promise for the matched Response
- * @param {Request} request The Request to fulfill from CACHE_NAME
+ * Looks up a Request in a cache and returns a Promise for the matched Response
+ * @param {String} cache The name of the cache to look in
+ * @param {String} requestUrl The Request URL to fulfill from cache
* @returns {Promise} A Promise for the cached Response, or rejects with strings 'disabled' or 'no-match'
*/
-function fromCache(request) {
+function fromCache(cache, requestUrl) {
// Prevents use of Cache API if user has disabled it
- if (!useCache) return Promise.reject('disabled');
- return caches.open(CACHE_NAME).then(function (cache) {
- return cache.match(request).then(function (matching) {
+ if (!useCache && cache === ASSETS_CACHE) return Promise.reject('disabled');
+ return caches.open(cache).then(function (cacheObj) {
+ return cacheObj.match(requestUrl).then(function (matching) {
if (!matching || matching.status === 404) {
return Promise.reject('no-match');
}
- console.log('[SW] Supplying ' + request.url + ' from ' + CACHE_NAME + '...');
+ console.debug('[SW] Supplying ' + requestUrl + ' from ' + cache + '...');
return matching;
});
});
}
/**
- * Stores or updates in CACHE_NAME the given Request/Response pair
+ * Stores or updates in a cache the given Request/Response pair
+ * @param {String} cache The name of the cache to open
* @param {Request} request The original Request object
* @param {Response} response The Response received from the server/ZIM
* @returns {Promise} A Promise for the update action
*/
-function updateCache(request, response) {
+function updateCache(cache, request, response) {
// Prevents use of Cache API if user has disabled it
- if (!useCache) return Promise.resolve();
- return caches.open(CACHE_NAME).then(function (cache) {
- console.log('[SW] Adding ' + request.url + ' to ' + CACHE_NAME + '...');
- return cache.put(request, response);
+ if (!useCache && cache === ASSETS_CACHE) return Promise.resolve();
+ return caches.open(cache).then(function (cacheObj) {
+ console.debug('[SW] Adding ' + request.url + ' to ' + cache + '...');
+ return cacheObj.put(request, response);
});
}
/**
* Tests the caching strategy available to this app and if it is Cache API, count the
- * number of assets in CACHE_NAME
+ * number of assets in ASSETS_CACHE
* @param {String} url A URL to test against excludedURLSchema
* @returns {Promise} A Promise for an array of format [cacheType, cacheDescription, assetCount]
*/
function testCacheAndCountAssets(url) {
- if (regexpExcludedURLSchema.test(url)) return Promise.resolve(['custom', 'Custom', '-']);
- if (!useCache) return Promise.resolve(['none', 'None', 0]);
- return caches.open(CACHE_NAME).then(function (cache) {
+ if (regexpExcludedURLSchema.test(url)) return Promise.resolve(['custom', 'custom', 'Custom', '-']);
+ if (!useCache) return Promise.resolve(['none', 'none', 'None', 0]);
+ return caches.open(ASSETS_CACHE).then(function (cache) {
return cache.keys().then(function (keys) {
- return ['cacheAPI', 'Cache API', keys.length];
+ return ['cacheAPI', ASSETS_CACHE, 'Cache API', keys.length];
}).catch(function(err) {
return err;
});
diff --git a/www/index.html b/www/index.html
index 302b3b1ca..daced0ce7 100644
--- a/www/index.html
+++ b/www/index.html
@@ -55,7 +55,7 @@
@@ -403,6 +403,11 @@
Other platforms/versions
Configuration
+
+
+
+
+
This application needs a ZIM archive to work. For download
instructions, please see the About section
@@ -582,7 +587,7 @@
Expert settings
-
+
Unable to display active content: This ZIM is not fully supported in jQuery mode.
Content may be available by searching above (type a space or a letter of the alphabet), or else
@@ -595,7 +600,7 @@