basket random
@@ -103,6 +103,11 @@
|
|||||||
"aliases": [],
|
"aliases": [],
|
||||||
"categories": []
|
"categories": []
|
||||||
},
|
},
|
||||||
|
"Basket Random": {
|
||||||
|
"path": "basket-random",
|
||||||
|
"aliases": [],
|
||||||
|
"categories": []
|
||||||
|
},
|
||||||
"Basketball Stars": {
|
"Basketball Stars": {
|
||||||
"path": "basketball-stars",
|
"path": "basketball-stars",
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Basket Random",
|
||||||
|
"short_name": "Basket Random",
|
||||||
|
"description": "",
|
||||||
|
"start_url": "index.html",
|
||||||
|
"display": "fullscreen",
|
||||||
|
"orientation": "any",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"icons": []
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 775 B |
|
After Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 282 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 512 B |
|
After Width: | Height: | Size: 236 B |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 253 B |
|
After Width: | Height: | Size: 79 B |
|
After Width: | Height: | Size: 505 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 239 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 89 B |
|
After Width: | Height: | Size: 828 B |
|
After Width: | Height: | Size: 677 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 390 B |
|
After Width: | Height: | Size: 70 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 76 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 714 B |
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Basket Random </title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
|
||||||
|
<meta name="generator" content="Construct 3" />
|
||||||
|
|
||||||
|
<link rel="manifest" href="appmanifest.json" />
|
||||||
|
<link rel="icon" href="./splash.jpeg">
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
<script>
|
||||||
|
window.addEventListener(
|
||||||
|
"keydown",
|
||||||
|
function (e) {
|
||||||
|
// space and arrow keys
|
||||||
|
if ([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="box2d.wasm.js"></script>
|
||||||
|
<noscript>
|
||||||
|
<div id="notSupportedWrap">
|
||||||
|
<h2 id="notSupportedTitle">This content requires JavaScript</h2>
|
||||||
|
<p class="notSupportedMessage">
|
||||||
|
JavaScript appears to be disabled. Please enable it to view this content.
|
||||||
|
</p>
|
||||||
|
<p class="notSupportedMessage">
|
||||||
|
This content was made with Construct 3 - a
|
||||||
|
<a href="https://www.construct.net/en">free game maker</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
|
<script src="scripts/supportcheck.js"></script>
|
||||||
|
<script src="scripts/offlineclient.js"></script>
|
||||||
|
<script src="scripts/main.js"></script>
|
||||||
|
<script src="scripts/register-sw.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
'use strict';
|
||||||
|
(self.inputPort = null),
|
||||||
|
(self.jobQueue = []),
|
||||||
|
(self.jobWorkers = []),
|
||||||
|
(self.sentBlobs = []),
|
||||||
|
(self.sentBuffers = []),
|
||||||
|
(self.importedScripts = []),
|
||||||
|
(self.lastBroadcasts = new Map());
|
||||||
|
class JobWorker {
|
||||||
|
constructor(a, b) {
|
||||||
|
(this._port = a),
|
||||||
|
(this._number = b),
|
||||||
|
(this._isReady = !1),
|
||||||
|
(this._isBusy = !1),
|
||||||
|
(this._port.onmessage = (a) => this._OnMessage(a.data));
|
||||||
|
}
|
||||||
|
ImportScripts(a) {
|
||||||
|
this._port.postMessage({ type: '_import_scripts', scripts: a });
|
||||||
|
}
|
||||||
|
SendBlob(a, b) {
|
||||||
|
this._port.postMessage({ type: '_send_blob', blob: a, id: b });
|
||||||
|
}
|
||||||
|
SendBuffer(a, b) {
|
||||||
|
this._port.postMessage({ type: '_send_buffer', buffer: a, id: b });
|
||||||
|
}
|
||||||
|
SendJob(a) {
|
||||||
|
if (this._isBusy || !this._isReady) throw new Error('cannot take job');
|
||||||
|
(this._isBusy = !0), this._port.postMessage(a, a['transferables']);
|
||||||
|
}
|
||||||
|
_InitBroadcast(a) {
|
||||||
|
this._port.postMessage(a, a['transferables']);
|
||||||
|
}
|
||||||
|
SendReady() {
|
||||||
|
this._port.postMessage({ type: '_ready' });
|
||||||
|
}
|
||||||
|
IsReady() {
|
||||||
|
return this._isReady;
|
||||||
|
}
|
||||||
|
_OnReady() {
|
||||||
|
(this._isReady = !0), this.MaybeStartNextJob();
|
||||||
|
}
|
||||||
|
IsBusy() {
|
||||||
|
return this._isBusy;
|
||||||
|
}
|
||||||
|
GetNumber() {
|
||||||
|
return this._number;
|
||||||
|
}
|
||||||
|
_OnMessage(a) {
|
||||||
|
const b = a['type'];
|
||||||
|
return 'ready' === b
|
||||||
|
? void this._OnReady()
|
||||||
|
: 'done' === b
|
||||||
|
? void this._OnJobDone()
|
||||||
|
: void console.error("unknown message from worker '" + b + "'");
|
||||||
|
}
|
||||||
|
_OnJobDone() {
|
||||||
|
(this._isBusy = !1), this.MaybeStartNextJob();
|
||||||
|
}
|
||||||
|
MaybeStartNextJob() {
|
||||||
|
if (!this._isBusy && this._isReady) {
|
||||||
|
const a = this._FindAvailableJob();
|
||||||
|
if (-1 !== a) {
|
||||||
|
const b = self.jobQueue[a],
|
||||||
|
c = b['isBroadcast'];
|
||||||
|
c
|
||||||
|
? ((b['doneFlags'][this._number] = !0),
|
||||||
|
b['doneFlags'].every((a) => a) && self.jobQueue.splice(a, 1))
|
||||||
|
: self.jobQueue.splice(a, 1),
|
||||||
|
this.SendJob(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_FindAvailableJob() {
|
||||||
|
for (let a = 0, b = self.jobQueue.length; a < b; ++a) {
|
||||||
|
const b = self.jobQueue[a];
|
||||||
|
if (
|
||||||
|
!b['isBroadcast'] ||
|
||||||
|
(this._number < b['doneFlags'].length && !b['doneFlags'][this._number])
|
||||||
|
)
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
TestMessageChannel() {
|
||||||
|
this._port.postMessage({ type: '_testMessageChannel' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let number = 0;
|
||||||
|
function AddJobWorker(a) {
|
||||||
|
const b = new JobWorker(a, number++);
|
||||||
|
self.jobWorkers.push(b);
|
||||||
|
for (const [c, d] of self.sentBlobs) b.SendBlob(c, d);
|
||||||
|
for (const [c, d] of self.sentBuffers) b.SendBuffer(c, d);
|
||||||
|
for (const c of self.importedScripts) b.ImportScripts(c);
|
||||||
|
for (const c of self.lastBroadcasts.values()) b._InitBroadcast(c);
|
||||||
|
b.SendReady();
|
||||||
|
}
|
||||||
|
function CancelJob(a) {
|
||||||
|
for (let b = 0, c = self.jobQueue.length; b < c; ++b)
|
||||||
|
if (self.jobQueue[b].jobId === a) return void self.jobQueue.splice(b, 1);
|
||||||
|
}
|
||||||
|
self.addEventListener('message', (a) => {
|
||||||
|
const b = a.data,
|
||||||
|
c = b['type'];
|
||||||
|
'_init' === c
|
||||||
|
? ((self.inputPort = b['in-port']), (self.inputPort.onmessage = OnInputPortMessage))
|
||||||
|
: '_addJobWorker' === c && AddJobWorker(b['port']);
|
||||||
|
});
|
||||||
|
function OnInputPortMessage(a) {
|
||||||
|
const b = a.data,
|
||||||
|
c = b['type'];
|
||||||
|
if ('_cancel' === c) return void CancelJob(b.jobId);
|
||||||
|
if ('_import_scripts' === c) {
|
||||||
|
const a = b['scripts'];
|
||||||
|
for (const b of self.jobWorkers) b.ImportScripts(a);
|
||||||
|
return void self.importedScripts.push(a);
|
||||||
|
}
|
||||||
|
if ('_send_blob' === c) {
|
||||||
|
const a = b['blob'],
|
||||||
|
c = b['id'];
|
||||||
|
for (const b of self.jobWorkers) b.SendBlob(a, c);
|
||||||
|
return void self.sentBlobs.push([a, c]);
|
||||||
|
}
|
||||||
|
if ('_send_buffer' === c) {
|
||||||
|
const a = b['buffer'],
|
||||||
|
c = b['id'];
|
||||||
|
for (const b of self.jobWorkers) b.SendBuffer(a, c);
|
||||||
|
return void self.sentBuffers.push([a, c]);
|
||||||
|
}
|
||||||
|
if ('_no_more_workers' === c)
|
||||||
|
return (
|
||||||
|
(self.sentBlobs.length = 0),
|
||||||
|
(self.sentBuffers.length = 0),
|
||||||
|
(self.importedScripts.length = 0),
|
||||||
|
void self.lastBroadcasts.clear()
|
||||||
|
);
|
||||||
|
if ('_testMessageChannel' === c) return void self.jobWorkers[0].TestMessageChannel();
|
||||||
|
self.jobQueue.push(b),
|
||||||
|
b['isBroadcast'] &&
|
||||||
|
((b['doneFlags'] = Array(self.jobWorkers.length).fill(!1)),
|
||||||
|
(b['transferables'] = []),
|
||||||
|
self.lastBroadcasts.set(b['type'], b));
|
||||||
|
for (const b of self.jobWorkers) b.MaybeStartNextJob();
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
'use strict';
|
||||||
|
(self.dispatchPort = null),
|
||||||
|
(self.outputPort = null),
|
||||||
|
(self.workerNumber = -1),
|
||||||
|
(self.activeJobId = null),
|
||||||
|
(self.sentBlobs = new Map()),
|
||||||
|
(self.sentBuffers = new Map()),
|
||||||
|
(self.JobHandlers = {});
|
||||||
|
function FlipImageData(a, b, c) {
|
||||||
|
const d = 4 * b,
|
||||||
|
e = new Uint8Array(d),
|
||||||
|
f = a.buffer;
|
||||||
|
for (let g = 0, h = Math.floor(c / 2); g < h; ++g) {
|
||||||
|
const a = c - g - 1,
|
||||||
|
b = new Uint8Array(f, g * d, d),
|
||||||
|
h = new Uint8Array(f, a * d, d);
|
||||||
|
e.set(b), b.set(h), h.set(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function UnpremultiplyImageData(b) {
|
||||||
|
for (let c = 0, a = b.length; c < a; c += 4) {
|
||||||
|
const d = b[c + 3];
|
||||||
|
if (255 === d) continue;
|
||||||
|
const a = 255 / d;
|
||||||
|
(b[c] *= a), (b[c + 1] *= a), (b[c + 2] *= a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(self.JobHandlers['ProcessImageData'] = function (a) {
|
||||||
|
const b = a['buffer'],
|
||||||
|
c = new Uint8Array(b),
|
||||||
|
d = a['width'],
|
||||||
|
e = a['height'];
|
||||||
|
return (
|
||||||
|
a['flipY'] && FlipImageData(c, d, e),
|
||||||
|
a['unpremultiply'] && UnpremultiplyImageData(c),
|
||||||
|
{ result: b, transferables: [b] }
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
self.addEventListener('message', (a) => {
|
||||||
|
const b = a.data,
|
||||||
|
c = b['type'];
|
||||||
|
return 'init' === c
|
||||||
|
? ((self.workerNumber = b['number']),
|
||||||
|
(self.dispatchPort = b['dispatch-port']),
|
||||||
|
(self.dispatchPort.onmessage = OnDispatchWorkerMessage),
|
||||||
|
void (self.outputPort = b['output-port']))
|
||||||
|
: 'terminate' === c
|
||||||
|
? void self.close()
|
||||||
|
: void console.error("unknown message '" + c + "'");
|
||||||
|
});
|
||||||
|
function SendReady() {
|
||||||
|
self.dispatchPort.postMessage({ type: 'ready' }), self.outputPort.postMessage({ type: 'ready' });
|
||||||
|
}
|
||||||
|
function SendError(a, b) {
|
||||||
|
a || self.outputPort.postMessage({ type: 'error', jobId: self.activeJobId, error: b.toString() }),
|
||||||
|
SendDone();
|
||||||
|
}
|
||||||
|
function SendResult(a, b) {
|
||||||
|
if (!a) {
|
||||||
|
const a = b.transferables || [];
|
||||||
|
self.outputPort.postMessage({ type: 'result', jobId: self.activeJobId, result: b.result }, a);
|
||||||
|
}
|
||||||
|
SendDone();
|
||||||
|
}
|
||||||
|
function SendDone() {
|
||||||
|
(self.activeJobId = null), self.dispatchPort.postMessage({ type: 'done' });
|
||||||
|
}
|
||||||
|
function SendProgress(a) {
|
||||||
|
self.outputPort.postMessage({ type: 'progress', jobId: self.activeJobId, progress: a });
|
||||||
|
}
|
||||||
|
function OnDispatchWorkerMessage(a) {
|
||||||
|
const b = a.data,
|
||||||
|
c = b['type'];
|
||||||
|
if ('_import_scripts' === c) return void importScripts(...b['scripts']);
|
||||||
|
if ('_send_blob' === c) return void self.sentBlobs.set(b['id'], b['blob']);
|
||||||
|
if ('_send_buffer' === c) return void self.sentBuffers.set(b['id'], b['buffer']);
|
||||||
|
if ('_testMessageChannel' === c)
|
||||||
|
return void self.outputPort.postMessage({ type: '_testMessageChannelOk' });
|
||||||
|
if ('_ready' === c) return void SendReady();
|
||||||
|
const d = b['jobId'],
|
||||||
|
f = b['isBroadcast'],
|
||||||
|
e = b['params'];
|
||||||
|
let g;
|
||||||
|
if (((self.activeJobId = d), !self.JobHandlers.hasOwnProperty(c)))
|
||||||
|
return void console.error(`no handler for message type '${c}'`);
|
||||||
|
try {
|
||||||
|
g = self.JobHandlers[c](e);
|
||||||
|
} catch (a) {
|
||||||
|
return void SendError(f, 'Exception in job handler: ' + a);
|
||||||
|
}
|
||||||
|
g && g.then
|
||||||
|
? g.then((a) => SendResult(f, a)).catch((a) => SendError(f, 'Rejection in job handler: ' + a))
|
||||||
|
: SendResult(f, g);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
'use strict';
|
||||||
|
{
|
||||||
|
window.OfflineClientInfo = new (class {
|
||||||
|
constructor() {
|
||||||
|
if (
|
||||||
|
((this._broadcastChannel =
|
||||||
|
'undefined' == typeof BroadcastChannel ? null : new BroadcastChannel('offline')),
|
||||||
|
(this._queuedMessages = []),
|
||||||
|
(this._onMessageCallback = null),
|
||||||
|
this._broadcastChannel)
|
||||||
|
) {
|
||||||
|
var a = this;
|
||||||
|
this._broadcastChannel.onmessage = function (b) {
|
||||||
|
a._OnBroadcastChannelMessage(b);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_OnBroadcastChannelMessage(a) {
|
||||||
|
return this._onMessageCallback
|
||||||
|
? void this._onMessageCallback(a)
|
||||||
|
: void this._queuedMessages.push(a);
|
||||||
|
}
|
||||||
|
SetMessageCallback(a) {
|
||||||
|
this._onMessageCallback = a;
|
||||||
|
for (let b of this._queuedMessages) this._onMessageCallback(b);
|
||||||
|
this._queuedMessages.length = 0;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
'use strict';
|
||||||
|
window.C3_RegisterSW = async function () {
|
||||||
|
if (navigator.serviceWorker)
|
||||||
|
try {
|
||||||
|
const a = await navigator.serviceWorker.register('sw.js', { scope: './' });
|
||||||
|
console.info('Registered service worker on ' + a.scope);
|
||||||
|
} catch (a) {
|
||||||
|
console.warn('Failed to register service worker: ', a);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
'use strict';
|
||||||
|
(function () {
|
||||||
|
var a = !!document.querySelector('script[src*="kaspersky"]'),
|
||||||
|
b = document.createElement('canvas'),
|
||||||
|
c = !!(b.getContext('webgl') || b.getContext('experimental-webgl')),
|
||||||
|
d = [];
|
||||||
|
if (
|
||||||
|
(c || d.push('WebGL'),
|
||||||
|
'undefined' == typeof WebAssembly && d.push('WebAssembly'),
|
||||||
|
0 === d.length && !a)
|
||||||
|
)
|
||||||
|
window['C3_IsSupported'] = !0;
|
||||||
|
else {
|
||||||
|
var e = document.createElement('div');
|
||||||
|
(e.id = 'notSupportedWrap'), document.body.appendChild(e);
|
||||||
|
var f = document.createElement('h2');
|
||||||
|
(f.id = 'notSupportedTitle'),
|
||||||
|
(f.textContent = a
|
||||||
|
? 'Kaspersky Internet Security broke this export'
|
||||||
|
: 'Software update needed'),
|
||||||
|
e.appendChild(f);
|
||||||
|
var g = document.createElement('p');
|
||||||
|
g.className = 'notSupportedMessage';
|
||||||
|
var h = "This content is not supported because your device's software is out-of-date. ",
|
||||||
|
i = navigator.userAgent;
|
||||||
|
/android/i.test(i)
|
||||||
|
? (h +=
|
||||||
|
'<br><br>On Android, fix this by making sure the <a href="https://play.google.com/store/apps/details?id=com.google.android.webview">Android System Webview</a> app has updates enabled and is up-to-date.')
|
||||||
|
: /iphone|ipad|ipod/i.test(i)
|
||||||
|
? (h +=
|
||||||
|
"<br><br>Note: the <strong>iOS simulator</strong> is not currently supported due to an <a href='https://bugs.webkit.org/show_bug.cgi?id=191064'>Apple bug</a>. If you are using the simulator, try testing on a real device instead.")
|
||||||
|
: (/msie/i.test(i) || /trident/i.test(i)) && !/edge\//i.test(i)
|
||||||
|
? (h +=
|
||||||
|
"<br><br>Note: <strong>Internet Explorer</strong> is not supported. Try using <a href='https://www.google.com/chrome'>Chrome</a> or <a href='https://www.mozilla.org/firefox'>Firefox</a> instead.")
|
||||||
|
: a
|
||||||
|
? (h =
|
||||||
|
'It appears a script was added to this export by Kaspersky software. This prevents the exported project from working. Try disabling Kaspersky and exporting again.')
|
||||||
|
: (h +=
|
||||||
|
'Try installing any available software updates. Alternatively try on a different device.'),
|
||||||
|
(h +=
|
||||||
|
'<br><br><em>Missing features: ' +
|
||||||
|
d.join(', ') +
|
||||||
|
'<br>User agent: ' +
|
||||||
|
navigator.userAgent +
|
||||||
|
'</em>'),
|
||||||
|
(g.innerHTML = h),
|
||||||
|
e.appendChild(g);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,41 @@
|
|||||||
|
html,
|
||||||
|
body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
background: #000000;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
canvas {
|
||||||
|
touch-action: none;
|
||||||
|
touch-action-delay: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#notSupportedWrap {
|
||||||
|
margin: 2em auto 1em auto;
|
||||||
|
width: 75%;
|
||||||
|
max-width: 45em;
|
||||||
|
border: 2px solid #aaa;
|
||||||
|
border-radius: 1em;
|
||||||
|
padding: 2em;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
font-family: 'Segoe UI', Frutiger, 'Frutiger Linotype', 'Dejavu Sans', 'Helvetica Neue', Arial,
|
||||||
|
sans-serif;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#notSupportedTitle {
|
||||||
|
font-size: 1.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notSupportedMessage {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notSupportedMessage em {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
'use strict';
|
||||||
|
const OFFLINE_DATA_FILE = 'offline.json',
|
||||||
|
CACHE_NAME_PREFIX = 'c3offline',
|
||||||
|
BROADCASTCHANNEL_NAME = 'offline',
|
||||||
|
CONSOLE_PREFIX = '[SW] ',
|
||||||
|
LAZYLOAD_KEYNAME = '',
|
||||||
|
broadcastChannel =
|
||||||
|
'undefined' == typeof BroadcastChannel ? null : new BroadcastChannel('offline');
|
||||||
|
function PostBroadcastMessage(a) {
|
||||||
|
broadcastChannel && setTimeout(() => broadcastChannel.postMessage(a), 3e3);
|
||||||
|
}
|
||||||
|
function Broadcast(a) {
|
||||||
|
PostBroadcastMessage({ type: a });
|
||||||
|
}
|
||||||
|
function BroadcastDownloadingUpdate(a) {
|
||||||
|
PostBroadcastMessage({ type: 'downloading-update', version: a });
|
||||||
|
}
|
||||||
|
function BroadcastUpdateReady(a) {
|
||||||
|
PostBroadcastMessage({ type: 'update-ready', version: a });
|
||||||
|
}
|
||||||
|
function IsUrlInLazyLoadList(a, b) {
|
||||||
|
if (!b) return !1;
|
||||||
|
try {
|
||||||
|
for (const c of b) if (new RegExp(c).test(a)) return !0;
|
||||||
|
} catch (a) {
|
||||||
|
console.error('[SW] Error matching in lazy-load list: ', a);
|
||||||
|
}
|
||||||
|
return !1;
|
||||||
|
}
|
||||||
|
function WriteLazyLoadListToStorage(a) {
|
||||||
|
return 'undefined' == typeof localforage
|
||||||
|
? Promise.resolve()
|
||||||
|
: localforage.setItem(LAZYLOAD_KEYNAME, a);
|
||||||
|
}
|
||||||
|
function ReadLazyLoadListFromStorage() {
|
||||||
|
return 'undefined' == typeof localforage
|
||||||
|
? Promise.resolve([])
|
||||||
|
: localforage.getItem(LAZYLOAD_KEYNAME);
|
||||||
|
}
|
||||||
|
function GetCacheBaseName() {
|
||||||
|
return 'c3offline-' + self.registration.scope;
|
||||||
|
}
|
||||||
|
function GetCacheVersionName(a) {
|
||||||
|
return GetCacheBaseName() + '-v' + a;
|
||||||
|
}
|
||||||
|
async function GetAvailableCacheNames() {
|
||||||
|
const a = await caches.keys(),
|
||||||
|
b = GetCacheBaseName();
|
||||||
|
return a.filter((a) => a.startsWith(b));
|
||||||
|
}
|
||||||
|
async function IsUpdatePending() {
|
||||||
|
const a = await GetAvailableCacheNames();
|
||||||
|
return 2 <= a.length;
|
||||||
|
}
|
||||||
|
async function GetMainPageUrl() {
|
||||||
|
const a = await clients.matchAll({ includeUncontrolled: !0, type: 'window' });
|
||||||
|
for (const b of a) {
|
||||||
|
let a = b.url;
|
||||||
|
if (
|
||||||
|
(a.startsWith(self.registration.scope) && (a = a.substring(self.registration.scope.length)),
|
||||||
|
a && '/' !== a)
|
||||||
|
)
|
||||||
|
return a.startsWith('?') && (a = '/' + a), a;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
function fetchWithBypass(a, b) {
|
||||||
|
return (
|
||||||
|
'string' == typeof a && (a = new Request(a)),
|
||||||
|
b
|
||||||
|
? fetch(a.url, {
|
||||||
|
headers: a.headers,
|
||||||
|
mode: a.mode,
|
||||||
|
credentials: a.credentials,
|
||||||
|
redirect: a.redirect,
|
||||||
|
cache: 'no-store'
|
||||||
|
})
|
||||||
|
: fetch(a)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
async function CreateCacheFromFileList(a, b, c) {
|
||||||
|
const d = await Promise.all(b.map((a) => fetchWithBypass(a, c)));
|
||||||
|
let e = !0;
|
||||||
|
for (const f of d)
|
||||||
|
f.ok ||
|
||||||
|
((e = !1),
|
||||||
|
console.error("[SW] Error fetching '" + f.url + "' (" + f.status + ' ' + f.statusText + ')'));
|
||||||
|
if (!e) throw new Error('not all resources were fetched successfully');
|
||||||
|
const f = await caches.open(a);
|
||||||
|
try {
|
||||||
|
return await Promise.all(d.map((a, c) => f.put(b[c], a)));
|
||||||
|
} catch (b) {
|
||||||
|
throw (console.error('[SW] Error writing cache entries: ', b), caches.delete(a), b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function UpdateCheck(a) {
|
||||||
|
try {
|
||||||
|
const b = await fetchWithBypass(OFFLINE_DATA_FILE, !0);
|
||||||
|
if (!b.ok) throw new Error('offline.json responded with ' + b.status + ' ' + b.statusText);
|
||||||
|
const c = await b.json(),
|
||||||
|
d = c.version,
|
||||||
|
e = c.fileList,
|
||||||
|
f = c.lazyLoad,
|
||||||
|
g = GetCacheVersionName(d),
|
||||||
|
h = await caches.has(g);
|
||||||
|
if (h) {
|
||||||
|
const a = await IsUpdatePending();
|
||||||
|
return void (a
|
||||||
|
? (console.log('[SW] Update pending'), Broadcast('update-pending'))
|
||||||
|
: (console.log('[SW] Up to date'), Broadcast('up-to-date')));
|
||||||
|
}
|
||||||
|
const i = await GetMainPageUrl();
|
||||||
|
e.unshift('./'),
|
||||||
|
i && -1 === e.indexOf(i) && e.unshift(i),
|
||||||
|
console.log('[SW] Caching ' + e.length + ' files for offline use'),
|
||||||
|
a ? Broadcast('downloading') : BroadcastDownloadingUpdate(d),
|
||||||
|
f && (await WriteLazyLoadListToStorage(f)),
|
||||||
|
await CreateCacheFromFileList(g, e, !a);
|
||||||
|
const j = await IsUpdatePending();
|
||||||
|
j
|
||||||
|
? (console.log('[SW] All resources saved, update ready'), BroadcastUpdateReady(d))
|
||||||
|
: (console.log('[SW] All resources saved, offline support ready'),
|
||||||
|
Broadcast('offline-ready'));
|
||||||
|
} catch (a) {
|
||||||
|
console.warn('[SW] Update check failed: ', a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.addEventListener('install', (a) => {
|
||||||
|
a.waitUntil(UpdateCheck(!0).catch(() => null));
|
||||||
|
});
|
||||||
|
async function GetCacheNameToUse(a, b) {
|
||||||
|
if (1 === a.length || !b) return a[0];
|
||||||
|
const c = await clients.matchAll();
|
||||||
|
if (1 < c.length) return a[0];
|
||||||
|
const d = a[a.length - 1];
|
||||||
|
return (
|
||||||
|
console.log('[SW] Updating to new version'),
|
||||||
|
await Promise.all(a.slice(0, -1).map((a) => caches.delete(a))),
|
||||||
|
d
|
||||||
|
);
|
||||||
|
}
|
||||||
|
async function HandleFetch(a, b) {
|
||||||
|
const c = await GetAvailableCacheNames();
|
||||||
|
if (!c.length) return fetch(a.request);
|
||||||
|
const d = await GetCacheNameToUse(c, b),
|
||||||
|
e = await caches.open(d),
|
||||||
|
f = await e.match(a.request);
|
||||||
|
if (f) return f;
|
||||||
|
const g = await Promise.all([fetch(a.request), ReadLazyLoadListFromStorage()]),
|
||||||
|
h = g[0],
|
||||||
|
i = g[1];
|
||||||
|
if (IsUrlInLazyLoadList(a.request.url, i))
|
||||||
|
try {
|
||||||
|
await e.put(a.request, h.clone());
|
||||||
|
} catch (b) {
|
||||||
|
console.warn("[SW] Error caching '" + a.request.url + "': ", b);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
self.addEventListener('fetch', (a) => {
|
||||||
|
if (new URL(a.request.url).origin === location.origin) {
|
||||||
|
const b = 'navigate' === a.request.mode,
|
||||||
|
c = HandleFetch(a, b);
|
||||||
|
b && a.waitUntil(c.then(() => UpdateCheck(!1))), a.respondWith(c);
|
||||||
|
}
|
||||||
|
});
|
||||||