Experimenting audioContext for Apple (Safari)
[sgc3.git] / sw.js
blob2297680a89ea88ad0527c5c14eb8c22149779d59
1 /*
2  Copyright 2014 Google Inc. All Rights Reserved.
3  Licensed under the Apache License, Version 2.0 (the "License");
4  you may not use this file except in compliance with the License.
5  You may obtain a copy of the License at
6  http://www.apache.org/licenses/LICENSE-2.0
7  Unless required by applicable law or agreed to in writing, software
8  distributed under the License is distributed on an "AS IS" BASIS,
9  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10  See the License for the specific language governing permissions and
11  limitations under the License.
14 // While overkill for this specific sample in which there is only one cache,
15 // this is one best practice that can be followed in general to keep track of
16 // multiple caches used by a given service worker, and keep them all versioned.
17 // It maps a shorthand identifier for a cache to a specific, versioned cache name.
19 // Note that since global state is discarded in between service worker restarts, these
20 // variables will be reinitialized each time the service worker handles an event, and you
21 // should not attempt to change their values inside an event handler. (Treat them as constants.)
23 // If at any point you want to force pages that use this service worker to start using a fresh
24 // cache, then increment the CACHE_VERSION value. It will kick off the service worker update
25 // flow and the old cache(s) will be purged as part of the activate event handler when the
26 // updated service worker is activated.
28 // commit c7c294d59a9172180cdf14bde9b40ec6c56ce81b
29 // Author: Rob van Son <r.j.j.h.vanson@gmail.com>
30 // Date:   Thu May 3 14:03:27 2018 +0200
31 var CACHE_VERSION = 1;
32 var CURRENT_CACHES = {
33   prefetch: 'prefetch-cache-v' + CACHE_VERSION
36 self.addEventListener('install', function(event) {
37   var now = Date.now();
39   var urlsToPrefetch = [
40         '/',
41         'manifest.json',
42         'Background.png',
43         'sgc.png',
44         'SpeakGoodChinese3.xml',
45         'SpeakGoodChinese3_Settings.xml',
46         'SpeakGoodChinese3_SelectWords.xml',
47         'SpeakGoodChinese3_Credits.xml',
48         'audioProcessing.js',
49         'internationalization_tables.js',
50         'mespeak/mespeak.full.js',
51         'mespeak/mespeak_config.json',
52         'mespeak/voices/zh.json',
53         'fft.js/lib/real.js',
54         'fft.js/lib/complex.js',
55         'toneprot.js',
56         'wordlists.js',
57         'wordlists_plus.js',
58         'RecordRTC.min.js',
59         'jszip.min.js',
60         'xhtml-default.css',
61   ];
63   // All of these logging statements should be visible via the "Inspect" interface
64   // for the relevant SW accessed via chrome://serviceworker-internals
65   console.log('Handling install event. Resources to prefetch:', urlsToPrefetch);
67   event.waitUntil(
68     caches.open(CURRENT_CACHES.prefetch).then(function(cache) {
69       var cachePromises = urlsToPrefetch.map(function(urlToPrefetch) {
70         // This constructs a new URL object using the service worker's script location as the base
71         // for relative URLs.
72         var url = new URL(urlToPrefetch, location.href);
73         // Append a cache-bust=TIMESTAMP URL parameter to each URL's query string.
74         // This is particularly important when precaching resources that are later used in the
75         // fetch handler as responses directly, without consulting the network (i.e. cache-first).
76         // If we were to get back a response from the HTTP browser cache for this precaching request
77         // then that stale response would be used indefinitely, or at least until the next time
78         // the service worker script changes triggering the install flow.
79         url.search += (url.search ? '&' : '?') + 'cache-bust=' + now;
81         // It's very important to use {mode: 'no-cors'} if there is any chance that
82         // the resources being fetched are served off of a server that doesn't support
83         // CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing).
84         // In this example, www.chromium.org doesn't support CORS, and the fetch()
85         // would fail if the default mode of 'cors' was used for the fetch() request.
86         // The drawback of hardcoding {mode: 'no-cors'} is that the response from all
87         // cross-origin hosts will always be opaque
88         // (https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#cross-origin-resources)
89         // and it is not possible to determine whether an opaque response represents a success or failure
90         // (https://github.com/whatwg/fetch/issues/14).
91         var request = new Request(url, {mode: 'no-cors'});
92         return fetch(request).then(function(response) {
93           if (response.status >= 400) {
94             throw new Error('request for ' + urlToPrefetch +
95               ' failed with status ' + response.statusText);
96           }
98           // Use the original URL without the cache-busting parameter as the key for cache.put().
99           return cache.put(urlToPrefetch, response);
100         }).catch(function(error) {
101           console.error('Not caching ' + urlToPrefetch + ' due to ' + error);
102         });
103       });
105       return Promise.all(cachePromises).then(function() {
106         console.log('Pre-fetching complete.');
107       });
108     }).catch(function(error) {
109       console.error('Pre-fetching failed:', error);
110     })
111   );
114 self.addEventListener('activate', function(event) {
115   // Delete all caches that aren't named in CURRENT_CACHES.
116   // While there is only one cache in this example, the same logic will handle the case where
117   // there are multiple versioned caches.
118   var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {
119     return CURRENT_CACHES[key];
120   });
122   event.waitUntil(
123     caches.keys().then(function(cacheNames) {
124       return Promise.all(
125         cacheNames.map(function(cacheName) {
126           if (expectedCacheNames.indexOf(cacheName) === -1) {
127             // If this cache name isn't present in the array of "expected" cache names, then delete it.
128             console.log('Deleting out of date cache:', cacheName);
129             return caches.delete(cacheName);
130           }
131         })
132       );
133     })
134   );
137 self.addEventListener('fetch', function(event) {
138   console.log('Handling fetch event for', event.request.url);
140   event.respondWith(
141     // caches.match() will look for a cache entry in all of the caches available to the service worker.
142     // It's an alternative to first opening a specific named cache and then matching on that.
143     caches.match(event.request).then(function(response) {
144       if (response) {
145         console.log('Found response in cache:', response);
147         return response;
148       }
150       console.log('No response found in cache. About to fetch from network...');
152       // event.request will always have the proper mode set ('cors, 'no-cors', etc.) so we don't
153       // have to hardcode 'no-cors' like we do when fetch()ing in the install handler.
154       return fetch(event.request).then(function(response) {
155         console.log('Response from network is:', response);
157         return response;
158       }).catch(function(error) {
159         // This catch() will handle exceptions thrown from the fetch() operation.
160         // Note that a HTTP error response (e.g. 404) will NOT trigger an exception.
161         // It will return a normal response object that has the appropriate error code set.
162         console.error('Fetching failed:', error);
164         throw error;
165       });
166     })
167   );