Typescript migration part 2 (#261)

Converts everything to typescript, adding `@ts-expect-error`s where
necessary. Also makes some progress converting elements to use
decorators, but we're not fully there yet — I think it'll make sense to
continue to do that in future PRs, rather than doing it all in one go,
just so that we can keep up with the dev branch.
This commit is contained in:
Emma Segal-Grossman
2023-11-29 15:53:48 -05:00
committed by emma
parent e9438eb724
commit ad38694598
28 changed files with 1141 additions and 613 deletions
+38 -37
View File
@@ -1,5 +1,5 @@
import { LitElement, html, css } from "lit";
import { property } from "lit/decorators.js";
import { LitElement, html, css, type TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import {
wrapCss,
@@ -16,9 +16,11 @@ import { SWManager } from "./swmanager";
import "./item";
import "./item-index";
import "./chooser";
import { LoadInfo } from "./item";
// ===========================================================================
class ReplayWebApp extends LitElement {
@customElement("replay-app-main")
export class ReplayWebApp extends LitElement {
@property({ type: Boolean })
inited = false;
@@ -41,10 +43,10 @@ class ReplayWebApp extends LitElement {
collTitle: string | null = null;
@property({ type: Object })
loadInfo: any = null;
loadInfo: LoadInfo | null = null;
@property({ type: String })
embed: any = null;
embed: string | null = null;
@property({ type: String })
collPageUrl = "";
@@ -56,13 +58,13 @@ class ReplayWebApp extends LitElement {
pageReplay = false;
@property({ type: String })
source: any = null;
source: string | null = null;
@property({ type: Boolean })
skipRuffle = false;
@property({ type: Object })
swErrorMsg: any = null;
swErrorMsg: TemplateResult<1> | "" | null = null;
private swName?: string;
private swmanager: SWManager | null;
@@ -70,7 +72,6 @@ class ReplayWebApp extends LitElement {
private droppedFile: File | null = null;
// eslint-disable-next-line no-undef
constructor(swName = __SW_NAME__) {
super();
@@ -105,7 +106,7 @@ class ReplayWebApp extends LitElement {
});
}
private maybeStartFileDrop = (dragEvent) => {
private maybeStartFileDrop = (dragEvent: DragEvent) => {
if (this.sourceUrl) {
// A source is already loaded. Don't allow dropping a file.
return;
@@ -372,7 +373,7 @@ class ReplayWebApp extends LitElement {
-->
<a
href="?terms"
@click="${(e) => {
@click="${(e: Event) => {
e.preventDefault();
this.showAbout = true;
}}"
@@ -385,7 +386,7 @@ class ReplayWebApp extends LitElement {
return html` <wr-item
.loadInfo="${this.loadInfo}"
sourceUrl="${this.sourceUrl || ""}"
embed="${this.embed}"
embed="${ifDefined(this.embed === null ? undefined : this.embed)}"
appName="${this.appName}"
swName="${ifDefined(this.swName)}"
.appLogo="${this.mainLogo}"
@@ -452,12 +453,11 @@ class ReplayWebApp extends LitElement {
}
this.swmanager = new SWManager({ name, appName: this.appName });
this.swmanager
.register()
.catch(
() =>
(this.swErrorMsg = this.swmanager?.renderErrorReport(this.mainLogo)),
);
this.swmanager.register().catch(
() =>
// @ts-expect-error - TS2554 - Expected 2 arguments, but got 1.
(this.swErrorMsg = this.swmanager?.renderErrorReport(this.mainLogo)),
);
window.addEventListener("popstate", () => {
this.initRoute();
@@ -534,16 +534,21 @@ class ReplayWebApp extends LitElement {
this.pageParams = new URLSearchParams(window.location.search);
// Google Drive
let state: any = this.pageParams.get("state");
const state = this.pageParams.get("state");
type State = {
ids?: string[];
userId?: string;
action?: string;
};
if (state) {
try {
state = JSON.parse(state);
const parsedState: State = JSON.parse(state);
if (
state.ids instanceof Array &&
state.userId &&
state.action === "open"
parsedState.ids instanceof Array &&
parsedState.userId &&
parsedState.action === "open"
) {
this.pageParams.set("source", "googledrive://" + state.ids[0]);
this.pageParams.set("source", "googledrive://" + parsedState.ids[0]);
this.pageParams.delete("state");
window.location.search = this.pageParams.toString();
return;
@@ -581,7 +586,7 @@ class ReplayWebApp extends LitElement {
if (this.pageParams.get("config")) {
try {
this.loadInfo.extraConfig = JSON.parse(
this.loadInfo!.extraConfig = JSON.parse(
this.pageParams.get("config") || "",
);
} catch (e) {
@@ -590,35 +595,35 @@ class ReplayWebApp extends LitElement {
}
if (this.pageParams.get("baseUrlSourcePrefix")) {
this.loadInfo.extraConfig = this.loadInfo.extraConfig || {};
this.loadInfo.extraConfig.baseUrlSourcePrefix = this.pageParams.get(
this.loadInfo!.extraConfig = this.loadInfo!.extraConfig || {};
this.loadInfo!.extraConfig.baseUrlSourcePrefix = this.pageParams.get(
"baseUrlSourcePrefix",
);
}
if (this.pageParams.get("basePageUrl")) {
this.loadInfo.extraConfig = this.loadInfo.extraConfig || {};
this.loadInfo.extraConfig.baseUrl = this.pageParams.get("basePageUrl");
this.loadInfo!.extraConfig = this.loadInfo!.extraConfig || {};
this.loadInfo!.extraConfig.baseUrl = this.pageParams.get("basePageUrl");
}
if (this.pageParams.get("customColl")) {
this.loadInfo.customColl = this.pageParams.get("customColl");
this.loadInfo!.customColl = this.pageParams.get("customColl");
}
if (this.pageParams.get("noWebWorker") === "1") {
this.loadInfo.noWebWorker = true;
this.loadInfo!.noWebWorker = true;
}
if (this.pageParams.get("noCache") === "1") {
this.loadInfo.noCache = true;
this.loadInfo!.noCache = true;
}
if (this.pageParams.get("hideOffscreen") === "1") {
this.loadInfo.hideOffscreen = true;
this.loadInfo!.hideOffscreen = true;
}
if (this.pageParams.get("loading") === "eager") {
this.loadInfo.loadEager = true;
this.loadInfo!.loadEager = true;
}
if (this.pageParams.get("swName")) {
@@ -791,7 +796,3 @@ class ReplayWebApp extends LitElement {
`;
}
}
customElements.define("replay-app-main", ReplayWebApp);
export { ReplayWebApp };
+62 -47
View File
@@ -2,47 +2,50 @@ import { LitElement, html, css } from "lit";
import { IS_APP, wrapCss } from "./misc";
import fasUpload from "@fortawesome/fontawesome-free/svgs/solid/upload.svg";
import { customElement, property } from "lit/decorators.js";
export interface FileWithPath extends File {
readonly path: string;
}
// ===========================================================================
class Chooser extends LitElement {
constructor() {
super();
@customElement("wr-chooser")
export class Chooser extends LitElement {
@property({ type: String })
fileDisplayName = "";
this.fileDisplayName = "";
this.file = null;
this.droppedFile = null;
@property({ attribute: false })
file: FileWithPath | null = null;
this.hasNativeFS = !!window.showOpenFilePicker && !IS_APP;
@property({ attribute: false })
droppedFile: FileWithPath | null = null;
this.newFullImport = false;
@property({ type: Boolean })
hasNativeFS = !!window.showOpenFilePicker && !IS_APP;
this.noHead = false;
this.showOpenFilePickerOptions = {
types: [
{
description: "WARC, WACZ, HAR and WBN Files",
accept: {
"application/warc": [".warc", ".gz"],
"application/har": [".har"],
"application/wacz": [".wacz"],
"application/wbn": [".wbn"],
"application/json": [".json"],
},
@property({ type: Object })
showOpenFilePickerOptions = {
types: [
{
description: "WARC, WACZ, HAR and WBN Files",
accept: {
"application/warc": [".warc", ".gz"],
"application/har": [".har"],
"application/wacz": [".wacz"],
"application/wbn": [".wbn"],
"application/json": [".json"],
},
],
};
}
},
],
};
static get properties() {
return {
fileDisplayName: { type: String },
/** @type File */
droppedFile: { attribute: false },
newFullImport: { type: Boolean },
noHead: { type: Boolean },
};
}
@property({ type: Boolean })
newFullImport = false;
@property({ type: Boolean })
noHead = false;
fileHandle?: FileSystemFileHandle;
updated(changedProperties) {
if (changedProperties.has("droppedFile") && this.droppedFile) {
@@ -56,11 +59,12 @@ class Chooser extends LitElement {
.map(Object.values)
.flat(2);
const fileHasAllowedExtension = allowedFileExtensions.some((extension) =>
this.droppedFile.name.endsWith(extension),
const fileHasAllowedExtension = allowedFileExtensions.some(
(extension) => this.droppedFile?.name.endsWith(extension),
);
if (fileHasAllowedExtension) {
if (this.droppedFile === null) return;
this.setFile(this.droppedFile);
this.dispatchEvent(
new CustomEvent("did-drop-file", { bubbles: true, composed: true }),
@@ -76,10 +80,10 @@ class Chooser extends LitElement {
this.setFile(event.currentTarget.files[0]);
}
setFile(file) {
setFile(file: FileWithPath) {
this.file = file;
// file.path only available in electron app
this.fileDisplayName = "file://" + (this.file.path || this.file.name);
this.fileDisplayName = "file://" + (file.path || file.name);
}
async onChooseNativeFile() {
@@ -90,9 +94,11 @@ class Chooser extends LitElement {
const [fileHandle] = await window.showOpenFilePicker(
this.showOpenFilePickerOptions,
);
this.fileHandle = fileHandle;
this.file = await fileHandle.getFile();
this.file = (await fileHandle.getFile()) as FileWithPath;
this.fileDisplayName = "file://" + fileHandle.name;
}
@@ -103,18 +109,32 @@ class Chooser extends LitElement {
);
}
onStartLoad(event) {
onStartLoad(event?: Event) {
if (event) {
event.preventDefault();
}
const loadInfo = { sourceUrl: this.fileDisplayName };
type LoadInfo = {
sourceUrl: string;
isFile?: boolean;
loadUrl?: string;
noCache?: boolean;
extra?: { fileHandle: FileSystemFileHandle };
blob?: Blob;
size?: number;
name?: string;
newFullImport: boolean;
};
const loadInfo: LoadInfo = {
sourceUrl: this.fileDisplayName,
newFullImport: this.newFullImport,
};
if (this.file) {
loadInfo.isFile = true;
// file.path only available in electron app
if (this.file.path) {
// eslint-disable-next-line no-undef
loadInfo.loadUrl = "file2://" + this.file.path;
loadInfo.noCache = true;
} else if (this.fileHandle) {
@@ -130,8 +150,6 @@ class Chooser extends LitElement {
loadInfo.name = this.fileDisplayName;
}
loadInfo.newFullImport = this.newFullImport;
this.dispatchEvent(
new CustomEvent("load-start", {
bubbles: true,
@@ -152,6 +170,7 @@ class Chooser extends LitElement {
this.fileDisplayName.startsWith("file://")
) {
this.file = null;
this.fileDisplayName = "";
}
}
@@ -280,7 +299,3 @@ class Chooser extends LitElement {
</section>`;
}
}
customElements.define("wr-chooser", Chooser);
export { Chooser };
+1 -1
View File
@@ -9,4 +9,4 @@ const replayApp = new ElectronReplayApp({
profileName: "replaywebpage",
});
replayApp.init(true);
replayApp.init();
+18
View File
@@ -11,6 +11,11 @@ const dbs = {};
const loader = new CollectionLoader();
/**
*
* @param {string} name
* @returns
*/
async function getColl(name) {
if (!dbs[name]) {
dbs[name] = await loader.loadColl(name);
@@ -20,11 +25,24 @@ async function getColl(name) {
return dbs[name];
}
/**
* @param {string} name
* @returns
*/
async function getDB(name) {
const coll = await getColl(name);
return coll.store;
}
/**
*
* @param {import("electron").IpcRendererEvent} event
* @param {*} request
* @param {*} coll
* @param {*} ts
* @param {*} channel
* @returns
*/
async function getResponse(event, request, coll, ts, channel) {
const db = await getDB(coll);
+48 -19
View File
@@ -26,7 +26,9 @@ import log from "electron-log";
import mime from "mime-types";
import url from "url";
// @ts-expect-error - TS2322 - Type 'typeof Headers' is not assignable to type '{ new (init?: HeadersInit | undefined): Headers; prototype: Headers; }'.
global.Headers = Headers;
// @ts-expect-error - TS2322 - Type '(url: RequestInfo, init?: RequestInit | undefined) => Promise<Response>' is not assignable to type '(input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>'.
global.fetch = fetch;
const STATIC_PREFIX = "http://localhost:5471/";
@@ -39,27 +41,43 @@ const URL_RX = /([^/]+)\/([\d]+)(?:\w\w_)?\/(.*)$/;
// ============================================================================
class ElectronReplayApp {
/**
* @type {string}
*/
pluginPath = "";
appPath = app.getAppPath();
projPath = path.join(this.appPath, "../");
staticContentPath = "./";
profileName = "";
proxyColl = null;
proxyTS = null;
/**
* @type {BrowserWindow | null}
*/
mainWindow = null;
/**
* @type {string | null}
*/
openNextFile = null;
screenSize = { width: 1024, height: 768 };
/**
* @type {string | null}
*/
origUA = null;
constructor({ staticPath = "./", profileName = "" } = {}) {
this.pluginPath = "";
this.appPath = app.getAppPath();
this.projPath = path.join(this.appPath, "../");
this.staticContentPath = staticPath;
this.profileName = profileName;
this.proxyColl = null;
this.proxyTS = null;
this.mainWindow = null;
this.openNextFile = null;
this.screenSize = { width: 1024, height: 768 };
this.origUA = null;
}
get mainWindowWebPreferences() {
@@ -132,7 +150,7 @@ class ElectronReplayApp {
});
});
app.on("activate", function () {
app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
@@ -153,6 +171,7 @@ class ElectronReplayApp {
checkUpdates() {
autoUpdater.logger = log;
// @ts-expect-error - TS2339 - Property 'transports' does not exist on type 'Logger'.
autoUpdater.logger.transports.file.level = "info";
autoUpdater.checkForUpdatesAndNotify();
}
@@ -332,6 +351,15 @@ class ElectronReplayApp {
callback({ statusCode, headers, data });
}
/**
*
* @param {string} url
* @param {(props: {
* statusCode: number;
* headers: Record<string, string>;
* data: unknown;
* }) => void} callback
*/
notFound(url, callback) {
console.log("not found: " + url);
const data = this._bufferToStream(
@@ -449,6 +477,7 @@ class ElectronReplayApp {
const theWindow = new BrowserWindow({
width: this.screenSize.width,
height: this.screenSize.height,
// @ts-expect-error - TS2345 - Argument of type '{ width: any; height: any; isMaximized: boolean; show: false; webPreferences: { plugins: boolean; preload: string; nativeWindowOpen: boolean; contextIsolation: boolean; enableRemoteModule: boolean; sandbox: boolean; nodeIntegration: boolean; }; }' is not assignable to parameter of type 'BrowserWindowConstructorOptions'.
isMaximized: true,
show: false,
webPreferences: this.mainWindowWebPreferences,
+58 -53
View File
@@ -6,36 +6,26 @@ import fasDownload from "@fortawesome/fontawesome-free/svgs/solid/download.svg";
import { clickOnSpacebarPress } from "./misc";
import { LitElement, html, css } from "lit";
import { LitElement, html, css, nothing } from "lit";
import { tsToDate } from "./pageutils";
import prettyBytes from "pretty-bytes";
import { property } from "lit/decorators.js";
import type { Item as ItemType } from "./types";
// ===========================================================================
export class RWPEmbedReceipt extends LitElement {
constructor() {
super();
this.collInfo = null;
this.appLogo = null;
this.ts = null;
this.url = null;
this.active = false;
}
@property({ type: Object }) collInfo: ItemType | null = null;
@property({ type: Object }) appLogo = null;
@property({ type: String }) ts: string | null = null;
@property({ type: String }) url: string | null = null;
@property({ type: Boolean }) active = false;
// @ts-expect-error - TS2611 - 'renderRoot' is defined as a property in class 'LitElement', but is overridden here in 'RWPEmbedReceipt' as an accessor.
get renderRoot() {
return this;
}
static get properties() {
return {
collInfo: { type: Object },
appLogo: { type: Object },
url: { type: String },
ts: { type: String },
active: { type: Boolean },
};
}
static get embedStyles() {
return css`
rwp-embed-receipt {
@@ -182,19 +172,17 @@ export class RWPEmbedReceipt extends LitElement {
}
render() {
let {
numValid,
numInvalid,
const {
numValid = 0,
numInvalid = 0,
domain,
certFingerprint,
datapackageHash,
publicKey,
software,
} = this.collInfo.verify || {};
numValid = numValid || 0;
numInvalid = numInvalid || 0;
} = this.collInfo?.verify || {};
const sourceUrl = this.collInfo.sourceUrl;
const sourceUrl = this.collInfo?.sourceUrl;
const certFingerprintUrl = certFingerprint
? `https://crt.sh/?q=${certFingerprint}`
@@ -251,25 +239,35 @@ export class RWPEmbedReceipt extends LitElement {
>replayweb.page</a
>.
</p>
<a
href="${sourceUrl}"
class="button is-primary mt-4"
@keyup="${clickOnSpacebarPress}"
>
<span class="icon is-small">
<fa-icon
size="1.0em"
aria-hidden="true"
.svg="${fasDownload}"
></fa-icon>
</span>
<span>Download Archive</span>
</a>
<hr class="dropdown-divider mt-4" />
${sourceUrl
? html`
<a
href="${sourceUrl}"
class="button is-primary mt-4"
@keyup="${clickOnSpacebarPress}"
>
<span class="icon is-small">
<fa-icon
size="1.0em"
aria-hidden="true"
.svg="${fasDownload}"
></fa-icon>
</span>
<span>Download Archive</span>
</a>
<hr class="dropdown-divider mt-4" />
`
: nothing}
<h2 class="mt-4">Technical Information</h2>
<div class="embed-info-drop-statscontainer mb-4">
<h3>Original URL:</h3>
<p><a target="_blank" href="${this.url}">${this.url}</a></p>
${this.url
? html`
<h3>Original URL:</h3>
<p>
<a target="_blank" href="${this.url}">${this.url}</a>
</p>
`
: nothing}
<h3 class="mt-2">Archived On:</h3>
<p>${dateStr}</p>
${domain
@@ -301,8 +299,12 @@ export class RWPEmbedReceipt extends LitElement {
: html` <p>Not Available</p> `}
<h3 class="mt-2">Package Hash:</h3>
<p class="show-hash">${datapackageHash}</p>
<h3 class="mt-2">Size</h3>
<p>${prettyBytes(Number(this.collInfo.size || 0))}</p>
${this.collInfo?.size != null
? html`
<h3 class="mt-2">Size</h3>
<p>${prettyBytes(Number(this.collInfo.size || 0))}</p>
`
: nothing}
</div>
${sourceUrl ? html`` : ""}
<p
@@ -314,13 +316,16 @@ export class RWPEmbedReceipt extends LitElement {
class="has-text-black"
target="_blank"
href="https://github.com/webrecorder/replayweb.page"
>
<fa-icon
class="menu-logo mr-1"
size="1.0rem"
aria-hidden="true"
.svg=${this.appLogo}
></fa-icon>
>${this.appLogo
? html`
<fa-icon
class="menu-logo mr-1"
size="1.0rem"
aria-hidden="true"
.svg=${this.appLogo}
></fa-icon>
`
: nothing}
Powered by ReplayWeb.page
</a>
</span>
+84 -81
View File
@@ -1,96 +1,77 @@
import { LitElement, html, css } from "lit";
import { LitElement, html, css, TemplateResult } from "lit";
import { ifDefined } from "lit/directives/if-defined.js";
import { wrapCss, rwpLogo } from "./misc";
import { SWManager } from "./swmanager";
import { property } from "lit/decorators.js";
var scriptSrc = document.currentScript && document.currentScript.src;
const scriptSrc =
document.currentScript && (document.currentScript as HTMLScriptElement).src;
var defaultReplayFile = "";
let defaultReplayFile = "";
const DEFAULT_REPLAY_BASE = "https://replayweb.page/";
// ===========================================================================
class Embed extends LitElement {
constructor() {
super();
this.replaybase = "./replay/";
this.replayfile = defaultReplayFile;
// eslint-disable-next-line no-undef
this.swName = __SW_NAME__;
this.mainElementName = "replay-app-main";
this.appName = "ReplayWeb.page";
this.view = "replay";
this.ts = "";
this.url = "";
this.query = "";
this.config = "";
this.customConfig = null;
this.coll = "";
this.paramString = null;
this.deepLink = false;
this.newWindowBase = "";
this.inited = false;
this.embed = null;
this.reloadCount = 0;
this.sandbox = false;
this.noWebWorker = false;
this.noCache = false;
// deprecated;
this.noSandbox = null;
this.logo = rwpLogo;
this.loading = "";
this.useRuffle = false;
}
@property({ type: String }) url = "";
@property({ type: String }) ts = "";
@property({ type: String }) query = "";
@property({ type: String }) source;
@property({ type: String }) src;
@property({ type: String }) view = "replay";
@property({ type: String }) embed: string | null = null;
@property({ type: String }) replaybase = "./replay/";
@property({ type: String }) swName = __SW_NAME__;
@property({ type: String }) title!: string;
@property({ type: String }) coll = "";
@property({ type: String }) config = "";
@property({ type: Boolean }) inited = false;
@property({ type: String }) paramString: string | null = null;
@property({ type: String }) hashString: string | undefined;
@property({ type: Boolean }) deepLink = false;
@property({ type: Boolean }) sandbox = false;
@property({ type: Boolean }) noSandbox: boolean | null = null;
@property({ type: Boolean }) noWebWorker = false;
@property({ type: Boolean }) noCache = false;
@property({ type: Boolean }) hideOffscreen: boolean | undefined;
@property({ type: String }) newWindowBase = "";
@property({ type: String }) errorMessage:
| ""
| TemplateResult<1>
| string
| undefined;
@property({ type: Boolean }) requireSubdomainIframe;
@property({ type: String }) loading = "";
@property({ type: Boolean }) useRuffle = false;
replayfile = defaultReplayFile;
mainElementName = "replay-app-main";
appName = "ReplayWeb.page";
customConfig = null;
reloadCount = 0;
logo = rwpLogo;
isCrossOrigin: boolean | undefined;
swmanager: SWManager | undefined;
static setDefaultReplayFile(replayfile) {
defaultReplayFile = replayfile;
}
static get properties() {
return {
url: { type: String },
ts: { type: String },
query: { type: String },
source: { type: String },
src: { type: String },
view: { type: String },
embed: { type: String },
replaybase: { type: String },
swName: { type: String },
title: { type: String },
coll: { type: String },
config: { type: String },
inited: { type: Boolean },
paramString: { type: String },
hashString: { type: String },
deepLink: { type: Boolean },
sandbox: { type: Boolean },
noSandbox: { type: Boolean },
noWebWorker: { type: Boolean },
noCache: { type: Boolean },
hideOffscreen: { type: Boolean },
newWindowBase: { type: String },
errorMessage: { type: String },
requireSubdomainIframe: { type: Boolean },
loading: { type: String },
useRuffle: { type: Boolean },
};
}
async doRegister() {
const replaybaseURL = new URL(this.replaybase, window.location.href);
@@ -168,6 +149,7 @@ class Embed extends LitElement {
// likely safari < 16, don't use web workers due to issues with split storage state
if (
// @ts-expect-error - TS2339 - Property 'GestureEvent' does not exist on type 'Window & typeof globalThis'.
window.GestureEvent !== undefined &&
window.SharedWorker === undefined
) {
@@ -184,15 +166,19 @@ class Embed extends LitElement {
const qs = new URLSearchParams(window.location.hash.slice(1));
if (qs.has("url")) {
// @ts-expect-error - TS2339 - Property 'url' does not exist on type 'Embed'.
this.url = qs.get("url");
}
if (qs.has("ts")) {
// @ts-expect-error - TS2339 - Property 'ts' does not exist on type 'Embed'.
this.ts = qs.get("ts");
}
if (qs.has("query")) {
// @ts-expect-error - TS2339 - Property 'query' does not exist on type 'Embed'.
this.query = qs.get("query");
}
if (qs.has("view")) {
// @ts-expect-error - TS2339 - Property 'view' does not exist on type 'Embed'.
this.view = qs.get("view");
}
}
@@ -203,6 +189,7 @@ class Embed extends LitElement {
}
if (this.config) {
// @ts-expect-error - TS2339 - Property 'customConfig' does not exist on type 'Embed'. | TS2339 - Property 'config' does not exist on type 'Embed'.
const config = { ...this.customConfig, ...JSON.parse(this.config) };
return JSON.stringify(config);
} else {
@@ -229,7 +216,20 @@ class Embed extends LitElement {
const config = this.mergeConfigs();
const params = {
const params: {
source: URL;
customColl: string;
config: string;
basePageUrl: string;
baseUrlSourcePrefix: string;
embed: string;
noWebWorker?: "1";
noCache?: "1";
hideOffscreen?: "1";
loading?: "eager";
swName?: string;
ruffle?: "1";
} = {
source,
customColl: this.coll,
config,
@@ -258,7 +258,6 @@ class Embed extends LitElement {
params.loading = "eager";
}
// eslint-disable-next-line no-undef
if (this.swName !== __SW_NAME__) {
params.swName = this.swName;
}
@@ -267,7 +266,10 @@ class Embed extends LitElement {
params.ruffle = "1";
}
this.paramString = new URLSearchParams(params).toString();
this.paramString = new URLSearchParams(
// Converting to unknown here so that we can ignore the URL -> string conversion necessary for the types to work out
params as unknown as Record<string, string>,
).toString();
this.hashString = new URLSearchParams({
url: this.url,
@@ -317,7 +319,8 @@ class Embed extends LitElement {
allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts\
allow-same-origin allow-forms"
: undefined,
)}"
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- the typedef for the `sandbox` attribute here is incorrect, it doesn't support multiple values
) as any}"
@load="${this.onLoad}"
src="${this.replaybase}${this.replayfile}?${this
.paramString}#${this.hashString}"
+61 -31
View File
@@ -7,9 +7,13 @@ import fabGoogleDrive from "@fortawesome/fontawesome-free/svgs/brands/google-dri
class GDrive extends LitElement {
constructor() {
super();
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'.
this.state = "trypublic";
// @ts-expect-error - TS2339 - Property 'sourceUrl' does not exist on type 'GDrive'.
this.sourceUrl = "";
// @ts-expect-error - TS2339 - Property 'scriptLoaded' does not exist on type 'GDrive'.
this.scriptLoaded = false;
// @ts-expect-error - TS2339 - Property 'error' does not exist on type 'GDrive'.
this.error = false;
}
@@ -24,10 +28,13 @@ class GDrive extends LitElement {
updated(changedProperties) {
if (changedProperties.has("sourceUrl")) {
// @ts-expect-error - TS2339 - Property 'error' does not exist on type 'GDrive'.
this.error = false;
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'.
this.state = "trypublic";
this.tryPublicAccess().then((result) => {
if (!result) {
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'.
this.state = "tryauto";
this.requestUpdate();
}
@@ -37,17 +44,19 @@ class GDrive extends LitElement {
async tryPublicAccess() {
try {
// @ts-expect-error - TS2339 - Property 'sourceUrl' does not exist on type 'GDrive'.
const sourceUrl = this.sourceUrl;
const fileId = sourceUrl.slice("googledrive://".length);
// eslint-disable-next-line no-undef
const publicCheckUrl = `${__HELPER_PROXY__}/g/${fileId}`;
let resp = null;
try {
// @ts-expect-error - TS2322 - Type 'Response' is not assignable to type 'null'.
resp = await fetch(publicCheckUrl);
} catch (e) {
return false;
}
// @ts-expect-error - TS2531 - Object is possibly 'null'.
const json = await resp.json();
if (!json.url || !json.name || !json.size) {
return false;
@@ -63,8 +72,10 @@ class GDrive extends LitElement {
try {
const abort = new AbortController();
const signal = abort.signal;
// @ts-expect-error - TS2322 - Type 'Response' is not assignable to type 'null'.
resp = await fetch(publicUrl, { signal });
abort.abort();
// @ts-expect-error - TS2531 - Object is possibly 'null'.
if (resp.status != 200) {
return false;
}
@@ -88,10 +99,13 @@ class GDrive extends LitElement {
}
onLoad() {
// @ts-expect-error - TS2339 - Property 'scriptLoaded' does not exist on type 'GDrive'.
this.scriptLoaded = true;
this.gauth("none", (response) => {
if (response.error) {
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'.
if (this.state !== "implicitonly") {
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'.
this.state = "trymanual";
}
} else {
@@ -109,6 +123,7 @@ class GDrive extends LitElement {
}
async authed(response) {
// @ts-expect-error - TS2339 - Property 'sourceUrl' does not exist on type 'GDrive'.
const sourceUrl = this.sourceUrl;
const fileId = sourceUrl.slice("googledrive://".length);
const metadataUrl = `https://www.googleapis.com/drive/v3/files/${fileId}`;
@@ -121,13 +136,17 @@ class GDrive extends LitElement {
);
if (resp.status === 404 || resp.status == 403) {
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'.
if (this.state !== "implicitonly") {
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'.
this.state = "trymanual";
}
// @ts-expect-error - TS2339 - Property 'error' does not exist on type 'GDrive'.
this.error = true;
return;
}
// @ts-expect-error - TS2339 - Property 'error' does not exist on type 'GDrive'.
this.error = false;
const metadata = await resp.json();
@@ -147,38 +166,48 @@ class GDrive extends LitElement {
render() {
return html` ${this.script()}
${this.state !== "trymanual"
? html` <p>Connecting to Google Drive...</p> `
: html`
${this.error
? html`
<div class="error has-text-danger">
<p>
${this.reauth
? "Some resources are loaded on demand from Google Drive, which requires reauthorization."
: "Could not access this file with the current Google Drive account."}
</p>
<p>
If you have multiple Google Drive accounts, be sure to
select the correct one.
</p>
</div>
<br />
`
: ""}
<button
class="button is-warning is-rounded"
@click="${this.onClickAuth}"
>
<span class="icon"
><fa-icon .svg="${fabGoogleDrive}"></fa-icon
></span>
<span>Authorize Google Drive</span>
</button>
`}`;
${
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'.
this.state !== "trymanual"
? html` <p>Connecting to Google Drive...</p> `
: html`
${
// @ts-expect-error - TS2339 - Property 'error' does not exist on type 'GDrive'.
this.error
? html`
<div class="error has-text-danger">
<p>
${
// @ts-expect-error - TS2339 - Property 'reauth' does not exist on type 'GDrive'.
this.reauth
? "Some resources are loaded on demand from Google Drive, which requires reauthorization."
: "Could not access this file with the current Google Drive account."
}
</p>
<p>
If you have multiple Google Drive accounts, be sure to
select the correct one.
</p>
</div>
<br />
`
: ""
}
<button
class="button is-warning is-rounded"
@click="${this.onClickAuth}"
>
<span class="icon"
><fa-icon .svg="${fabGoogleDrive}"></fa-icon
></span>
<span>Authorize Google Drive</span>
</button>
`
}`;
}
script() {
// @ts-expect-error - TS2339 - Property 'state' does not exist on type 'GDrive'. | TS2339 - Property 'scriptLoaded' does not exist on type 'GDrive'.
if (this.state === "trypublic" || this.scriptLoaded) {
return html``;
}
@@ -189,10 +218,11 @@ class GDrive extends LitElement {
}
gauth(prompt, callback) {
// @ts-expect-error - TS2339 - Property 'gapi' does not exist on type 'Window & typeof globalThis'.
self.gapi.load("auth2", () => {
// @ts-expect-error - TS2339 - Property 'gapi' does not exist on type 'Window & typeof globalThis'.
self.gapi.auth2.authorize(
{
// eslint-disable-next-line no-undef
client_id: __GDRIVE_CLIENT_ID__,
scope: "https://www.googleapis.com/auth/drive.file",
response_type: "token",
+12 -1
View File
@@ -1,2 +1,13 @@
declare module "*.svg";
declare let __SW_NAME__: string;
declare const __SW_NAME__: string;
declare const __HELPER_PROXY__: string;
declare const __GDRIVE_CLIENT_ID__: string;
declare const __VERSION__: string;
// showOpenFilePicker doesn't yet exist in Typescript's DOM lib
// see https://developer.mozilla.org/en-US/docs/Web/API/Window/showOpenFilePicker for details
interface Window {
showOpenFilePicker: (options?: {
types: { description: string; accept: Record<string, string[]> }[];
}) => Promise<[FileSystemFileHandle]>;
}
+4
View File
@@ -20,12 +20,15 @@ class ItemIndex extends LitElement {
query = "";
@property({ type: Array })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
filteredItems: any[] = [];
@property({ type: Array })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
sortedItems: any[] | null = null;
@property({ type: Boolean })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
hideHeader: any = null;
@property({ type: String })
@@ -35,6 +38,7 @@ class ItemIndex extends LitElement {
headerName = "Loaded Archives";
@state()
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
private _deleting: any = {};
private typeFilter = "";
+48 -24
View File
@@ -48,16 +48,36 @@ import fasAngleLeft from "@fortawesome/fontawesome-free/svgs/solid/angle-left.sv
import fasAngleRight from "@fortawesome/fontawesome-free/svgs/solid/angle-right.svg";
import fasCaretDown from "@fortawesome/fontawesome-free/svgs/solid/caret-down.svg";
import { RWPEmbedReceipt } from "./embed-receipt.js";
import { RWPEmbedReceipt } from "./embed-receipt";
import Split from "split.js";
import type { Item as ItemInfo } from "./types";
import type { Replay } from "./replay";
import { ifDefined } from "lit/directives/if-defined.js";
import "./item-info";
const RWP_SCHEME = "search://";
export type LoadInfo = {
extraConfig?: {
baseUrlSourcePrefix?: unknown;
baseUrl?: unknown;
headers?: unknown;
recording?: unknown;
};
customColl?: string | null;
noWebWorker?: boolean;
noCache?: boolean;
hideOffscreen?: boolean;
loadEager?: boolean;
sourceUrl?: string;
loadUrl?: string;
swError?: string;
newFullImport?: unknown;
name?: string;
};
// ===========================================================================
class Item extends LitElement {
@property({ type: Boolean })
@@ -67,7 +87,7 @@ class Item extends LitElement {
sourceUrl: string | null = null;
@property({ type: Object, attribute: false })
loadInfo: any;
loadInfo: LoadInfo | null = null;
@property({ type: Boolean })
showSidebar: boolean | null = null;
@@ -142,9 +162,9 @@ class Item extends LitElement {
autoUpdateInterval = 10;
@property({ type: String })
swName: any = null;
swName: string | null = null;
private splitter: any = null;
private splitter: Split.Instance | null = null;
private _replaceLoc = false;
private _locUpdateNeeded = false;
@@ -224,7 +244,7 @@ class Item extends LitElement {
this.updateTabData({ multiTs: json.timestamps });
}
willUpdate(changedProperties: Map<string, any>) {
willUpdate(changedProperties: Map<string, Record<string, unknown>>) {
if (changedProperties.has("tabData") && this.tabData) {
// Format tab data from URL query params
const tabData = {};
@@ -266,7 +286,9 @@ class Item extends LitElement {
if (!this.itemInfo || !this.itemInfo.coll) {
return;
}
const newHash = "#" + new URLSearchParams(this.tabData as any).toString();
const newHash =
"#" +
new URLSearchParams(this.tabData as Record<string, string>).toString();
if (!this.tabData.url) {
this.url =
@@ -338,7 +360,7 @@ class Item extends LitElement {
},
};
this.splitter = Split([contents as any, replay], opts);
this.splitter = Split([contents, replay], opts);
}
} else if (this.splitter) {
try {
@@ -850,6 +872,7 @@ class Item extends LitElement {
if (!isReplay && this.tabData && this.tabData.view) {
const detail = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
title: (this.tabLabels as any)[this.tabData.view],
replayTitle: false,
};
@@ -866,7 +889,7 @@ class Item extends LitElement {
return html` <wr-loader
.loadInfo="${this.loadInfo}"
embed="${this.embed || ""}"
swName="${this.swName}"
swName="${ifDefined(this.swName === null ? undefined : this.swName)}"
.coll="${this.item}"
sourceUrl="${this.sourceUrl || ""}"
@coll-loaded=${this.onItemLoaded}
@@ -891,7 +914,7 @@ class Item extends LitElement {
: isReplay
? "is-hidden"
: "full-pages"}"
role="${(isSidebar ? "complementary" : "") as any}"
role="${ifDefined(isSidebar ? "complementary" : undefined)}"
aria-label="${isSidebar ? "Browse Contents" : ""}"
>
${this.renderTabHeader(isSidebar)}
@@ -961,9 +984,9 @@ class Item extends LitElement {
href="#story"
class="is-size-6"
aria-label="Story"
aria-current="${(this.tabData.view === "story"
? "location"
: "") as any}"
aria-current="${ifDefined(
this.tabData.view === "story" ? "location" : undefined,
)}"
>
<span class="icon"
><fa-icon
@@ -987,9 +1010,9 @@ class Item extends LitElement {
href="#pages"
class="is-size-6"
aria-label="Pages"
aria-current="${(this.tabData.view === "pages"
? "location"
: "") as any}"
aria-current="${ifDefined(
this.tabData.view === "pages" ? "location" : undefined,
)}"
>
<span class="icon"
><fa-icon
@@ -1012,9 +1035,9 @@ class Item extends LitElement {
href="#resources"
class="is-size-6"
aria-label="URLs"
aria-current="${(this.tabData.view === "resources"
? "location"
: "") as any}"
aria-current="${ifDefined(
this.tabData.view === "resources" ? "location" : undefined,
)}"
>
<span class="icon"
><fa-icon
@@ -1513,7 +1536,7 @@ class Item extends LitElement {
id="story"
.isSidebar="${isSidebar}"
class="${isStory ? "" : "is-hidden"} ${isSidebar ? "sidebar" : ""}"
role="${(isSidebar ? "" : "main") as any}"
role="${ifDefined(isSidebar ? undefined : "main")}"
>
</wr-coll-story>`
: ""}
@@ -1530,7 +1553,7 @@ class Item extends LitElement {
class="is-paddingless ${isResources ? "" : "is-hidden"} ${isSidebar
? "sidebar"
: ""}"
role="${(isSidebar ? "" : "main") as any}"
role="${ifDefined(isSidebar ? undefined : "main")}"
>
</wr-coll-resources>`
: ""}
@@ -1548,7 +1571,7 @@ class Item extends LitElement {
id="pages"
@coll-update="${this.onItemUpdate}"
class="${isPages ? "" : "is-hidden"} ${isSidebar ? "sidebar" : ""}"
role="${(isSidebar ? "" : "main") as any}"
role="${ifDefined(isSidebar ? undefined : "main")}"
>
</wr-page-view>`
: ""}
@@ -1738,6 +1761,7 @@ class Item extends LitElement {
_stringToParams(value) {
const q = new URLSearchParams(value.slice(RWP_SCHEME.length));
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
const data: any = {};
data.url = "";
data.ts = "";
@@ -1757,7 +1781,7 @@ class Item extends LitElement {
return data;
}
_paramsToString(value) {
_paramsToString(value: Record<string, unknown>) {
const q = new URLSearchParams();
for (const param of [
@@ -1768,14 +1792,14 @@ class Item extends LitElement {
"urlSearchType",
]) {
if (param in value) {
q.set(param, value[param]);
q.set(param, String(value[param]));
}
}
return q.toString();
}
onRefresh(event, replayOnly = false) {
onRefresh(event: Event | null, replayOnly = false) {
if (event) {
event.preventDefault();
}
+50 -54
View File
@@ -4,52 +4,36 @@ import { wrapCss } from "./misc";
import prettyBytes from "pretty-bytes";
import { parseURLSchemeHostPath } from "./pageutils";
import { property } from "lit/decorators.js";
import { LoadInfo } from "./item";
// ===========================================================================
class Loader extends LitElement {
constructor() {
super();
this.progress = 0;
this.total = 0;
this.percent = 0;
this.coll = "";
this.state = "waiting";
this.loadInfo = null;
@property({ type: String }) sourceUrl?: string;
@property({ type: Object }) loadInfo: LoadInfo | null = null;
@property({ type: String }) state = "waiting";
@property({ type: Number }) progress = 0;
@property({ type: Number }) percent = 0;
@property({ type: Number }) currentSize = 0;
@property({ type: Number }) totalSize = 0;
@property({ type: String }) error?: string;
@property({ type: Number }) total = 0;
@property({ type: String }) status?: string;
@property({ type: String }) coll = "";
@property({ type: String }) embed?: string;
@property({ type: Boolean }) tryFileHandle = !!window.showOpenFilePicker;
@property({ type: Boolean }) errorAllowRetry = false;
@property({ type: String }) extraMsg?: string;
@property({ type: String }) swName?: string;
this.currentSize = 0;
this.totalSize = 0;
pingInterval: number | NodeJS.Timer = 0;
fileHandle: FileSystemHandle | null = null;
noWebWorker = false;
worker?: Worker | null;
this.tryFileHandle = !!window.showOpenFilePicker;
this.fileHandle = null;
this.errorAllowRetry = false;
this.pingInterval = 0;
this.noWebWorker = false;
}
static get properties() {
return {
sourceUrl: { type: String },
loadInfo: { type: Object },
state: { type: String },
progress: { type: Number },
percent: { type: Number },
currentSize: { type: Number },
totalSize: { type: Number },
error: { type: String },
total: { type: Number },
status: { type: String },
coll: { type: String },
embed: { type: String },
tryFileHandle: { type: Boolean },
errorAllowRetry: { type: Boolean },
extraMsg: { type: String },
swName: { type: String },
};
}
// Google Drive
_gdWait?: Promise<LoadInfo>;
_gdResolve!: (value: LoadInfo | PromiseLike<LoadInfo>) => void;
firstUpdated() {
this.initMessages();
@@ -57,17 +41,17 @@ class Loader extends LitElement {
}
initMessages() {
this.noWebWorker = this.loadInfo && this.loadInfo.noWebWorker;
this.noWebWorker = Boolean(this.loadInfo && this.loadInfo.noWebWorker);
if (!this.noWebWorker) {
// eslint-disable-next-line no-undef
this.worker = new Worker(this.swName);
this.worker = new Worker(this.swName!);
} else {
if (!navigator.serviceWorker) {
return;
}
this.worker = navigator.serviceWorker;
// TODO figure out if this is okay?
this.worker = navigator.serviceWorker as unknown as Worker;
}
this.worker.addEventListener("message", (event) => {
@@ -110,7 +94,7 @@ class Loader extends LitElement {
);
if (!this.noWebWorker) {
this.worker.terminate();
this.worker?.terminate();
} else {
if (this.pingInterval) {
clearInterval(this.pingInterval);
@@ -125,7 +109,7 @@ class Loader extends LitElement {
async doLoad() {
let sourceUrl = this.sourceUrl;
let source = null;
let source: LoadInfo | null = null;
this.percent = this.currentSize = this.totalSize = 0;
@@ -145,7 +129,7 @@ class Loader extends LitElement {
switch (scheme) {
case "googledrive":
this.state = "googledrive";
source = await this.googledriveInit();
source = (await this.googledriveInit()) ?? null;
break;
case "s3":
@@ -170,7 +154,7 @@ You can select a file to upload from the main page by clicking the 'Choose File.
break;
case "proxy":
sourceUrl = "proxy:" + sourceUrl.slice("proxy://".length);
sourceUrl = "proxy:" + sourceUrl!.slice("proxy://".length);
break;
}
} catch (e) {
@@ -184,7 +168,7 @@ You can select a file to upload from the main page by clicking the 'Choose File.
this.state = "started";
let type = undefined;
let extraConfig = undefined;
let extraConfig: LoadInfo["extraConfig"] = undefined;
if (this.loadInfo) {
source.newFullImport = this.loadInfo.newFullImport;
@@ -196,10 +180,11 @@ You can select a file to upload from the main page by clicking the 'Choose File.
}
// todo: too special case?
if (
sourceUrl.startsWith("proxy:") &&
sourceUrl!.startsWith("proxy:") &&
extraConfig &&
extraConfig.recording
) {
// @ts-expect-error - TS2322 - Type '"recordingproxy"' is not assignable to type 'undefined'.
type = "recordingproxy";
}
}
@@ -216,6 +201,7 @@ You can select a file to upload from the main page by clicking the 'Choose File.
if (!navigator.serviceWorker.controller) {
await new Promise((resolve) => {
navigator.serviceWorker.addEventListener("controllerchange", () =>
// @ts-expect-error - TS2794 - Expected 1 arguments, but got 0. Did you forget to include 'void' in your type argument to 'Promise'?
resolve(),
);
});
@@ -225,11 +211,13 @@ You can select a file to upload from the main page by clicking the 'Choose File.
if (!this.noWebWorker) {
this.worker.postMessage(msg);
} else {
// @ts-expect-error - TS2531 - Object is possibly 'null'.
navigator.serviceWorker.controller.postMessage(msg);
// ping service worker with messages to avoid shutdown while loading
// (mostly for Firefox)
this.pingInterval = setInterval(() => {
// @ts-expect-error - TS2531 - Object is possibly 'null'.
navigator.serviceWorker.controller.postMessage({ msg_type: "ping" });
}, 15000);
}
@@ -350,7 +338,7 @@ You can select a file to upload from the main page by clicking the 'Choose File.
switch (this.state) {
case "googledrive":
return html`<wr-gdrive
.sourceUrl=${this.sourceUrl}
.sourceUrl=${this.sourceUrl!}
@load-ready=${this.onLoadReady}
></wr-gdrive>`;
@@ -363,10 +351,15 @@ You can select a file to upload from the main page by clicking the 'Choose File.
max="100"
></progress>
<label class="progress-label" for="progress">${this.percent}%</label>
${this.currentSize && this.totalSize
? html` <div class="loaded-prog">
Loaded <b>${prettyBytes(this.currentSize)}</b> of
Loaded
<b>${prettyBytes(this.currentSize)}</b>
of
<b>${prettyBytes(this.totalSize)}</b>
${this.extraMsg &&
html` <p class="extra-msg">(${this.extraMsg})</p> `}
</div>`
@@ -417,7 +410,10 @@ You can select a file to upload from the main page by clicking the 'Choose File.
}
async onAskPermission() {
const result = await this.fileHandle.requestPermission({ mode: "read" });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = await (this.fileHandle as any)?.requestPermission({
mode: "read",
});
if (result === "granted") {
this.doLoad();
}
+33 -4
View File
@@ -4,6 +4,7 @@ import { LitElement, html, css, unsafeCSS } from "lit";
import { unsafeSVG } from "lit/directives/unsafe-svg.js";
import { styleMap } from "lit/directives/style-map.js";
// @ts-expect-error - TS2307 - Cannot find module '../assets/main.scss' or its corresponding type declarations.
import allCssRaw from "../assets/main.scss";
import rwpLogo from "../assets/logo.svg";
@@ -18,11 +19,12 @@ function wrapCss(custom) {
}
const IS_APP =
// @ts-expect-error - TS2339 - Property 'IS_APP' does not exist on type 'Window & typeof globalThis'.
window.IS_APP ||
// @ts-expect-error - TS2551 - Property 'electron' does not exist on type 'Window & typeof globalThis'. Did you mean 'Electron'? | TS2551 - Property 'electron' does not exist on type 'Window & typeof globalThis'. Did you mean 'Electron'?
(window.electron && window.electron.IS_APP) ||
window.matchMedia("(display-mode: standalone)").matches;
// eslint-disable-next-line no-undef
const VERSION = __VERSION__;
// ===========================================================================
@@ -39,8 +41,11 @@ function clickOnSpacebarPress(event) {
class FaIcon extends LitElement {
constructor() {
super();
// @ts-expect-error - TS2339 - Property 'size' does not exist on type 'FaIcon'.
this.size = "1.1em";
// @ts-expect-error - TS2339 - Property 'width' does not exist on type 'FaIcon'.
this.width = null;
// @ts-expect-error - TS2339 - Property 'height' does not exist on type 'FaIcon'.
this.height = null;
}
@@ -70,26 +75,39 @@ class FaIcon extends LitElement {
}
render() {
// @ts-expect-error - TS2339 - Property 'svg' does not exist on type 'FaIcon'.
if (!this.svg) {
return html``;
}
const styles = {};
// @ts-expect-error - TS2339 - Property 'size' does not exist on type 'FaIcon'.
if (this.size) {
// @ts-expect-error - TS2339 - Property 'width' does not exist on type '{}'. | TS2339 - Property 'size' does not exist on type 'FaIcon'.
styles.width = this.size;
// @ts-expect-error - TS2339 - Property 'height' does not exist on type '{}'. | TS2339 - Property 'size' does not exist on type 'FaIcon'.
styles.height = this.size;
} else {
// @ts-expect-error - TS2339 - Property 'width' does not exist on type 'FaIcon'.
if (this.width) {
// @ts-expect-error - TS2339 - Property 'width' does not exist on type '{}'. | TS2339 - Property 'width' does not exist on type 'FaIcon'.
styles.width = this.width;
}
// @ts-expect-error - TS2339 - Property 'height' does not exist on type 'FaIcon'.
if (this.height) {
// @ts-expect-error - TS2339 - Property 'height' does not exist on type '{}'. | TS2339 - Property 'height' does not exist on type 'FaIcon'.
styles.height = this.height;
}
}
return html`<svg style="${styleMap(styles)}">
<g>${unsafeSVG(this.svg)}</g>
<g>
${
// @ts-expect-error - TS2339 - Property 'svg' does not exist on type 'FaIcon'.
unsafeSVG(this.svg)
}
</g>
</svg>`;
}
}
@@ -98,6 +116,7 @@ class FaIcon extends LitElement {
class AnimLogo extends FaIcon {
constructor() {
super();
// @ts-expect-error - TS2339 - Property 'svg' does not exist on type 'AnimLogo'.
this.svg = rwpLogo;
}
@@ -155,7 +174,9 @@ class WrModal extends LitElement {
constructor() {
super();
this.title = "";
// @ts-expect-error - TS2339 - Property 'bgClass' does not exist on type 'WrModal'.
this.bgClass = "";
// @ts-expect-error - TS2339 - Property 'noBgClose' does not exist on type 'WrModal'.
this.noBgClose = false;
}
@@ -188,10 +209,18 @@ class WrModal extends LitElement {
return html` <div class="modal is-active">
<div
class="modal-background"
@click="${() => !this.noBgClose && this.onClose()}"
@click="${
// @ts-expect-error - TS2339 - Property 'noBgClose' does not exist on type 'WrModal'.
() => !this.noBgClose && this.onClose()
}"
></div>
<div class="modal-card">
<header class="modal-card-head ${this.bgClass}">
<header
class="modal-card-head ${
// @ts-expect-error - TS2339 - Property 'bgClass' does not exist on type 'WrModal'.
this.bgClass
}"
>
<p class="modal-card-title is-3">${this.title}</p>
<button
class="delete"
+2 -1
View File
@@ -18,6 +18,7 @@ class PageEntry extends LitElement {
textSnippet: string | null = "";
@property({ type: Object })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
page: any = null;
@property({ type: String })
@@ -77,7 +78,7 @@ class PageEntry extends LitElement {
width: 100%;
}
/* Overrde Bulma to add the tiniest margin, so the focus indicator isn't obscured */
/* Override Bulma to add the tiniest margin, so the focus indicator isn't obscured */
.columns {
margin-top: calc(-0.75rem + 2px);
}
+16
View File
@@ -20,21 +20,26 @@ import type { PageEntry } from "./pageentry";
// ===========================================================================
class Pages extends LitElement {
@property({ type: Array })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
filteredPages: any[] = [];
@property({ type: Array })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
sortedPages: any[] = [];
@property({ type: String })
query = "";
@property()
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
flex: any = null;
@property()
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
textPages: any = null;
@property()
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
newQuery: any = null;
@property({ type: Boolean })
@@ -83,15 +88,19 @@ class Pages extends LitElement {
ts = "";
@property({ type: Boolean })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
editing: any = false;
@property({ type: Object })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
toDeletePages: any = null;
@property({ type: Object })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
toDeletePage: any = null;
@property({ type: Object })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
collInfo: any;
@property({ type: Boolean })
@@ -100,6 +109,7 @@ class Pages extends LitElement {
@property({ type: String })
defaultKey = "";
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
private _ival: any;
static get sortKeys() {
@@ -127,6 +137,7 @@ class Pages extends LitElement {
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
async updated(changedProperties: Map<string, any>) {
if (changedProperties.has("collInfo")) {
this.updateTextSearch();
@@ -154,7 +165,9 @@ class Pages extends LitElement {
}
const sorter = this.renderRoot.querySelector("wr-sorter") as Sorter;
if (sorter) {
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
sorter.sortKey = this.sortKey;
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
sorter.sortDesc = this.sortDesc;
}
}
@@ -168,6 +181,7 @@ class Pages extends LitElement {
block: "nearest",
inline: "nearest",
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
setTimeout(() => selected.scrollIntoView(opts as any), 100);
}
//}
@@ -175,6 +189,7 @@ class Pages extends LitElement {
}
onChangeQuery(event: Event) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
this.newQuery = (event.currentTarget as any).value;
//this.loading = true;
if (this._ival) {
@@ -280,6 +295,7 @@ class Pages extends LitElement {
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
const lines: any[] = [];
for await (const line of ndjson(resp.body!.getReader())) {
+8 -2
View File
@@ -10,6 +10,7 @@ class Replay extends LitElement {
collInfo: Item | Record<string, never> | null = null;
@property({ type: String })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
sourceUrl: any = null;
// external url set from parent
@@ -33,12 +34,14 @@ class Replay extends LitElement {
title = "";
@property({ type: String })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
iframeUrl: any = null;
@property({ type: Boolean })
showAuth = false;
@property({ type: Object })
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
authFileHandle: any = null;
private reauthWait: null | Promise<void> = null;
@@ -161,7 +164,8 @@ class Replay extends LitElement {
}
}
setDisablePointer(disable) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
setDisablePointer(disable: any) {
const iframe = this.renderRoot.querySelector("iframe");
if (iframe) {
@@ -169,7 +173,8 @@ class Replay extends LitElement {
}
}
onReplayMessage(event) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
onReplayMessage(event: any) {
const iframe = this.renderRoot.querySelector("iframe");
if (iframe && event.source === iframe.contentWindow) {
@@ -237,6 +242,7 @@ class Replay extends LitElement {
!iframe.contentDocument ||
!iframe.contentWindow ||
(iframe.contentDocument.readyState === "complete" &&
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
!(iframe.contentWindow as Window & { _WBWombat: any })._WBWombat)
) {
this.clearLoading(iframe && iframe.contentWindow);
-153
View File
@@ -1,153 +0,0 @@
import { LitElement, html, css } from "lit";
import { wrapCss } from "./misc";
import fasSortDown from "@fortawesome/fontawesome-free/svgs/solid/sort-down.svg";
import fasSortUp from "@fortawesome/fontawesome-free/svgs/solid/sort-up.svg";
// ===========================================================================
/**
* @typedef {{key: string;name: string;}[]} SortKeys
* @prop {SortKeys} sortKeys
*/
class Sorter extends LitElement {
constructor() {
super();
this.sortedData = [];
this.data = [];
this.pageResults = 0;
this.numResults = 0;
this.sortKey = null;
this.sortDesc = null;
}
static get properties() {
return {
id: { type: String },
pageResults: { type: Number },
data: { type: Array },
sortedData: { type: Array },
sortKey: { type: String },
sortDesc: { type: Boolean },
};
}
firstUpdated() {
if (this.id) {
const sortKey = localStorage.getItem(`${this.id}:sortKey`);
if (sortKey !== null) {
this.sortKey = sortKey;
}
const sortDesc = localStorage.getItem(`${this.id}:sortDesc`);
if (sortDesc !== null) {
this.sortDesc = sortDesc === "1";
}
}
}
updated(changedProperties) {
const keyChanged = changedProperties.has("sortKey");
const descChanged = changedProperties.has("sortDesc");
const dataChanged = changedProperties.has("data");
if (keyChanged && this.sortKey !== null) {
localStorage.setItem(`${this.id}:sortKey`, this.sortKey);
}
if (descChanged && this.sortDesc !== null) {
localStorage.setItem(`${this.id}:sortDesc`, this.sortDesc ? "1" : "0");
}
if (keyChanged || descChanged || dataChanged) {
this.sortData();
}
}
sortData() {
this.sortedData = [...this.data];
this.numResults = this.pageResults;
if (this.sortKey === "") {
if (this.sortDesc) {
this.sortedData.reverse();
}
} else {
this.sortedData.sort((first, second) => {
if (first[this.sortKey] === second[this.sortKey]) {
return 0;
}
return this.sortDesc == first[this.sortKey] < second[this.sortKey]
? 1
: -1;
});
}
this.sendSortChanged();
}
sendSortChanged() {
const detail = {
sortKey: this.sortKey,
sortDesc: this.sortDesc,
sortedData: this.numResults
? this.sortedData.slice(0, this.numResults)
: this.sortedData,
};
this.dispatchEvent(new CustomEvent("sort-changed", { detail }));
}
getMore(more = 100) {
if (this.pageResults && this.numResults >= this.sortedData.length) {
return;
}
this.numResults += more;
this.sendSortChanged();
}
static get styles() {
return wrapCss(css`
:host {
min-width: 100px;
box-sizing: border-box !important;
}
button.button.is-small {
border-radius: 4px;
}
`);
}
render() {
return html`
<div class="select is-small">
<select id="sort-select" @change=${(e) =>
(this.sortKey = e.currentTarget.value)}>
${this.sortKeys.map(
(sort) => html`
<option value="${sort.key}" ?selected="${sort.key === this.sortKey}">
Sort By: ${sort.name}
</option>
`,
)}
</select>
</div>
<button @click=${() =>
(this.sortDesc = !this.sortDesc)} class="button is-small">
<span>Order:</span>
<span class="is-sr-only">${
this.sortDesc ? "Ascending" : "Descending"
}</span>
<span class="icon"><fa-icon aria-hidden="true" .svg=${
this.sortDesc ? fasSortUp : fasSortDown
}></span>
</button>`;
}
}
customElements.define("wr-sorter", Sorter);
export { Sorter };
+191
View File
@@ -0,0 +1,191 @@
import { LitElement, html, css } from "lit";
import { wrapCss } from "./misc";
import fasSortDown from "@fortawesome/fontawesome-free/svgs/solid/sort-down.svg";
import fasSortUp from "@fortawesome/fontawesome-free/svgs/solid/sort-up.svg";
// ===========================================================================
class Sorter extends LitElement {
constructor() {
super();
// @ts-expect-error - TS2551 - Property 'sortedData' does not exist on type 'Sorter'. Did you mean 'sortData'?
this.sortedData = [];
// @ts-expect-error - TS2339 - Property 'data' does not exist on type 'Sorter'.
this.data = [];
// @ts-expect-error - TS2339 - Property 'pageResults' does not exist on type 'Sorter'.
this.pageResults = 0;
// @ts-expect-error - TS2339 - Property 'numResults' does not exist on type 'Sorter'.
this.numResults = 0;
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
this.sortKey = null;
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
this.sortDesc = null;
}
static get properties() {
return {
id: { type: String },
pageResults: { type: Number },
data: { type: Array },
sortedData: { type: Array },
sortKey: { type: String },
sortDesc: { type: Boolean },
};
}
firstUpdated() {
if (this.id) {
const sortKey = localStorage.getItem(`${this.id}:sortKey`);
if (sortKey !== null) {
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
this.sortKey = sortKey;
}
const sortDesc = localStorage.getItem(`${this.id}:sortDesc`);
if (sortDesc !== null) {
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
this.sortDesc = sortDesc === "1";
}
}
}
updated(changedProperties) {
const keyChanged = changedProperties.has("sortKey");
const descChanged = changedProperties.has("sortDesc");
const dataChanged = changedProperties.has("data");
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
if (keyChanged && this.sortKey !== null) {
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
localStorage.setItem(`${this.id}:sortKey`, this.sortKey);
}
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
if (descChanged && this.sortDesc !== null) {
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
localStorage.setItem(`${this.id}:sortDesc`, this.sortDesc ? "1" : "0");
}
if (keyChanged || descChanged || dataChanged) {
this.sortData();
}
}
sortData() {
// @ts-expect-error - TS2551 - Property 'sortedData' does not exist on type 'Sorter'. Did you mean 'sortData'? | TS2339 - Property 'data' does not exist on type 'Sorter'.
this.sortedData = [...this.data];
// @ts-expect-error - TS2339 - Property 'numResults' does not exist on type 'Sorter'. | TS2339 - Property 'pageResults' does not exist on type 'Sorter'.
this.numResults = this.pageResults;
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
if (this.sortKey === "") {
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
if (this.sortDesc) {
// @ts-expect-error - TS2551 - Property 'sortedData' does not exist on type 'Sorter'. Did you mean 'sortData'?
this.sortedData.reverse();
}
} else {
// @ts-expect-error - TS2551 - Property 'sortedData' does not exist on type 'Sorter'. Did you mean 'sortData'?
this.sortedData.sort((first, second) => {
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'. | TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
if (first[this.sortKey] === second[this.sortKey]) {
return 0;
}
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'. | TS2339 - Property 'sortKey' does not exist on type 'Sorter'. | TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
return this.sortDesc == first[this.sortKey] < second[this.sortKey]
? 1
: -1;
});
}
this.sendSortChanged();
}
sendSortChanged() {
const detail = {
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
sortKey: this.sortKey,
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
sortDesc: this.sortDesc,
// @ts-expect-error - TS2339 - Property 'numResults' does not exist on type 'Sorter'.
sortedData: this.numResults
? // @ts-expect-error - TS2551 - Property 'sortedData' does not exist on type 'Sorter'. Did you mean 'sortData'? | TS2339 - Property 'numResults' does not exist on type 'Sorter'.
this.sortedData.slice(0, this.numResults)
: // @ts-expect-error - TS2551 - Property 'sortedData' does not exist on type 'Sorter'. Did you mean 'sortData'?
this.sortedData,
};
this.dispatchEvent(new CustomEvent("sort-changed", { detail }));
}
getMore(more = 100) {
// @ts-expect-error - TS2339 - Property 'pageResults' does not exist on type 'Sorter'. | TS2339 - Property 'numResults' does not exist on type 'Sorter'. | TS2551 - Property 'sortedData' does not exist on type 'Sorter'. Did you mean 'sortData'?
if (this.pageResults && this.numResults >= this.sortedData.length) {
return;
}
// @ts-expect-error - TS2339 - Property 'numResults' does not exist on type 'Sorter'.
this.numResults += more;
this.sendSortChanged();
}
static get styles() {
return wrapCss(css`
:host {
min-width: 100px;
box-sizing: border-box !important;
}
button.button.is-small {
border-radius: 4px;
}
`);
}
render() {
return html`
<div class="select is-small">
<select id="sort-select" @change=${(e) =>
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
(this.sortKey = e.currentTarget.value)}>
${
// @ts-expect-error - TS2339 - Property 'sortKeys' does not exist on type 'Sorter'.
this.sortKeys.map(
(sort) => html`
<option
value="${sort.key}"
?selected="${
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'Sorter'.
sort.key === this.sortKey
}"
>
Sort By: ${sort.name}
</option>
`,
)
}
</select>
</div>
<button @click=${() =>
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'. | TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
(this.sortDesc = !this.sortDesc)} class="button is-small">
<span>Order:</span>
<span class="is-sr-only">${
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
this.sortDesc ? "Ascending" : "Descending"
}</span>
<span class="icon"><fa-icon aria-hidden="true" .svg=${
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'Sorter'.
this.sortDesc ? fasSortUp : fasSortDown
}></span>
</button>`;
}
}
customElements.define("wr-sorter", Sorter);
export { Sorter };
+88 -20
View File
@@ -13,18 +13,26 @@ class Story extends LitElement {
constructor() {
super();
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'.
this.collInfo = null;
// @ts-expect-error - TS2339 - Property 'curatedPageMap' does not exist on type 'Story'.
this.curatedPageMap = {};
// @ts-expect-error - TS2339 - Property 'currList' does not exist on type 'Story'.
this.currList = 0;
// @ts-expect-error - TS2339 - Property 'active' does not exist on type 'Story'.
this.active = false;
// @ts-expect-error - TS2339 - Property 'lastST' does not exist on type 'Story'.
this.lastST = 0;
// @ts-expect-error - TS2339 - Property 'clickTime' does not exist on type 'Story'.
this.clickTime = 0;
// @ts-expect-error - TS2339 - Property 'isSidebar' does not exist on type 'Story'.
this.isSidebar = false;
// @ts-expect-error - TS2339 - Property 'splitDirection' does not exist on type 'Story'.
this.splitDirection = false;
}
@@ -44,17 +52,21 @@ class Story extends LitElement {
}
recalcSplitter(width) {
// @ts-expect-error - TS2339 - Property 'splitDirection' does not exist on type 'Story'.
this.splitDirection =
// @ts-expect-error - TS2339 - Property 'isSidebar' does not exist on type 'Story'.
this.isSidebar || width < 769 ? "vertical" : "horizontal";
}
firstUpdated() {
this.recalcSplitter(document.documentElement.clientWidth);
// @ts-expect-error - TS2339 - Property 'obs' does not exist on type 'Story'.
this.obs = new ResizeObserver((entries /*, observer*/) => {
this.recalcSplitter(entries[0].contentRect.width);
});
// @ts-expect-error - TS2339 - Property 'obs' does not exist on type 'Story'.
this.obs.observe(this);
}
@@ -74,8 +86,10 @@ class Story extends LitElement {
this.configureSplitter();
}
// @ts-expect-error - TS2339 - Property 'active' does not exist on type 'Story'.
if (changedProperties.has("currList") && this.active) {
this.sendChangeEvent({
// @ts-expect-error - TS2339 - Property 'currList' does not exist on type 'Story'.
currList: this.currList,
});
}
@@ -85,39 +99,50 @@ class Story extends LitElement {
const sidebar = this.renderRoot.querySelector(".sidebar");
const content = this.renderRoot.querySelector(".main-content");
// @ts-expect-error - TS2339 - Property 'splitter' does not exist on type 'Story'.
if (this.splitter) {
try {
// @ts-expect-error - TS2339 - Property 'splitter' does not exist on type 'Story'.
this.splitter.destroy();
} catch (e) {
// ignore splitter destory err
}
// @ts-expect-error - TS2339 - Property 'splitter' does not exist on type 'Story'.
this.splitter = null;
}
// @ts-expect-error - TS2339 - Property 'splitter' does not exist on type 'Story'.
if (sidebar && content && !this.splitter) {
const opts = {
sizes: [20, 80],
gutterSize: 4,
// @ts-expect-error - TS2339 - Property 'splitDirection' does not exist on type 'Story'.
direction: this.splitDirection,
};
// @ts-expect-error - TS2339 - Property 'splitter' does not exist on type 'Story'. | TS2322 - Type 'Element' is not assignable to type 'string | HTMLElement'. | TS2322 - Type 'Element' is not assignable to type 'string | HTMLElement'.
this.splitter = Split([sidebar, content], opts);
}
}
async doLoadCurated() {
// @ts-expect-error - TS2339 - Property 'curatedPageMap' does not exist on type 'Story'.
this.curatedPageMap = {};
const pageMap = {};
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'.
for (const page of this.collInfo.pages) {
pageMap[page.id] = page;
}
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'.
for (const curated of this.collInfo.curatedPages) {
// @ts-expect-error - TS2339 - Property 'curatedPageMap' does not exist on type 'Story'.
if (!this.curatedPageMap[curated.list]) {
// @ts-expect-error - TS2339 - Property 'curatedPageMap' does not exist on type 'Story'.
this.curatedPageMap[curated.list] = [];
}
const page = curated;
@@ -135,6 +160,7 @@ class Story extends LitElement {
const title = page.title || page.url;
const desc = curated.desc;
// @ts-expect-error - TS2339 - Property 'curatedPageMap' does not exist on type 'Story'.
this.curatedPageMap[curated.list].push({ url, ts, title, desc });
}
@@ -249,15 +275,23 @@ class Story extends LitElement {
}
render() {
// @ts-expect-error - TS2339 - Property 'currList' does not exist on type 'Story'.
const currListNum = this.currList;
return html`
<div
class="is-sr-only"
role="heading"
aria-level="${this.isSidebar ? "2" : "1"}"
aria-level="${
// @ts-expect-error - TS2339 - Property 'isSidebar' does not exist on type 'Story'.
this.isSidebar ? "2" : "1"
}"
>
Story for ${this.collInfo.title}
Story for
${
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'.
this.collInfo.title
}
</div>
<div class="columns">
<div class="column sidebar is-one-fifth">
@@ -271,21 +305,29 @@ class Story extends LitElement {
? "is-active"
: ""} menu-label is-size-4"
@click=${this.onClickScroll}
>${this.collInfo.title}</a
>${
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'.
this.collInfo.title
}</a
>
<ul class="menu-list">
${this.collInfo.lists.map(
(list) =>
html` <li>
<a
@click=${this.onClickScroll}
href="#list-${list.id}"
data-list="${list.id}"
class="${currListNum === list.id ? "is-active" : ""}"
>${list.title}</a
>
</li>`,
)}
${
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'.
this.collInfo.lists.map(
(list) =>
html` <li>
<a
@click=${this.onClickScroll}
href="#list-${list.id}"
data-list="${list.id}"
class="${currListNum === list.id
? "is-active"
: ""}"
>${list.title}</a
>
</li>`,
)
}
</ul>
</li>
</ul>
@@ -293,8 +335,17 @@ class Story extends LitElement {
</div>
<div @scroll=${this.onScroll} class="column main-content main-scroll">
<section id="list-0" class="desc">
<h2 class="has-text-centered title is-3">${this.collInfo.title}</h2>
${this.collInfo.desc ? unsafeHTML(marked(this.collInfo.desc)) : ""}
<h2 class="has-text-centered title is-3">
${
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'.
this.collInfo.title
}
</h2>
${
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'. | TS2339 - Property 'collInfo' does not exist on type 'Story'.
this.collInfo.desc ? unsafeHTML(marked(this.collInfo.desc)) : ""
}
</section>
${this.renderLists()}
</div>
@@ -303,6 +354,7 @@ class Story extends LitElement {
}
renderLists() {
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'Story'.
return html` ${this.collInfo.lists.map(
(list) => html`
<article id="list-${list.id}">
@@ -311,9 +363,13 @@ class Story extends LitElement {
<h3>${list.title}</h3>
<p>${list.desc}</p>
<ol>
${this.curatedPageMap[list.id]
? this.curatedPageMap[list.id].map((p) => this.renderCPage(p))
: html``}
${
// @ts-expect-error - TS2339 - Property 'curatedPageMap' does not exist on type 'Story'.
this.curatedPageMap[list.id]
? // @ts-expect-error - TS2339 - Property 'curatedPageMap' does not exist on type 'Story'.
this.curatedPageMap[list.id].map((p) => this.renderCPage(p))
: html``
}
</ol>
</div>
</article>
@@ -361,6 +417,7 @@ class Story extends LitElement {
onClickScroll(event) {
event.preventDefault();
//this.pageView = false;
// @ts-expect-error - TS2339 - Property 'currList' does not exist on type 'Story'.
this.currList = Number(event.currentTarget.getAttribute("data-list"));
this.scrollToList();
return false;
@@ -368,12 +425,16 @@ class Story extends LitElement {
scrollToList() {
// lists are 1 based, 0 is header, 1 is first list
// @ts-expect-error - TS2339 - Property 'currList' does not exist on type 'Story'. | TS2339 - Property 'collInfo' does not exist on type 'Story'.
if (this.currList > this.collInfo.lists.length) {
// @ts-expect-error - TS2339 - Property 'currList' does not exist on type 'Story'.
this.currList = 0;
}
const opts = { behavior: "smooth", block: "nearest", inline: "nearest" };
// @ts-expect-error - TS2339 - Property 'clickTime' does not exist on type 'Story'.
this.clickTime = new Date().getTime();
// @ts-expect-error - TS2339 - Property 'getElementById' does not exist on type 'HTMLElement | ShadowRoot'. | TS2339 - Property 'currList' does not exist on type 'Story'.
const curr = this.renderRoot.getElementById("list-" + this.currList);
if (curr) {
curr.scrollIntoView(opts);
@@ -382,6 +443,7 @@ class Story extends LitElement {
onScroll(event) {
const scrollable = event.currentTarget;
// @ts-expect-error - TS2339 - Property 'getElementById' does not exist on type 'HTMLElement | ShadowRoot'. | TS2339 - Property 'currList' does not exist on type 'Story'.
const curr = this.renderRoot.getElementById("list-" + this.currList);
if (!curr) {
@@ -392,6 +454,7 @@ class Story extends LitElement {
const target = scrollable.offsetTop;
const currST = scrollable.scrollTop;
// @ts-expect-error - TS2339 - Property 'lastST' does not exist on type 'Story'.
if (currST > this.lastST) {
while (
next.nextElementSibling &&
@@ -407,22 +470,27 @@ class Story extends LitElement {
next = next.previousElementSibling;
}
}
// @ts-expect-error - TS2339 - Property 'lastST' does not exist on type 'Story'.
this.lastST = currST;
if (next && next != curr) {
if (next.id.startsWith("list-")) {
// @ts-expect-error - TS2339 - Property 'currList' does not exist on type 'Story'.
this.currList = Number(next.id.slice(5));
}
}
// @ts-expect-error - TS2339 - Property 'clickTime' does not exist on type 'Story'.
if (new Date().getTime() - this.clickTime < 1000) {
return;
}
const sel = this.renderRoot.querySelector(
// @ts-expect-error - TS2339 - Property 'currList' does not exist on type 'Story'.
`a[data-list="${this.currList}"]`,
);
if (sel) {
const opts = { behavior: "smooth", block: "nearest", inline: "nearest" };
// @ts-expect-error - TS2345 - Argument of type '{ behavior: string; block: string; inline: string; }' is not assignable to parameter of type 'boolean | ScrollIntoViewOptions | undefined'.
sel.scrollIntoView(opts);
}
}
+29 -2
View File
@@ -9,15 +9,21 @@ export class SWManager {
appName = "ReplayWeb.page",
requireSubdomainIframe = false,
} = {}) {
// @ts-expect-error - TS2339 - Property 'name' does not exist on type 'SWManager'.
this.name = name;
// @ts-expect-error - TS2339 - Property 'scope' does not exist on type 'SWManager'.
this.scope = scope;
// @ts-expect-error - TS2339 - Property 'appName' does not exist on type 'SWManager'.
this.appName = appName;
// @ts-expect-error - TS2339 - Property 'requireSubdomainIframe' does not exist on type 'SWManager'.
this.requireSubdomainIframe = requireSubdomainIframe;
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
this.errorMsg = null;
}
setAppName(newAppName) {
// @ts-expect-error - TS2339 - Property 'appName' does not exist on type 'SWManager'.
this.appName = newAppName;
}
@@ -29,26 +35,37 @@ export class SWManager {
reject = rej;
});
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
this.errorMsg = this.getSWErrorMsg();
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
if (this.errorMsg) {
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
console.error(this.errorMsg);
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
reject(this.errorMsg);
}
const handleError = (error) => {
console.error("Error during service worker registration:", error);
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
this.errorMsg = this.getCrossOriginIframeMsg();
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
if (!this.errorMsg) {
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
this.errorMsg = `${
// @ts-expect-error - TS2339 - Property 'appName' does not exist on type 'SWManager'.
this.appName
} could not be loaded due to the following error:\n${error.toString()}`;
}
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
reject(this.errorMsg);
};
// @ts-expect-error - TS2339 - Property 'scope' does not exist on type 'SWManager'. | TS2339 - Property 'name' does not exist on type 'SWManager'.
register(this.scope + this.name, {
// @ts-expect-error - TS2339 - Property 'scope' does not exist on type 'SWManager'.
registrationOptions: { scope: this.scope },
registered() {
console.log("Service worker is registered");
@@ -80,6 +97,7 @@ export class SWManager {
}
try {
// @ts-expect-error - TS2531 - Object is possibly 'null'.
return window.top.location.href === "";
} catch (e) {
return true;
@@ -89,7 +107,9 @@ export class SWManager {
getSWErrorMsg() {
if (navigator.serviceWorker) {
// must be loaded from a cross-origin (eg. subdomain)
// @ts-expect-error - TS2339 - Property 'requireSubdomainIframe' does not exist on type 'SWManager'.
if (this.requireSubdomainIframe && !this.isCrossOriginIframe()) {
// @ts-expect-error - TS2339 - Property 'appName' does not exist on type 'SWManager'.
return `Sorry, due to security settings, this ${this.appName} embed only be viewed within a subdomain iframe.`;
}
@@ -104,7 +124,12 @@ export class SWManager {
if (!window.isSecureContext) {
return `
Sorry, the ${this.appName} system must be loaded from an HTTPS URL (or localhost), but was loaded from: ${window.location.host}.
Sorry, the ${
// @ts-expect-error - TS2339 - Property 'appName' does not exist on type 'SWManager'.
this.appName
} system must be loaded from an HTTPS URL (or localhost), but was loaded from: ${
window.location.host
}.
Please try loading this page from an HTTPS URL`;
}
@@ -113,11 +138,13 @@ export class SWManager {
return "Sorry, Service Workers are disabled in Firefox in Private Mode. Please try loading this page in regular mode instead.";
}
// @ts-expect-error - TS2339 - Property 'appName' does not exist on type 'SWManager'.
return `Sorry, ${this.appName} won't work in this browser as Service Workers are not supported in this window.
Please try a different browser.`;
}
renderErrorReport(logo, override) {
renderErrorReport(logo: string, override?: string) {
// @ts-expect-error - TS2339 - Property 'errorMsg' does not exist on type 'SWManager'.
const msg = this.errorMsg || override;
if (!msg) {
+5 -1
View File
@@ -8,6 +8,8 @@ export interface Item {
* Archived Item ID
*/
coll?: string;
// TODO(emma) is `id` the same as `coll`? should they be merged?
id?: string;
name?: string;
title?: string;
loadUrl?: string;
@@ -24,9 +26,11 @@ export interface Item {
software?: string;
};
onDemand?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
pages?: any[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO fixme
lists?: any[];
ctime?: string;
totalSize?: unknown;
size?: unknown;
size?: number | string;
}
+192 -74
View File
@@ -58,24 +58,37 @@ class URLResources extends LitElement {
constructor() {
super();
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'URLResources'.
this.collInfo = null;
// @ts-expect-error - TS2339 - Property 'isSidebar' does not exist on type 'URLResources'.
this.isSidebar = false;
// @ts-expect-error - TS2339 - Property 'currMime' does not exist on type 'URLResources'.
this.currMime = "";
// @ts-expect-error - TS2339 - Property 'query' does not exist on type 'URLResources'.
this.query = "";
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
this.urlSearchType = "";
// @ts-expect-error - TS2339 - Property 'filteredResults' does not exist on type 'URLResources'.
this.filteredResults = [];
// @ts-expect-error - TS2339 - Property 'sortedResults' does not exist on type 'URLResources'.
this.sortedResults = [];
// @ts-expect-error - TS2339 - Property 'results' does not exist on type 'URLResources'.
this.results = [];
// @ts-expect-error - TS2339 - Property 'newQuery' does not exist on type 'URLResources'.
this.newQuery = null;
// @ts-expect-error - TS2339 - Property 'tryMore' does not exist on type 'URLResources'.
this.tryMore = false;
// @ts-expect-error - TS2339 - Property 'loading' does not exist on type 'URLResources'.
this.loading = false;
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
this.sortKey = "url";
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc = false;
}
@@ -96,14 +109,19 @@ class URLResources extends LitElement {
firstUpdated() {
//this.doLoadResources();
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
if (this.urlSearchType === "") {
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
this.urlSearchType = "prefix";
}
}
_timedUpdate() {
// @ts-expect-error - TS2339 - Property 'newQuery' does not exist on type 'URLResources'.
if (this.newQuery !== null) {
// @ts-expect-error - TS2339 - Property 'query' does not exist on type 'URLResources'. | TS2339 - Property 'newQuery' does not exist on type 'URLResources'.
this.query = this.newQuery;
// @ts-expect-error - TS2339 - Property 'newQuery' does not exist on type 'URLResources'.
this.newQuery = null;
}
}
@@ -116,8 +134,11 @@ class URLResources extends LitElement {
) {
this.doLoadResources();
const data = {
// @ts-expect-error - TS2339 - Property 'query' does not exist on type 'URLResources'.
query: this.query,
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
urlSearchType: this.urlSearchType,
// @ts-expect-error - TS2339 - Property 'currMime' does not exist on type 'URLResources'.
currMime: this.currMime,
};
const replaceLoc =
@@ -136,16 +157,21 @@ class URLResources extends LitElement {
async doLoadResources(isMore = false) {
const count = 100;
// @ts-expect-error - TS2339 - Property 'tryMore' does not exist on type 'URLResources'. | TS2339 - Property 'results' does not exist on type 'URLResources'.
if (isMore && (!this.tryMore || !this.results.length)) {
return;
}
// @ts-expect-error - TS2339 - Property 'loading' does not exist on type 'URLResources'.
if (this.loading) {
return;
}
// @ts-expect-error - TS2339 - Property 'loading' does not exist on type 'URLResources'.
this.loading = true;
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'. | TS2339 - Property 'query' does not exist on type 'URLResources'.
let url = this.urlSearchType !== "contains" ? this.query : "";
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
const prefix = url && this.urlSearchType === "prefix" ? 1 : 0;
// optimization: if not starting with http, likely won't have a match here, so just add https://
@@ -153,8 +179,10 @@ class URLResources extends LitElement {
url = "https://" + url;
}
// @ts-expect-error - TS2339 - Property 'currMime' does not exist on type 'URLResources'.
const mime = this.currMime;
// @ts-expect-error - TS2345 - Argument of type '{ mime: any; url: any; prefix: number; count: number; }' is not assignable to parameter of type 'string | Record<string, string> | URLSearchParams | string[][] | undefined'.
const params = new URLSearchParams({
mime,
url,
@@ -163,50 +191,66 @@ class URLResources extends LitElement {
});
if (isMore) {
// @ts-expect-error - TS2339 - Property 'results' does not exist on type 'URLResources'. | TS2339 - Property 'results' does not exist on type 'URLResources'.
const last = this.results[this.results.length - 1];
params.set("fromMime", last.mime);
params.set("fromUrl", last.url);
params.set("fromStatus", last.status);
// @ts-expect-error - TS2345 - Argument of type 'number' is not assignable to parameter of type 'string'.
params.set("fromTs", new Date(last.date).getTime());
}
let resp = await fetch(
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'URLResources'.
`${this.collInfo.apiPrefix}/urls?${params.toString()}`,
);
resp = await resp.json();
// @ts-expect-error - TS2339 - Property 'results' does not exist on type 'URLResources'. | TS2339 - Property 'results' does not exist on type 'URLResources'. | TS2551 - Property 'urls' does not exist on type 'Response'. Did you mean 'url'? | TS2551 - Property 'urls' does not exist on type 'Response'. Did you mean 'url'?
this.results = isMore ? this.results.concat(resp.urls) : resp.urls;
// can be more than count if multiple mimes
// @ts-expect-error - TS2339 - Property 'tryMore' does not exist on type 'URLResources'. | TS2551 - Property 'urls' does not exist on type 'Response'. Did you mean 'url'?
this.tryMore = resp.urls.length >= count;
this.filter();
// @ts-expect-error - TS2339 - Property 'loading' does not exist on type 'URLResources'.
this.loading = false;
}
onChangeTypeSearch(event) {
// @ts-expect-error - TS2339 - Property 'currMime' does not exist on type 'URLResources'.
this.currMime = event.currentTarget.value;
}
onChangeQuery(event) {
// @ts-expect-error - TS2339 - Property 'newQuery' does not exist on type 'URLResources'.
this.newQuery = event.currentTarget.value;
// @ts-expect-error - TS2339 - Property '_ival' does not exist on type 'URLResources'.
if (this._ival) {
// @ts-expect-error - TS2339 - Property '_ival' does not exist on type 'URLResources'.
window.clearTimeout(this._ival);
}
// @ts-expect-error - TS2339 - Property '_ival' does not exist on type 'URLResources'.
this._ival = window.setTimeout(() => this._timedUpdate(), 250);
}
onClickUrlType(event) {
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
this.urlSearchType = event.currentTarget.value;
}
filter() {
const filteredResults = [];
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'. | TS2339 - Property 'query' does not exist on type 'URLResources'.
const filterText = this.urlSearchType === "contains" ? this.query : "";
// @ts-expect-error - TS2339 - Property 'results' does not exist on type 'URLResources'.
for (const result of this.results) {
if (!filterText || result.url.indexOf(filterText) >= 0) {
// @ts-expect-error - TS2345 - Argument of type 'any' is not assignable to parameter of type 'never'.
filteredResults.push(result);
}
}
// @ts-expect-error - TS2339 - Property 'filteredResults' does not exist on type 'URLResources'.
this.filteredResults = filteredResults;
}
@@ -214,6 +258,7 @@ class URLResources extends LitElement {
const element = event.currentTarget;
const diff =
element.scrollHeight - element.scrollTop - element.clientHeight;
// @ts-expect-error - TS2339 - Property 'tryMore' does not exist on type 'URLResources'.
if (this.tryMore && diff < 40) {
this.doLoadResources(true);
}
@@ -320,15 +365,25 @@ class URLResources extends LitElement {
return html`
<div
role="heading"
aria-level="${this.isSidebar ? "2" : "1"}"
aria-level="${
// @ts-expect-error - TS2339 - Property 'isSidebar' does not exist on type 'URLResources'.
this.isSidebar ? "2" : "1"
}"
class="is-sr-only"
>
URLs in ${this.collInfo.title}
URLs in
${
// @ts-expect-error - TS2339 - Property 'collInfo' does not exist on type 'URLResources'.
this.collInfo.title
}
</div>
<div
role="heading"
aria-level="${this.isSidebar ? "3" : "2"}"
aria-level="${
// @ts-expect-error - TS2339 - Property 'isSidebar' does not exist on type 'URLResources'.
this.isSidebar ? "3" : "2"
}"
class="is-sr-only"
>
Search and Filter
@@ -343,7 +398,10 @@ class URLResources extends LitElement {
(filter) => html`
<option
value="${filter.filter}"
?selected="${filter.filter === this.currMime}"
?selected="${
// @ts-expect-error - TS2339 - Property 'currMime' does not exist on type 'URLResources'.
filter.filter === this.currMime
}"
>
${filter.name}
</option>
@@ -353,15 +411,19 @@ class URLResources extends LitElement {
</div>
<div class="field flex-auto">
<div
class="control has-icons-left ${this.loading
? "is-loading"
: ""}"
class="control has-icons-left ${
// @ts-expect-error - TS2339 - Property 'loading' does not exist on type 'URLResources'.
this.loading ? "is-loading" : ""
}"
>
<input
type="text"
class="input"
@input="${this.onChangeQuery}"
.value="${this.query}"
.value="${
// @ts-expect-error - TS2339 - Property 'query' does not exist on type 'URLResources'.
this.query
}"
placeholder="Enter URL to Search"
/>
<span class="icon is-left"
@@ -378,7 +440,10 @@ class URLResources extends LitElement {
type="radio"
name="urltype"
value="contains"
?checked="${this.urlSearchType === "contains"}"
?checked="${
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
this.urlSearchType === "contains"
}"
@click="${this.onClickUrlType}"
/>&nbsp;Contains</label
>
@@ -387,7 +452,10 @@ class URLResources extends LitElement {
type="radio"
name="urltype"
value="prefix"
?checked="${this.urlSearchType === "prefix"}"
?checked="${
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
this.urlSearchType === "prefix"
}"
@click="${this.onClickUrlType}"
/>&nbsp;Prefix</label
>
@@ -396,7 +464,10 @@ class URLResources extends LitElement {
type="radio"
name="urltype"
value="exact"
?checked="${this.urlSearchType === "exact"}"
?checked="${
// @ts-expect-error - TS2339 - Property 'urlSearchType' does not exist on type 'URLResources'.
this.urlSearchType === "exact"
}"
@click="${this.onClickUrlType}"
/>&nbsp;Exact</label
>
@@ -406,7 +477,11 @@ class URLResources extends LitElement {
is-pulled-right
aria-live="polite"
aria-atomic="true"
>${this.filteredResults.length} Result(s)</span
>${
// @ts-expect-error - TS2339 - Property 'filteredResults' does not exist on type 'URLResources'.
this.filteredResults.length
}
Result(s)</span
>
</div>
</div>
@@ -415,10 +490,19 @@ class URLResources extends LitElement {
<div class="sort-header is-hidden-tablet">
<wr-sorter
id="urls"
.sortKey="${this.sortKey}"
.sortDesc="${this.sortDesc}"
.sortKey="${
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
this.sortKey
}"
.sortDesc="${
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc
}"
.sortKeys="${URLResources.sortKeys}"
.data="${this.filteredResults}"
.data="${
// @ts-expect-error - TS2339 - Property 'filteredResults' does not exist on type 'URLResources'.
this.filteredResults
}"
@sort-changed="${this.onSortChanged}"
>
</wr-sorter>
@@ -426,7 +510,10 @@ class URLResources extends LitElement {
<div
role="heading"
aria-level="${this.isSidebar ? "3" : "2"}"
aria-level="${
// @ts-expect-error - TS2339 - Property 'isSidebar' does not exist on type 'URLResources'.
this.isSidebar ? "3" : "2"
}"
id="results-heading"
class="is-sr-only"
>
@@ -443,11 +530,15 @@ class URLResources extends LitElement {
@click="${this.onSort}"
@keyup="${clickOnSpacebarPress}"
data-key="url"
class="${this.sortKey === "url"
? this.sortDesc
? "desc"
: "asc"
: ""}"
class="${
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
this.sortKey === "url"
? // @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc
? "desc"
: "asc"
: ""
}"
>URL</a
>
</th>
@@ -458,11 +549,15 @@ class URLResources extends LitElement {
@click="${this.onSort}"
@keyup="${clickOnSpacebarPress}"
data-key="ts"
class="${this.sortKey === "ts"
? this.sortDesc
? "desc"
: "asc"
: ""}"
class="${
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
this.sortKey === "ts"
? // @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc
? "desc"
: "asc"
: ""
}"
>Date</a
>
</th>
@@ -473,11 +568,15 @@ class URLResources extends LitElement {
@click="${this.onSort}"
@keyup="${clickOnSpacebarPress}"
data-key="mime"
class="${this.sortKey === "mime"
? this.sortDesc
? "desc"
: "asc"
: ""}"
class="${
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
this.sortKey === "mime"
? // @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc
? "desc"
: "asc"
: ""
}"
>Mime Type</a
>
</th>
@@ -488,11 +587,15 @@ class URLResources extends LitElement {
@click="${this.onSort}"
@keyup="${clickOnSpacebarPress}"
data-key="status"
class="${this.sortKey === "status"
? this.sortDesc
? "desc"
: "asc"
: ""}"
class="${
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
this.sortKey === "status"
? // @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc
? "desc"
: "asc"
: ""
}"
>Status</a
>
</th>
@@ -500,45 +603,53 @@ class URLResources extends LitElement {
</thead>
<tbody class="main-scroll" @scroll="${this.onScroll}">
${this.sortedResults.length
? this.sortedResults.map(
(result) => html`
<tr class="columns result">
<td class="column col-url is-6">
<p class="minihead is-hidden-tablet">URL</p>
<a
@click="${this.onReplay}"
data-url="${result.url}"
data-ts="${result.ts}"
href="${getReplayLink(
"resources",
result.url,
result.ts,
)}"
>
<keyword-mark keywords="${this.query}"
>${result.url}</keyword-mark
${
// @ts-expect-error - TS2339 - Property 'sortedResults' does not exist on type 'URLResources'.
this.sortedResults.length
? // @ts-expect-error - TS2339 - Property 'sortedResults' does not exist on type 'URLResources'.
this.sortedResults.map(
(result) => html`
<tr class="columns result">
<td class="column col-url is-6">
<p class="minihead is-hidden-tablet">URL</p>
<a
@click="${this.onReplay}"
data-url="${result.url}"
data-ts="${result.ts}"
href="${getReplayLink(
"resources",
result.url,
result.ts,
)}"
>
</a>
</td>
<td class="column col-ts is-2">
<p class="minihead is-hidden-tablet">Date</p>
${new Date(result.date).toLocaleString()}
</td>
<td class="column col-mime is-3">
<p class="minihead is-hidden-tablet">Mime Type</p>
${result.mime}
</td>
<td class="column col-status is-1">
<p class="minihead is-hidden-tablet">Status</p>
${result.status}
</td>
</tr>
`,
)
: html`<tr class="section">
<td colspan="4"><i>No Results Found.</i></td>
</tr>`}
<keyword-mark
keywords="${
// @ts-expect-error - TS2339 - Property 'query' does not exist on type 'URLResources'.
this.query
}"
>${result.url}</keyword-mark
>
</a>
</td>
<td class="column col-ts is-2">
<p class="minihead is-hidden-tablet">Date</p>
${new Date(result.date).toLocaleString()}
</td>
<td class="column col-mime is-3">
<p class="minihead is-hidden-tablet">Mime Type</p>
${result.mime}
</td>
<td class="column col-status is-1">
<p class="minihead is-hidden-tablet">Status</p>
${result.status}
</td>
</tr>
`,
)
: html`<tr class="section">
<td colspan="4"><i>No Results Found.</i></td>
</tr>`
}
</tbody>
</table>
`;
@@ -548,17 +659,24 @@ class URLResources extends LitElement {
event.preventDefault();
const key = event.currentTarget.getAttribute("data-key");
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
if (key === this.sortKey) {
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'. | TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc = !this.sortDesc;
} else {
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc = false;
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
this.sortKey = key;
}
}
onSortChanged(event) {
// @ts-expect-error - TS2339 - Property 'sortedResults' does not exist on type 'URLResources'.
this.sortedResults = event.detail.sortedData;
// @ts-expect-error - TS2339 - Property 'sortKey' does not exist on type 'URLResources'.
this.sortKey = event.detail.sortKey;
// @ts-expect-error - TS2339 - Property 'sortDesc' does not exist on type 'URLResources'.
this.sortDesc = event.detail.sortDesc;
}
+10
View File
@@ -0,0 +1,10 @@
export function assertNonNullish<T>(
item: T,
itemName: string,
): asserts item is NonNullable<T> {
if (item == null) {
throw new Error(
`Variable \`${itemName}\` was expected to be defined, but found value ${item} instead`,
);
}
}