-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathcache.js
138 lines (130 loc) · 4.92 KB
/
cache.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
This file is part of Alpertron Calculators.
Copyright 2015 Dario Alejandro Alpern
Alpertron Calculators is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Alpertron Calculators is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Alpertron Calculators. If not, see <http://www.gnu.org/licenses/>.
*/
/* global getCalcURLs */
/* global initMenubarEvents */
let url = window.location.pathname;
async function updateCache(cache)
{
try
{ // Retrieve from server all files. Use temporary cache.
const tempCache = await caches.open("cacheTEMP");
// Do not retrieve alternate JavaScript code if
// WebAssembly is enabled in browser. Always include current HTML.
await tempCache.addAll([url].concat((typeof(WebAssembly) === "undefined")?
getCalcURLs():getCalcURLs().slice(1)));
// For each file in temporary cache, copy it to cache passed as parameter.
const matchesArr = await tempCache.matchAll();
for (const match of matchesArr)
{
await cache.put(match.url, match);
}
}
catch (e)
{ // Nothing to do on error (missing file, error retrieving file, etc.)
}
finally
{ // In any case, delete the temporary cache.
await caches.delete("cacheTEMP");
}
}
async function fillCache()
{
try
{
// Test whether the current HTML is already on the cache.
const cache = await caches.open("newCache");
// url has the format "/xxxx.HTML".
const response = await cache.match(url);
if (typeof response === "undefined")
{ // HTML is not in cache.
await updateCache(cache);
}
else
{ // Response is the HTML contents.
let date = response.headers.get("last-modified");
// Request the HTML from the Web server.
// Use non-standard header to tell Service Worker
// not to retrieve HTML from cache.
let responseHTML = await fetch(url,
{headers:{"If-Modified-Since": date, "x-calc": "1"},
cache: "no-store"});
if (responseHTML.status !== 200)
{
return; // HTML could not be retrieved, so go out.
}
if (date === responseHTML.headers.get("last-modified"))
{
return; // HTML has not changed,
// so other files have not been changed. Go out.
}
// Read files to new cache.
// Use temporary cache so if there is any network error,
// original cache is not changed.
try
{
let tempCache = await caches.open("cacheTEMP");
// Do not fetch HTML because it is already fetched.
await tempCache.addAll((typeof(WebAssembly) === "undefined")?
getCalcURLs():getCalcURLs().slice(1));
// Copy cached resources to main cache and delete this one.
let matchesArr = await tempCache.matchAll();
// For each match...
for (const match of matchesArr)
{
let urlTemp = match.url;
let indexZero = url.indexOf("00");
if (indexZero > 0)
{ // There is an old version of this resource on cache to be erased.
let keysArr = await cache.keys();
// For each key...
for (const key of keysArr)
{ // Traverse cache.
if (key.url.startsWith(urlTemp.substring(0, indexZero+2)) &&
key.url.substring(indexZero+2, indexZero+4) !== urlTemp.substring(indexZero+2, indexZero+4) &&
key.url.endsWith(urlTemp.substring(indexZero+4)))
{ // Old version of asset found (different number and same prefix
// and suffix). Delete it from cache.
await cache.delete(key);
}
}
}
// Put resource into cache.
await cache.put(urlTemp, match);
}
await cache.put(url, responseHTML);
}
catch (e) // Cannot fetch HTML.
{
await updateCache(cache);
}
}
}
finally
{
await caches.delete("cacheTEMP");
}
}
function registerServiceWorker()
{
initMenubarEvents();
if ("serviceWorker" in navigator)
{ // Attempt to register service worker.
// There is no need to do anything on registration success or failure in this JavaScript module.
navigator["serviceWorker"]["register"]("calcSW.js").
then(fillCache, function()
{
});
}
}