IPFS Support + Loading Improvements (Better local file handling) + Streamlined Collection View (#25)

* support ipfs:// urls!
misc: better error message for loading from http://
tabs: don't render pages/story/urls if hidden

* ipfs work: remove ww only use sw

* electron + ipfs: add ipfs support to electron app, using ipfs-core
- route ipfs requests to files proxy with 'ipfs=' query param

* file loading:
- add support for new Chrome native file system api with file handles, which allows persistent access to files vial file handles
- if window.showOpenFilePicker() is available use that, include file handle in load message
- support asking permissions for file handles, using similar workflow as google drive auth
- attempt to ask for file permission directly, show auth button if fails (user gestured required)
- replace auth modal with iframe replacement insert to ask for auth for google drive and local file

* ui overhaul for 1.3.0 / condense collection view:
- don't show navbar in collection view
- add logo to back to home page to location bar
- condense location bar buttons
- convert terms to general about dialog, available from collection context menu
- add info tab to collection view in place of drop-down info
- make <wr-coll-info> component, used in both collection list and info tab with additional details
- update to wabac.js 2.2.0

* update CHANGES.md
This commit is contained in:
Ilya Kreymer
2020-11-16 18:31:15 -08:00
committed by GitHub
parent e839400017
commit 228e9bdff6
15 changed files with 4533 additions and 614 deletions
+78 -42
View File
@@ -1,5 +1,5 @@
import { LitElement, html, css } from 'lit-element';
import { wrapCss } from './misc';
import { wrapCss, rwpLogo } from './misc';
@@ -17,6 +17,7 @@ class Replay extends LitElement
this.showAuth = false;
this.reauthWait = null;
this.authFileHandle = null;
}
static get properties() {
@@ -36,20 +37,37 @@ class Replay extends LitElement
iframeUrl: { type: String },
showAuth: { type: Boolean },
authFileHandle: { type: Object }
}
}
firstUpdated() {
window.addEventListener("message", (event) => this.onReplayMessage(event));
navigator.serviceWorker.addEventListener("message", async (event) => {
if (event.data.type === "authneeded" && this.collInfo && event.data.coll === this.collInfo.coll) {
if (this.reauthWait) {
await this.reauthWait;
} else {
this.showAuth = true;
}
navigator.serviceWorker.addEventListener("message", (event) => this.handleAuthMessage(event));
}
async handleAuthMessage(event) {
if (event.data.type === "authneeded" && this.collInfo && event.data.coll === this.collInfo.coll) {
if (event.data.fileHandle) {
this.authFileHandle = event.data.fileHandle;
try {
if (await this.authFileHandle.requestPermission({mode: "read"}) === "granted") {
this.showAuth = false;
this.reauthWait = null;
this.refresh();
return;
}
} catch (e) {}
} else {
this.authFileHandle = null;
}
});
if (this.reauthWait) {
await this.reauthWait;
} else {
this.showAuth = true;
}
}
}
doSetIframeUrl() {
@@ -58,9 +76,6 @@ class Replay extends LitElement
updated(changedProperties) {
if (changedProperties.has("sourceUrl") || changedProperties.has("collInfo")) {
this.isAuthable = (this.sourceUrl.startsWith("googledrive://") &&
this.collInfo && this.collInfo.onDemand);
this.reauthWait = null;
}
@@ -70,6 +85,8 @@ class Replay extends LitElement
this.replayUrl = this.url;
this.replayTS = this.ts;
this.showAuth = false;
this.reauthWait = null;
this.doSetIframeUrl();
}
@@ -121,17 +138,28 @@ class Replay extends LitElement
onReAuthed(event) {
this.reauthWait = (async () => {
const headers = event.detail.headers;
const resp = await fetch(`${this.collInfo.apiPrefix}/updateAuth`, {
method: 'POST',
body: JSON.stringify({headers})
});
if (!this.authFileHandle) {
// google drive reauth
const headers = event.detail.headers;
const resp = await fetch(`${this.collInfo.apiPrefix}/updateAuth`, {
method: 'POST',
body: JSON.stringify({headers})
});
} else {
if (await this.authFileHandle.requestPermission({mode: "read"}) !== "granted") {
this.reauthWait = null;
return;
}
this.authFileHandle = null;
}
if (this.showAuth) {
this.refresh();
this.showAuth = false;
this.reauthWait = null;
}
this.refresh();
})();
}
@@ -191,18 +219,24 @@ class Replay extends LitElement
.intro-panel .panel-heading {
font-size: 1.0em;
display: inline-block;
}
#wrlogo {
vertical-align: middle;
}
.intro-panel .panel-block {
padding: 1.0em;
flex-direction: column;
line-height: 2.5em;
}
div.intro-panel.panel {
min-width: 40%;
display: flex;
flex-direction: column;
margin: auto;
margin: 3em auto;
}
`);
}
@@ -214,37 +248,39 @@ class Replay extends LitElement
<h1 id="replay-heading" class="is-sr-only">${title}</h1>
${this.iframeUrl ? html`
<iframe @message="${this.onReplayMessage}" allow="autoplay 'self'; fullscreen" allowfullscreen
src="${this.iframeUrl}" title="${title}"></iframe>
` : html`
${!this.iframeUrl ? html`
<div class="panel intro-panel">
<p class="panel-heading">Replay Web Page</p>
<div class="panel-block">
<p>Enter a URL above to replay it from the web archive!</p>
<p>(Or, check out <a href="#view=pages">Pages</a> or <a href="#view=resources">URLs</a> to explore the contents of this archive.)</p>
</div>
</div>
`}
</div>` : html`
${this.isAuthable ? html`
<div class="modal ${this.showAuth ? 'is-active' : ''}">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Auth Needed</p>
<button class="delete" aria-label="close"></button>
</header>
<section class="modal-card-body">
<div class="container has-text-centered">
<wr-gdrive .sourceUrl=${this.sourceUrl} .state="${this.showAuth ? 'trymanual' : 'implicitonly'}" .reauth="${true}" @load-ready=${this.onReAuthed}/>
</div>
</section>
${this.showAuth ? html`
<div class="panel intro-panel">
<p class="panel-heading">
<fa-icon id="wrlogo" size="1.5rem" .svg=${rwpLogo} aria-hidden="true"></fa-icon>
Authorization Needed
</p>
<div class="panel-block">
${this.authFileHandle ? html`
<p>This archive is loaded from a local file: <b>${this.authFileHandle.name}</b></p>
<p>The browser needs to confirm your permission to continue loading from this file.</p>
<button class="button is-warning is-rounded" @click="${this.onReAuthed}">Show Confirmation</button>
` : html`
<wr-gdrive
.sourceUrl=${this.sourceUrl}
.state="${this.showAuth ? 'trymanual' : 'implicitonly'}"
.reauth="${true}
@load-ready=${this.onReAuthed}/>`}
</div>
</div>
</div>
` : ``}
`;
</div>` : html`
<iframe @message="${this.onReplayMessage}" allow="autoplay 'self'; fullscreen" allowfullscreen
src="${this.iframeUrl}" title="${title}"></iframe>
`}
`}`;
}
}