refactor: split frontend into file per component!

This commit is contained in:
Ilya Kreymer
2020-05-22 23:43:56 -07:00
parent 99b5fe4479
commit e3d5abdbeb
17 changed files with 2760 additions and 2733 deletions
+306
View File
@@ -0,0 +1,306 @@
import { LitElement, html, css } from 'lit-element';
import { wrapCss } from './misc';
import { tsToDate } from './pageutils';
import fasRefresh from '@fortawesome/fontawesome-free/svgs/solid/redo-alt.svg';
import fasFullscreen from '@fortawesome/fontawesome-free/svgs/solid/desktop.svg';
import fasUnfullscreen from '@fortawesome/fontawesome-free/svgs/solid/compress-arrows-alt.svg';
// ===========================================================================
class Replay extends LitElement
{
constructor() {
super();
this.isLoading = false;
this.replayUrl = "";
this.replayTS = "";
this.url = "";
this.ts = "";
this.title = "";
this.showAuth = false;
this.reauthWait = null;
}
static get properties() {
return {
collInfo: {type: Object },
sourceUrl: { type: String },
// external url set by parent
url: { type: String },
ts: { type: String },
// actual replay url
replayUrl: { type: String },
replayTS: { type: String },
title: { type: String },
iframeUrl: { type: String },
isLoading: { type: Boolean },
showAuth: { type: Boolean },
embed: { type: String },
isFullscreen: { type: Boolean }
}
}
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;
}
}
});
this.addEventListener("fullscreenchange", (event) => {
this.isFullscreen = !!document.fullscreenElement;
});
}
onFullscreenToggle() {
if (!this.isFullscreen) {
this.requestFullscreen();
} else {
document.exitFullscreen();
}
}
doSetIframeUrl() {
this.iframeUrl = this.url ? `${this.collInfo.replayPrefix}/${this.ts || ""}mp_/${this.url}` : "";
}
updated(changedProperties) {
if (changedProperties.has("sourceUrl") || changedProperties.has("collInfo")) {
this.isAuthable = (this.sourceUrl.startsWith("googledrive://") &&
this.collInfo && this.collInfo.onDemand);
this.reauthWait = null;
}
if (this.url &&
((this.replayUrl != this.url) || (this.replayTS != this.ts)) &&
(changedProperties.has("url") || changedProperties.has("ts"))) {
this.replayUrl = this.url;
this.replayTS = this.ts;
this.doSetIframeUrl();
}
if (this.iframeUrl && changedProperties.has("iframeUrl")) {
this.isLoading = true;
}
if (this.replayUrl && changedProperties.has("replayUrl")) {
const data = {
url: this.replayUrl,
ts: this.replayTS,
};
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail: {replaceLoc: true, data}}));
}
if (this.embed && window.parent !== window && changedProperties.has("title")) {
window.parent.postMessage({
title: this.title,
url: this.replayUrl,
ts: this.replayTS
}, '*');
}
}
onReplayMessage(event) {
const iframe = this.renderRoot.querySelector("iframe");
if (iframe && event.source === iframe.contentWindow) {
if (event.data.wb_type === "load" || event.data.wb_type === "replace-url") {
this.replayTS = event.data.ts;
this.replayUrl = event.data.url;
this.title = event.data.title || this.title;
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;
}
}
}
onSubmit(event) {
event.preventDefault();
const value = this.renderRoot.querySelector("input").value;
//this.replayUrl = value;
this.url = value;
return false;
}
onRefresh(event, forceReload) {
if (event) {
event.preventDefault();
}
if (this.isLoading && !forceReload) {
return;
}
const iframe = this.renderRoot.querySelector("iframe");
if (iframe) {
this.isLoading = true;
iframe.contentWindow.location.reload();
}
}
static get styles() {
return wrapCss(css`
host: {
display: flex;
}
iframe {
width: 100vw;
#height: calc(100vh - 150px);
height: 100%;
border: 0px;
}
.replay-bar {
padding: 1em;
max-width: none;
border-bottom: solid .1rem #97989A;
width: 100%;
background-color: white;
}
.embed-bar {
padding: 0.25em;
max-width: none;
border-bottom: solid .1rem #97989A;
text-align: center;
height: 44px;
}
input#url {
border-radius: 4px;
}
.intro-panel {
min-width: 40%;
display: flex;
flex-direction: column;
margin: auto;
}
.intro-panel .panel-heading {
font-size: 1.0em;
}
.intro-panel .panel-block {
padding: 1.0em;
}
#datetime {
position: absolute;
right: 1em;
z-index: 10;
background: linear-gradient(90deg, rgba(255, 255, 255, 0), #FFF 15%, #FFF);
margin: 5px 0.75em 5px 0;
line-height: 2;
}
.is-borderless {
border: 0px;
}
.modal {
top: 174px;
}
`);
}
render() {
return html`
${this.embed !== "replayonly" ? html`
<div class="replay-bar">
<form @submit="${this.onSubmit}">
<div class="field has-addons">
<a id="fullscreen" class="button is-borderless" @click="${this.onFullscreenToggle}">
<span class="icon is-small">
<fa-icon size="1.0em" class="has-text-grey" .svg="${this.isFullscreen ? fasUnfullscreen : fasFullscreen}"></fa-icon>
</span>
</a>
<a id="refresh" class="button is-borderless ${this.isLoading ? 'is-loading' : ''}" @click="${this.onRefresh}">
<span class="icon is-small">
${!this.isLoading ? html`
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRefresh}"></fa-icon>
` : ``}
</span>
</a>
<p class="control is-expanded">
<input id="url" class="input" type="text" .value="${this.replayUrl}" placeholder="https://... Enter a URL to replay from the archive here">
</p>
<p id="datetime" class="control is-hidden-mobile">${tsToDate(this.replayTS).toLocaleString()}</p>
</div>
</form>
</div>` : html`
`}
${this.iframeUrl ? html`
<iframe @message="${this.onReplayMessage}" allow="autoplay 'self'; fullscreen"
src="${this.iframeUrl}"></iframe>
` : html`
<nav class="panel intro-panel">
<p class="panel-heading">Replay Web Page</p>
<p class="panel-block">Enter a URL above to replay it from the web archive!</p>
</nav>
`}
${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" @click="${(e) => this.showAuth = false}"></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>
</div>
</div>
` : ``}
`;
}
onReAuthed(event) {
this.reauthWait = (async () => {
const headers = event.detail.headers;
const resp = await fetch(`/wabac/api/${this.collInfo.coll}/updateAuth`, {
method: 'POST',
body: JSON.stringify({headers})
});
if (this.showAuth) {
this.onRefresh(null, true);
this.showAuth = false;
}
})();
}
}
customElements.define("wr-coll-replay", Replay);
export { Replay };