more ui tweaks:
- make index scrollable - don't show 'current archive' until successfully loaded - begin embed view for wr-replay - cleanup pageutils
This commit is contained in:
Vendored
+47
-14
File diff suppressed because one or more lines are too long
+80
-7
@@ -40,6 +40,7 @@ class AppMain extends LitElement
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.sourceUrl = null;
|
this.sourceUrl = null;
|
||||||
|
this.sourceLoaded = false;
|
||||||
this.showTerms = false;
|
this.showTerms = false;
|
||||||
this.pageParams = {};
|
this.pageParams = {};
|
||||||
}
|
}
|
||||||
@@ -49,7 +50,8 @@ class AppMain extends LitElement
|
|||||||
pageParams: { type: Object },
|
pageParams: { type: Object },
|
||||||
sourceUrl: { type: String },
|
sourceUrl: { type: String },
|
||||||
navMenuShown: { type: Boolean },
|
navMenuShown: { type: Boolean },
|
||||||
showTerms: { type: Boolean }
|
showTerms: { type: Boolean },
|
||||||
|
sourceLoaded: { type: Boolean }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +85,7 @@ class AppMain extends LitElement
|
|||||||
</div>
|
</div>
|
||||||
<div class="navbar-menu ${this.navMenuShown ? 'is-active' : ''}">
|
<div class="navbar-menu ${this.navMenuShown ? 'is-active' : ''}">
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
${this.sourceUrl ?
|
${this.sourceUrl && this.sourceLoaded ?
|
||||||
html`
|
html`
|
||||||
<div class="navbar-item">Current Archive: <b>${this.sourceUrl}</b>
|
<div class="navbar-item">Current Archive: <b>${this.sourceUrl}</b>
|
||||||
</div>` : html``}
|
</div>` : html``}
|
||||||
@@ -105,6 +107,7 @@ class AppMain extends LitElement
|
|||||||
return html`
|
return html`
|
||||||
<wr-coll .loadInfo="${this.loadInfo}"
|
<wr-coll .loadInfo="${this.loadInfo}"
|
||||||
sourceUrl="${this.sourceUrl}"
|
sourceUrl="${this.sourceUrl}"
|
||||||
|
@replay-favicons=${this.onFavIcons}
|
||||||
@coll-loaded=${this.onCollLoaded}></wr-coll>
|
@coll-loaded=${this.onCollLoaded}></wr-coll>
|
||||||
`;
|
`;
|
||||||
} else if (this.showTerms) {
|
} else if (this.showTerms) {
|
||||||
@@ -143,6 +146,28 @@ class AppMain extends LitElement
|
|||||||
this.initRoute();
|
this.initRoute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updated(changedProperties) {
|
||||||
|
if (changedProperties.has("sourceUrl")) {
|
||||||
|
this.sourceLoaded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFavIcons(event) {
|
||||||
|
const head = document.querySelector('head');
|
||||||
|
const oldLinks = document.querySelectorAll("link[rel*='icon']");
|
||||||
|
|
||||||
|
for (const link of oldLinks) {
|
||||||
|
head.removeChild(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const icon of event.detail.icons) {
|
||||||
|
const link = document.createElement('link');
|
||||||
|
link.rel = icon.rel;
|
||||||
|
link.href = icon.href;
|
||||||
|
head.appendChild(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onNavMenu() {
|
onNavMenu() {
|
||||||
this.navMenuShown = !this.navMenuShown;
|
this.navMenuShown = !this.navMenuShown;
|
||||||
}
|
}
|
||||||
@@ -187,6 +212,11 @@ class AppMain extends LitElement
|
|||||||
|
|
||||||
onCollLoaded(event) {
|
onCollLoaded(event) {
|
||||||
this.loadInfo = null;
|
this.loadInfo = null;
|
||||||
|
if (event.detail.alreadyLoaded) {
|
||||||
|
this.sourceLoaded = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.initRoute();
|
this.initRoute();
|
||||||
|
|
||||||
if (event.detail.sourceUrl !== this.sourceUrl) {
|
if (event.detail.sourceUrl !== this.sourceUrl) {
|
||||||
@@ -352,6 +382,10 @@ class WrLoader extends LitElement
|
|||||||
font-size: calc(1.5rem / 1.5);
|
font-size: calc(1.5rem / 1.5);
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
}
|
}
|
||||||
|
.error {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +419,7 @@ class WrLoader extends LitElement
|
|||||||
style="max-width: 400px"/>`;
|
style="max-width: 400px"/>`;
|
||||||
|
|
||||||
case "errored":
|
case "errored":
|
||||||
return html`<div class="has-text-danger">${this.error}</div>`;
|
return html`<div class="error has-text-danger">${this.error}</div>`;
|
||||||
|
|
||||||
case "waiting":
|
case "waiting":
|
||||||
default:
|
default:
|
||||||
@@ -502,6 +536,12 @@ class WrIndex extends LitElement
|
|||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
.coll-list {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
nav.main-scroll {
|
||||||
|
max-height: calc(100vh - 279px);
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,9 +585,10 @@ class WrIndex extends LitElement
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="container">
|
<section class="container">
|
||||||
<nav class="panel">
|
<nav class="panel main-scroll">
|
||||||
<p class="panel-heading">Loaded Archives</p>
|
<p class="panel-heading">Loaded Archives</p>
|
||||||
${this.colls.map((coll, i) => html`
|
<div class="coll-list">
|
||||||
|
${this.colls.length ? this.colls.map((coll, i) => html`
|
||||||
<div class="panel-block">
|
<div class="panel-block">
|
||||||
<div class="level" style="width: 100%">
|
<div class="level" style="width: 100%">
|
||||||
<div class="level-left">
|
<div class="level-left">
|
||||||
@@ -564,7 +605,12 @@ class WrIndex extends LitElement
|
|||||||
<button class="button is-loading is-static"></button>`}
|
<button class="button is-loading is-static"></button>`}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`)}
|
`) : html`
|
||||||
|
<div class="panel-block extra-padding">
|
||||||
|
<i>No Archices so far! Archives loaded in the section above will appear here.</i>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</section>
|
</section>
|
||||||
`;
|
`;
|
||||||
@@ -682,6 +728,7 @@ class WrColl extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.hasCurated = (this.collInfo.lists && this.collInfo.lists.length);
|
this.hasCurated = (this.collInfo.lists && this.collInfo.lists.length);
|
||||||
|
this.dispatchEvent(new CustomEvent("coll-loaded", {detail: {alreadyLoaded: true}}));
|
||||||
|
|
||||||
const hash = window.location.hash;
|
const hash = window.location.hash;
|
||||||
if (hash) {
|
if (hash) {
|
||||||
@@ -1300,6 +1347,7 @@ class WrReplayPage extends LitElement
|
|||||||
this.replayTS = "";
|
this.replayTS = "";
|
||||||
this.url = "";
|
this.url = "";
|
||||||
this.ts = "";
|
this.ts = "";
|
||||||
|
this.title = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -1313,6 +1361,7 @@ class WrReplayPage extends LitElement
|
|||||||
// actual replay url
|
// actual replay url
|
||||||
replayUrl: { type: String },
|
replayUrl: { type: String },
|
||||||
replayTS: { type: String },
|
replayTS: { type: String },
|
||||||
|
title: { type: String },
|
||||||
|
|
||||||
iframeUrl: { type: String },
|
iframeUrl: { type: String },
|
||||||
isLoading: { type: Boolean }
|
isLoading: { type: Boolean }
|
||||||
@@ -1358,7 +1407,15 @@ class WrReplayPage extends LitElement
|
|||||||
if (event.data.wb_type === "load" || event.data.wb_type === "replace-url") {
|
if (event.data.wb_type === "load" || event.data.wb_type === "replace-url") {
|
||||||
this.replayTS = event.data.ts;
|
this.replayTS = event.data.ts;
|
||||||
this.replayUrl = event.data.url;
|
this.replayUrl = event.data.url;
|
||||||
|
this.title = event.data.title || this.title;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
|
||||||
|
if (event.data.icons) {
|
||||||
|
const icons = event.data.icons;
|
||||||
|
this.dispatchEvent(new CustomEvent("replay-favicons", {bubbles: true, composed: true, detail: {icons}}));
|
||||||
|
}
|
||||||
|
} else if (event.data.wb_type === "title") {
|
||||||
|
this.title = event.data.title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1403,6 +1460,15 @@ class WrReplayPage extends LitElement
|
|||||||
border-bottom: solid .1rem #97989A;
|
border-bottom: solid .1rem #97989A;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.embed-bar {
|
||||||
|
padding: 0.25em;
|
||||||
|
max-width: none;
|
||||||
|
border-bottom: solid .1rem #97989A;
|
||||||
|
background-color: aliceblue;
|
||||||
|
text-align: center;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
input#url {
|
input#url {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
@@ -1424,6 +1490,7 @@ class WrReplayPage extends LitElement
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
|
${!this.embed ? html`
|
||||||
<div class="container replay-bar">
|
<div class="container replay-bar">
|
||||||
<form @submit="${this.onSubmit}">
|
<form @submit="${this.onSubmit}">
|
||||||
<div class="field has-addons">
|
<div class="field has-addons">
|
||||||
@@ -1440,7 +1507,13 @@ class WrReplayPage extends LitElement
|
|||||||
<p id="datetime" class="control is-hidden-mobile">${tsToDate(this.replayTS).toLocaleString()}</p>
|
<p id="datetime" class="control is-hidden-mobile">${tsToDate(this.replayTS).toLocaleString()}</p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</div>` : html`
|
||||||
|
|
||||||
|
<div class="container embed-bar">
|
||||||
|
<p class="is-size-5">${this.title}</p>
|
||||||
</div>
|
</div>
|
||||||
|
`}
|
||||||
|
|
||||||
${this.iframeUrl ? html`
|
${this.iframeUrl ? html`
|
||||||
<iframe @message="${this.onReplayMessage}"
|
<iframe @message="${this.onReplayMessage}"
|
||||||
src="${this.iframeUrl}"></iframe>
|
src="${this.iframeUrl}"></iframe>
|
||||||
@@ -1626,7 +1699,7 @@ function registerSW(url) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
register(url, {
|
register(url, {
|
||||||
registrationOptions: { scope: '/', otherOptions: 'foo' },
|
registrationOptions: { scope: '/' },
|
||||||
ready (registration) {
|
ready (registration) {
|
||||||
console.log('Service worker is active.');
|
console.log('Service worker is active.');
|
||||||
resolve();
|
resolve();
|
||||||
|
|||||||
+1
-84
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
async function digestMessage(message, hashtype) {
|
async function digestMessage(message, hashtype) {
|
||||||
const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array
|
const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array
|
||||||
const hashBuffer = await crypto.subtle.digest(hashtype, msgUint8); // hash the message
|
const hashBuffer = await crypto.subtle.digest(hashtype, msgUint8); // hash the message
|
||||||
@@ -7,88 +6,6 @@ async function digestMessage(message, hashtype) {
|
|||||||
return hashHex;
|
return hashHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForReady() {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
window.addEventListener("load", () => {
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (document.readyState === 'complete') {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function initSW(relUrl = 'sw.js?replayPrefix=wabac&stats=true', path) {
|
|
||||||
const loc = window.location;
|
|
||||||
|
|
||||||
console.log(`Register SW: ${relUrl}`);
|
|
||||||
|
|
||||||
if (!navigator.serviceWorker) {
|
|
||||||
let msg = null;
|
|
||||||
|
|
||||||
if (loc.protocol === "http:") {
|
|
||||||
msg = 'Service workers only supported when loading via https://, but this site loaded from: ' + loc.origin;
|
|
||||||
} else {
|
|
||||||
msg = 'Sorry, Service workers are not supported in this browser'
|
|
||||||
}
|
|
||||||
return Promise.reject(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register SW in current path scope (if not '/' use curr directory)
|
|
||||||
if (!path) {
|
|
||||||
path = loc.origin + loc.pathname;
|
|
||||||
} else {
|
|
||||||
path = new URL(path, window.location.href).href;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!path.endsWith("/")) {
|
|
||||||
path = path.slice(0, path.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = new URL(relUrl, path);
|
|
||||||
|
|
||||||
if (navigator.serviceWorker.controller && navigator.serviceWorker.controller.scriptURL === url) {
|
|
||||||
return Promise.resolve(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
let done = false;
|
|
||||||
let resolve, reject;
|
|
||||||
|
|
||||||
const pr = new Promise((res, rej) => {
|
|
||||||
resolve = (e) => { done = true; res(e); };
|
|
||||||
reject = (e) => { done = true; rej(e); };
|
|
||||||
});
|
|
||||||
|
|
||||||
window.fetch(url, { "mode": "cors" }).then(resp => {
|
|
||||||
if (!resp.url.startsWith(path)) {
|
|
||||||
reject("Service Worker in wrong scope!")
|
|
||||||
}
|
|
||||||
return resp.url;
|
|
||||||
}).then((swUrl) => {
|
|
||||||
navigator.serviceWorker.addEventListener('error', e => reject(null));
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!done) {
|
|
||||||
reject('Service Worker is not available');
|
|
||||||
}
|
|
||||||
}, 30000);
|
|
||||||
|
|
||||||
return navigator.serviceWorker.register(swUrl, { scope: path });
|
|
||||||
}).then((registration) => {
|
|
||||||
console.log('Service worker registration succeeded:', registration);
|
|
||||||
if (navigator.serviceWorker.controller) {
|
|
||||||
resolve(true);
|
|
||||||
}
|
|
||||||
navigator.serviceWorker.addEventListener('controllerchange', e => resolve(true));
|
|
||||||
}).catch((error) => {
|
|
||||||
console.log('Service worker registration failed:', error);
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
return pr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tsToDate(ts) {
|
function tsToDate(ts) {
|
||||||
if (!ts) {
|
if (!ts) {
|
||||||
return "";
|
return "";
|
||||||
@@ -115,4 +32,4 @@ function getTS(iso) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export { initSW, waitForReady, digestMessage, tsToDate, getTS };
|
export { digestMessage, tsToDate, getTS };
|
||||||
|
|||||||
Reference in New Issue
Block a user