254 lines
9.4 KiB
HTML
254 lines
9.4 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width" />
|
|
<title>blog3000 powered blog</title>
|
|
<base href="/" />
|
|
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
|
|
<link href="css/site.css" rel="stylesheet" />
|
|
<link href="css/github-stylesheet.css" rel="stylesheet" />
|
|
<link href="manifest.json" rel="manifest" />
|
|
</head>
|
|
|
|
|
|
<body>
|
|
<app>Loading page (blazor-app, modern browser required for this to work)...</app>
|
|
|
|
<div id="blazor-error-ui">
|
|
An unhandled error has occurred.
|
|
<a href="" class="reload">Reload</a>
|
|
<a class="dismiss">🗙</a>
|
|
</div>
|
|
<script src="_framework/blazor.webassembly.js"></script>
|
|
<script>navigator.serviceWorker.register('service-worker.js');</script>
|
|
<script>
|
|
window.Network = {
|
|
Init: function (interop) {
|
|
function handler() {
|
|
interop.invokeMethodAsync("Network.StatusChanged", navigator.onLine);
|
|
}
|
|
|
|
window.addEventListener('online', handler);
|
|
window.addEventListener('offline', handler);
|
|
|
|
if (!navigator.onLine) {
|
|
handler(navigator.onLine);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
class MyCacheStorage {
|
|
|
|
// TODO: Improve SetException, pass object instead of string?
|
|
|
|
static async Create(cbObject, cacheId) {
|
|
try {
|
|
let i = new MyCacheStorage();
|
|
i.cacheId = cacheId;
|
|
i.myCache = await caches.open(cacheId);
|
|
window[cacheId] = i;
|
|
if (!await caches.has(cacheId)) {
|
|
//Should not occurr on a healthy system, was probably a red herring during debugging
|
|
/*
|
|
console.warn("Cache NOT " + cacheId + " created, retry in 1000ms");
|
|
setTimeout(() => {
|
|
caches.open(cacheId).then((c) => {
|
|
caches.has(cacheId).then((b) => {
|
|
if (!b) {
|
|
console.warn("Cache NOT " + cacheId + "created, giving up");
|
|
cbObject.invokeMethodAsync("SetResult", false);
|
|
}
|
|
else {
|
|
console.log("Cache: " + cacheId + " created");
|
|
cbObject.invokeMethodAsync("SetResult", true);
|
|
}
|
|
})
|
|
});
|
|
}, 1000);*/
|
|
console.log("Cache" + cacheId + " NOT created");
|
|
cbObject.invokeMethodAsync("SetResult", false);
|
|
}
|
|
else {
|
|
console.log("Cache: " + cacheId + " created");
|
|
cbObject.invokeMethodAsync("SetResult", true);
|
|
}
|
|
}
|
|
catch (e) {
|
|
console.warn(e);
|
|
cbObject.invokeMethodAsync("SetException", "" + e);
|
|
}
|
|
}
|
|
|
|
async CheckCache() {
|
|
if (!await caches.has(this.cacheId)) {
|
|
// Should only occur on cache reset e.g. during debugging!
|
|
console.log("Cache" + this.cacheId + " NOT found, reopening");
|
|
this.myCache = await caches.open(this.cacheId);
|
|
if (!await caches.has(this.cacheId)) {
|
|
console.log("Cache " + this.cacheId + " still NOT found, failing");
|
|
throw new ("Cache " + this.cacheId + " not openable/creatable");
|
|
}
|
|
}
|
|
}
|
|
|
|
async Add(cbObject, url) {
|
|
try {
|
|
await this.CheckCache();
|
|
await this.myCache.add(url);
|
|
//console.log("my-cache added to", url);
|
|
cbObject.invokeMethodAsync("SetResult", true);
|
|
}
|
|
catch (e) {
|
|
console.warn(e);
|
|
cbObject.invokeMethodAsync("SetException", "" + e);
|
|
}
|
|
}
|
|
|
|
async AddAll(cbObject, urls) {
|
|
try {
|
|
if (typeof (urls) === "string") urls = [urls];
|
|
|
|
await this.CheckCache();
|
|
await this.myCache.addAll(urls);
|
|
//console.log("my-cache added all to", urls);
|
|
cbObject.invokeMethodAsync("SetResult", true);
|
|
}
|
|
catch (e) {
|
|
console.warn(e, urls);
|
|
cbObject.invokeMethodAsync("SetException", "" + e);
|
|
}
|
|
}
|
|
|
|
async Delete(cbObject, url) {
|
|
try {
|
|
await this.CheckCache();
|
|
await this.myCache.delete(url);
|
|
//console.log("my-cache added to");
|
|
cbObject.invokeMethodAsync("SetResult", true);
|
|
}
|
|
catch (e) {
|
|
console.warn(e);
|
|
cbObject.invokeMethodAsync("SetException", "" + e);
|
|
}
|
|
}
|
|
|
|
|
|
async MatchAll(cbObject, filter) {
|
|
try {
|
|
// filter does not do contains-match, uri in cache
|
|
// includes host-part etc, therefore built in filtering can't be used
|
|
await this.CheckCache();
|
|
var responses = await this.myCache.matchAll(/*filter*/);
|
|
var matches = [];
|
|
responses.forEach(function (element, index, array) {
|
|
if (element.url.includes(filter)) {
|
|
matches.push(element.url);
|
|
}
|
|
});
|
|
|
|
//console.log(filter, matches);
|
|
cbObject.invokeMethodAsync("SetResult", matches);
|
|
}
|
|
catch (e) {
|
|
console.warn(e);
|
|
cbObject.invokeMethodAsync("SetException", "" + e);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* check if all given "filters" are in cache
|
|
* @param cbObject
|
|
* @param filters
|
|
*/
|
|
async AreCached(cbObject, filters) {
|
|
try {
|
|
if (typeof (filters) === "string") filters = [filters];
|
|
|
|
// filter does not do contains-match, uri in cache
|
|
// includes host-part etc, therefore built in filtering can't be used
|
|
|
|
let res = true;
|
|
await this.CheckCache();
|
|
var responses = await this.myCache.matchAll(/*filter*/);
|
|
if (responses && filters) {
|
|
let match = null;
|
|
filters.forEach(f => {
|
|
responses.forEach(function (element, index, array) {
|
|
if (element.url.includes(f)) {
|
|
match = element.url;
|
|
return;
|
|
}
|
|
});
|
|
if (!match) {
|
|
res = false;
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
|
|
console.log(filters, res);
|
|
cbObject.invokeMethodAsync("SetResult", res);
|
|
}
|
|
catch (e) {
|
|
console.warn(e);
|
|
cbObject.invokeMethodAsync("SetException", "" + e);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
window.MyCacheStorage = MyCacheStorage;
|
|
|
|
|
|
</script>
|
|
|
|
<script>
|
|
/**
|
|
*
|
|
* @param uri
|
|
* @param name optional, only works for same-origin attributes, otherwise server will override
|
|
*/
|
|
window.downloadURI = function (uri, name) {
|
|
console.log("Preparing download of " + uri);
|
|
setTimeout(() => {
|
|
var link = document.createElement("a");
|
|
// If you don't know the name or want to use
|
|
// the webserver default set name = ''
|
|
if (name) {
|
|
link.setAttribute('download', name);
|
|
}
|
|
link.href = uri;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
link.remove();
|
|
}, 1000);
|
|
}
|
|
|
|
|
|
window.scrollElmIntoView = function (element) {
|
|
//console.log("YY", element);
|
|
if (element) {
|
|
var rect = element.getBoundingClientRect();
|
|
|
|
// Scroll only when not in view!
|
|
if (!(
|
|
rect.top >= 0 &&
|
|
rect.left >= 0 &&
|
|
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
|
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
|
)) element.scrollIntoView();
|
|
}
|
|
}
|
|
|
|
window.setTitle = function(txt) {
|
|
document.title = txt;
|
|
}
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|