Migrate ReplayWebApp, Coll and Replay to TS (#233)

This commit is contained in:
sua yoo
2023-09-18 10:43:29 -07:00
committed by GitHub
parent 79d2f1585c
commit 4d55efa341
6 changed files with 220 additions and 165 deletions
+72 -49
View File
@@ -1,4 +1,6 @@
import { LitElement, html, css } from "lit";
import { property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import {
wrapCss,
rwpLogo,
@@ -14,24 +16,60 @@ import { SWManager } from "./swmanager";
// ===========================================================================
class ReplayWebApp extends LitElement {
@property({ type: Boolean })
inited = false;
@property({ type: Object })
pageParams: URLSearchParams = new URLSearchParams();
@property({ type: String })
sourceUrl: string | null = null;
@property({ type: Boolean })
navMenuShown = false;
@property({ type: Boolean })
showAbout = false;
@property({ type: Boolean })
showFileDropOverlay = false;
@property({ type: String })
collTitle: string | null = null;
@property({ type: Object })
loadInfo: any = null;
@property({ type: String })
embed: any = null;
@property({ type: String })
collPageUrl = "";
@property({ type: String })
pageTitle = "";
@property({ type: Boolean })
pageReplay = false;
@property({ type: String })
source: any = null;
@property({ type: Boolean })
skipRuffle = false;
@property({ type: Object })
swErrorMsg: any = null;
private swName?: string;
private swmanager: SWManager | null;
private useRuffle = false;
private droppedFile: File | null = null;
// eslint-disable-next-line no-undef
constructor(swName = __SW_NAME__) {
super();
this.sourceUrl = null;
this.collTitle = null;
this.showAbout = false;
this.showFileDropOverlay = false;
this.pageParams = new URLSearchParams();
this.inited = false;
this.navMenuShown = false;
this.collPageUrl = "";
this.pageTitle = "";
this.pageReplay = false;
this.loadInfo = null;
this.swName = swName;
this.swmanager = null;
@@ -58,12 +96,13 @@ class ReplayWebApp extends LitElement {
});
this.addEventListener("drop", (dragEvent) => {
this.droppedFile = dragEvent.dataTransfer.files[0];
this.droppedFile = dragEvent.dataTransfer?.files[0] || null;
this.showFileDropOverlay = false;
dragEvent.preventDefault();
});
}
this.maybeStartFileDrop = (dragEvent) => {
private maybeStartFileDrop = (dragEvent) => {
if (this.sourceUrl) {
// A source is already loaded. Don't allow dropping a file.
return;
@@ -71,7 +110,6 @@ class ReplayWebApp extends LitElement {
this.showFileDropOverlay = true;
dragEvent.preventDefault();
};
}
get appName() {
return "ReplayWeb.page";
@@ -81,27 +119,6 @@ class ReplayWebApp extends LitElement {
return window.location.pathname;
}
static get properties() {
return {
inited: { type: Boolean },
pageParams: { type: Object },
sourceUrl: { type: String },
navMenuShown: { type: Boolean },
showAbout: { type: Boolean },
showFileDropOverlay: { type: Boolean },
collTitle: { type: String },
loadInfo: { type: Object },
embed: { type: String },
collPageUrl: { type: String },
pageTitle: { type: String },
pageReplay: { type: Boolean },
source: { type: String },
skipRuffle: { type: Boolean },
swErrorMsg: { type: Object },
};
}
static get styles() {
return wrapCss(ReplayWebApp.appStyles);
}
@@ -364,10 +381,10 @@ class ReplayWebApp extends LitElement {
renderColl() {
return html` <wr-coll
.loadInfo="${this.loadInfo}"
sourceUrl="${this.sourceUrl}"
sourceUrl="${this.sourceUrl || ""}"
embed="${this.embed}"
appName="${this.appName}"
swName="${this.swName}"
swName="${ifDefined(this.swName)}"
.appLogo="${this.mainLogo}"
@replay-favicons=${this.onFavIcons}
@update-title=${this.onTitle}
@@ -436,7 +453,7 @@ class ReplayWebApp extends LitElement {
.register()
.catch(
() =>
(this.swErrorMsg = this.swmanager.renderErrorReport(this.mainLogo)),
(this.swErrorMsg = this.swmanager?.renderErrorReport(this.mainLogo)),
);
window.addEventListener("popstate", () => {
@@ -451,7 +468,7 @@ class ReplayWebApp extends LitElement {
}
onFavIcons(event) {
const head = document.querySelector("head");
const head = document.querySelector("head")!;
const oldLinks = document.querySelectorAll("link[rel*='icon']");
for (const link of oldLinks) {
@@ -470,7 +487,7 @@ class ReplayWebApp extends LitElement {
// This is a workaround, since this app's routing doesn't permit normal
// following of in-page anchors.
event.preventDefault();
this.renderRoot.querySelector("#skip-main-target").focus();
(this.renderRoot.querySelector("#skip-main-target") as HTMLElement).focus();
}
onNavMenu(event) {
@@ -487,7 +504,9 @@ class ReplayWebApp extends LitElement {
(event) => {
event.preventDefault();
this.navMenuShown = false;
this.renderRoot.querySelector("#menu-button").focus();
(
this.renderRoot.querySelector("#menu-button") as HTMLElement
).focus();
},
{ once: true },
);
@@ -497,7 +516,9 @@ class ReplayWebApp extends LitElement {
if (event.key == "Escape") {
event.preventDefault();
this.navMenuShown = false;
this.renderRoot.querySelector("#menu-button").focus();
(
this.renderRoot.querySelector("#menu-button") as HTMLElement
).focus();
}
},
{ once: true },
@@ -510,7 +531,7 @@ class ReplayWebApp extends LitElement {
this.pageParams = new URLSearchParams(window.location.search);
// Google Drive
let state = this.pageParams.get("state");
let state: any = this.pageParams.get("state");
if (state) {
try {
state = JSON.parse(state);
@@ -557,7 +578,9 @@ class ReplayWebApp extends LitElement {
if (this.pageParams.get("config")) {
try {
this.loadInfo.extraConfig = JSON.parse(this.pageParams.get("config"));
this.loadInfo.extraConfig = JSON.parse(
this.pageParams.get("config") || "",
);
} catch (e) {
console.log("invalid config: " + e);
}
@@ -596,7 +619,7 @@ class ReplayWebApp extends LitElement {
}
if (this.pageParams.get("swName")) {
this.swName = this.pageParams.get("swName");
this.swName = this.pageParams.get("swName") || undefined;
}
if (IS_APP && this.sourceUrl.startsWith("file://")) {
+38 -46
View File
@@ -1,4 +1,5 @@
import { LitElement, html, css } from "lit";
import { property, state } from "lit/decorators.js";
import { wrapCss, apiPrefix } from "./misc";
import { map } from "lit/directives/map.js";
@@ -11,26 +12,41 @@ import fasArrowDown from "@fortawesome/fontawesome-free/svgs/solid/angle-double-
import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg";
import type { Coll } from "./types";
// ===========================================================================
class CollIndex extends LitElement {
@property({ type: Array })
colls: Coll[] = [];
@property({ type: String })
query = "";
@property({ type: Array })
filteredColls: any[] = [];
@property({ type: Array })
sortedColls: any[] | null = null;
@property({ type: Boolean })
hideHeader: any = null;
@property({ type: String })
dateName = "Date Loaded";
@property({ type: String })
headerName = "Loaded Archives";
@state()
private _deleting: any = {};
private typeFilter = "";
private indexParams = "";
constructor() {
super();
this.colls = [];
this.filteredColls = [];
this.sortedColls = null;
this.query = "";
this.hideHeader = localStorage.getItem("index:hideHeader") === "1";
this._deleting = {};
this.dateName = "Date Loaded";
this.headerName = "Loaded Archives";
this.typeFilter = "";
this.indexParams = "";
}
get sortKeys() {
@@ -45,25 +61,6 @@ class CollIndex extends LitElement {
];
}
static get properties() {
return {
colls: { type: Array },
query: { type: String },
filteredColls: { type: Array },
sortedColls: { type: Array },
hideHeader: { type: Boolean },
_deleting: { type: Object },
dateName: { type: String },
headerName: { type: String },
};
}
firstUpdated() {
this.loadColls();
}
@@ -363,19 +360,14 @@ class CollIndex extends LitElement {
// ===========================================================================
class CollInfo extends LitElement {
constructor() {
super();
this.detailed = false;
this.canDelete = false;
}
@property({ type: Object })
coll!: Coll | Record<string, never>;
static get properties() {
return {
coll: { type: Object },
detailed: { type: Boolean },
canDelete: { type: Boolean },
};
}
@property({ type: Boolean })
detailed = false;
@property({ type: Boolean })
canDelete = false;
static get styles() {
return wrapCss(CollInfo.compStyles);
@@ -526,7 +518,7 @@ class CollInfo extends LitElement {
<ol style="padding: revert">
${map(
coll.resources,
(resource) =>
(resource: any) =>
html`<li>
<a href="${resource.path}">${resource.name + "\n"}</a>
</li>`,
+42 -26
View File
@@ -1,6 +1,5 @@
import { LitElement, html, css } from "lit";
import { property, state } from "lit/decorators.js";
import { map } from "lit/directives/map.js";
import type {
SlDropdown,
SlMenu,
@@ -47,6 +46,8 @@ import fasCaretDown from "@fortawesome/fontawesome-free/svgs/solid/caret-down.sv
import { RWPEmbedReceipt } from "./embed-receipt.js";
import Split from "split.js";
import type { Coll as CollInfo } from "./types";
import type { Replay } from "./replay";
const RWP_SCHEME = "search://";
@@ -66,7 +67,7 @@ class Coll extends LitElement {
showSidebar: boolean | null = null;
@property({ type: Object, attribute: false })
collInfo: any = null;
collInfo: CollInfo | Record<string, never> | null = null;
@property({ type: String })
coll = "";
@@ -96,13 +97,13 @@ class Coll extends LitElement {
ts = "";
@property({ type: Boolean })
isFullscreen: any;
isFullscreen: boolean | null = null;
@property({ type: Boolean })
menuActive = false;
@property({ type: String })
embed: any;
embed: string | null = null;
@property({ type: Boolean })
embedDropdownActive = false;
@@ -135,24 +136,30 @@ class Coll extends LitElement {
autoUpdateInterval = 10;
@property({ type: String })
swName: any;
swName: any = null;
private tabNames = ["pages", "story", "resources", "info"];
private tabLabels = {
private splitter: any = null;
private _replaceLoc = false;
private _locUpdateNeeded = false;
private _locationHash = "";
private _autoUpdater: null | Promise<void> = null;
private observer?: IntersectionObserver;
private readonly tabNames = ["pages", "story", "resources", "info"];
private readonly tabLabels = {
pages: "Pages",
story: "Story",
resources: "URLs",
info: "Archive Info",
};
private splitter: any = null;
private _replaceLoc = false;
private _locUpdateNeeded = false;
private _locationHash = "";
private _autoUpdater: Promise<void> | null = null;
private observer?: IntersectionObserver;
constructor() {
super();
this.showSidebar = localStorage.getItem("pages:showSidebar") === "1";
}
@@ -301,7 +308,9 @@ class Coll extends LitElement {
configureSplitter() {
if (this.tabData.url && this.showSidebar) {
const contents = this.renderRoot.querySelector("#contents");
const contents = this.renderRoot.querySelector(
"#contents",
) as HTMLElement;
const replay = this.renderRoot.querySelector("wr-coll-replay") as Replay;
if (contents && replay && !this.splitter) {
@@ -379,15 +388,17 @@ class Coll extends LitElement {
});
}
if (!this.collInfo.title) {
this.collInfo.title = this.collInfo.filename;
if (!this.collInfo!.title) {
this.collInfo!.title = this.collInfo!.filename;
}
if (this.embed === "replayonly" || this.embed === "replay-with-info") {
this.showSidebar = false;
}
this.hasStory = this.collInfo.desc || this.collInfo.lists.length;
this.hasStory = Boolean(
this.collInfo!.desc || this.collInfo!.lists?.length,
);
this.dispatchEvent(
new CustomEvent("coll-loaded", {
@@ -435,12 +446,12 @@ class Coll extends LitElement {
}
if (
this.collInfo.coll &&
this.collInfo?.coll &&
(!this.tabData.view || !this.tabNames.includes(this.tabData.view))
) {
const view = this.hasStory
? "story"
: this.editable || this.collInfo.pages.length
: this.editable || this.collInfo.pages?.length
? "pages"
: "resources";
@@ -452,7 +463,11 @@ class Coll extends LitElement {
if (this.tabData.url && this.tabData.url.startsWith("page:")) {
const pageIndex = Number(this.tabData.url.slice("page:".length));
if (!isNaN(pageIndex) && pageIndex < this.collInfo.pages.length) {
if (
this.collInfo?.pages &&
!isNaN(pageIndex) &&
pageIndex < this.collInfo.pages.length
) {
const page = this.collInfo.pages[pageIndex];
this.tabData.url = page.url;
this.tabData.ts = getPageDateTS(page).timestamp;
@@ -852,7 +867,7 @@ class Coll extends LitElement {
if (this.collInfo && !this.collInfo.coll) {
return html` <wr-loader
.loadInfo="${this.loadInfo}"
embed="${this.embed}"
embed="${this.embed || ""}"
swName="${this.swName}"
.coll="${this.coll}"
sourceUrl="${this.sourceUrl || ""}"
@@ -1442,7 +1457,7 @@ class Coll extends LitElement {
}
return html`<rwp-embed-receipt
.collInfo=${this.collInfo}
.collInfo=${this.collInfo || {}}
url=${this.url}
ts=${this.ts}
.appLogo=${this.appLogo}
@@ -1465,6 +1480,7 @@ class Coll extends LitElement {
}
renderCollInfo() {
if (!this.collInfo) return;
return html` <div class="info-bg">
<wr-coll-info
class="is-list"
@@ -1490,7 +1506,7 @@ class Coll extends LitElement {
${isInfo ? this.renderCollInfo() : html``}
${isStory
? html` <wr-coll-story
.collInfo="${this.collInfo}"
.collInfo="${this.collInfo || {}}"
.active="${isStory}"
currList="${this.tabData.currList || 0}"
@coll-tab-nav="${this.onCollTabNav}"
@@ -1503,7 +1519,7 @@ class Coll extends LitElement {
: ""}
${isResources
? html` <wr-coll-resources
.collInfo="${this.collInfo}"
.collInfo="${this.collInfo || {}}"
.active="${isResources}"
query="${this.tabData.query || ""}"
urlSearchType="${this.tabData.urlSearchType || ""}"
@@ -1642,7 +1658,7 @@ class Coll extends LitElement {
}
async deleteFully(reload = false) {
const deleteURL = this.collInfo.apiPrefix + (reload ? "?reload=1" : "");
const deleteURL = this.collInfo!.apiPrefix + (reload ? "?reload=1" : "");
const resp = await fetch(deleteURL, {
method: "DELETE",
@@ -1663,7 +1679,7 @@ class Coll extends LitElement {
onSubmit(event) {
event.preventDefault();
const input = this.renderRoot.querySelector("input")!;
const input = this.renderRoot.querySelector("input") as HTMLInputElement;
if (input.value) {
this.navigateTo(input.value);
} else {
+1
View File
@@ -1 +1,2 @@
declare module "*.svg";
declare var __SW_NAME__: string;
+40 -34
View File
@@ -1,44 +1,49 @@
import { LitElement, html, css } from "lit";
import { property, state } from "lit/decorators.js";
import { wrapCss, rwpLogo } from "./misc";
import type { Coll } from "./types";
// ===========================================================================
class Replay extends LitElement {
constructor() {
super();
this.replayUrl = "";
this.replayTS = "";
this.actualTS = "";
this.url = "";
this.ts = "";
this.title = "";
this.collInfo = null;
@property({ type: Object })
collInfo: Coll | Record<string, never> | null = null;
this.showAuth = false;
this.reauthWait = null;
this.authFileHandle = null;
}
static get properties() {
return {
collInfo: { type: Object },
sourceUrl: { type: String },
@property({ type: String })
sourceUrl: any = null;
// external url set from parent
url: { type: String },
ts: { type: String },
@property({ type: String })
url = "";
@property({ type: String })
ts = "";
// actual replay url
replayUrl: { type: String },
replayTS: { type: String },
actualTS: { type: String },
title: { type: String },
@property({ type: String })
replayUrl = "";
iframeUrl: { type: String },
@property({ type: String })
replayTS = "";
showAuth: { type: Boolean },
authFileHandle: { type: Object },
};
}
@property({ type: String })
actualTS = "";
@property({ type: String })
title = "";
@property({ type: String })
iframeUrl: any = null;
@property({ type: Boolean })
showAuth = false;
@property({ type: Object })
authFileHandle: any = null;
private reauthWait: null | Promise<void> = null;
private _loadPoll: null | number = null;
firstUpdated() {
window.addEventListener("message", (event) => this.onReplayMessage(event));
@@ -81,7 +86,8 @@ class Replay extends LitElement {
}
doSetIframeUrl() {
this.iframeUrl = this.url
this.iframeUrl =
this.url && this.collInfo
? `${this.collInfo.replayPrefix}/${this.ts || ""}mp_/${this.url}`
: "";
}
@@ -199,7 +205,7 @@ class Replay extends LitElement {
// google drive reauth
const headers = event.detail.headers;
await fetch(`${this.collInfo.apiPrefix}/updateAuth`, {
await fetch(`${this.collInfo!.apiPrefix}/updateAuth`, {
method: "POST",
body: JSON.stringify({ headers }),
});
@@ -231,7 +237,7 @@ class Replay extends LitElement {
!iframe.contentDocument ||
!iframe.contentWindow ||
(iframe.contentDocument.readyState === "complete" &&
!iframe.contentWindow._WBWombat)
!(iframe.contentWindow as Window & { _WBWombat: any })._WBWombat)
) {
this.clearLoading(iframe && iframe.contentWindow);
}
@@ -273,7 +279,7 @@ class Replay extends LitElement {
this.doSetIframeUrl();
if (oldIframeUrl === this.iframeUrl || this.url === this.replayUrl) {
this.waitForLoad();
iframe.contentWindow.location.reload();
iframe.contentWindow?.location.reload();
}
}
@@ -394,7 +400,7 @@ class Replay extends LitElement {
`
: html` <wr-gdrive
.sourceUrl="${this.sourceUrl}"
.state="trymanual"
state="trymanual"
.reauth="${true}"
@load-ready="${this.onReAuthed}"
></wr-gdrive>`}
+17
View File
@@ -0,0 +1,17 @@
export interface Coll {
filename: string;
sourceUrl: string;
replayPrefix: string;
apiPrefix: string;
coll?: string;
name?: string;
title?: string;
loadUrl?: string;
desc?: string;
description?: string;
resources?: { path: string; name: string }[];
verify?: any;
onDemand?: any;
pages?: any[];
lists?: any[];
}