feat: Add "not found" error detail on page load (#482)
Resolves https://github.com/webrecorder/replayweb.page/issues/481 with workaround Related to https://github.com/webrecorder/browsertrix/issues/2865 ## Changes - Includes `replayNotFoundError` in `"page-loading"` event when page is finished loading as a workaround for the actual `replayNotFoundError` value not being available on `urlchange`. - Minor refactor to more strongly typed events.
This commit is contained in:
+6
-5
@@ -11,14 +11,15 @@ import { wrapCss, updateFaviconLinks, apiPrefix } from "./misc";
|
||||
import { SWManager } from "./swmanager";
|
||||
import { property, query } from "lit/decorators.js";
|
||||
import type { FavIconEventDetail } from "./types";
|
||||
import type { EmbedReplayData, EmbedReplayEvent } from "./item";
|
||||
import type { EmbedReplayData } from "./item";
|
||||
import type { RwpPageLoadingEvent, RwpUrlChangeEvent } from "./events";
|
||||
|
||||
type IframeMessage = MessageEvent<
|
||||
| EmbedReplayEvent
|
||||
| RwpUrlChangeEvent["detail"]
|
||||
| RwpPageLoadingEvent["detail"]
|
||||
| ({
|
||||
type: "favicons";
|
||||
} & FavIconEventDetail)
|
||||
| { loading: boolean; type: "page-loading" }
|
||||
>;
|
||||
|
||||
const scriptSrc =
|
||||
@@ -157,7 +158,7 @@ class Embed extends LitElement {
|
||||
this.handleUrlChangeMessage(event.data);
|
||||
}
|
||||
this.dispatchEvent(
|
||||
new CustomEvent<EmbedReplayEvent>("rwp-url-change", {
|
||||
new CustomEvent<RwpUrlChangeEvent["detail"]>("rwp-url-change", {
|
||||
detail: event.data,
|
||||
}),
|
||||
);
|
||||
@@ -165,7 +166,7 @@ class Embed extends LitElement {
|
||||
|
||||
case "page-loading":
|
||||
this.dispatchEvent(
|
||||
new CustomEvent<{ loading: boolean }>("rwp-page-loading", {
|
||||
new CustomEvent<RwpPageLoadingEvent["detail"]>("rwp-page-loading", {
|
||||
detail: event.data,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { EmbedReplayData, TabData } from "./item";
|
||||
|
||||
export type TabNavEvent = CustomEvent<{
|
||||
data: TabData;
|
||||
reload?: boolean;
|
||||
replaceLoc?: boolean;
|
||||
replayNotFoundError?: boolean;
|
||||
}>;
|
||||
|
||||
export type RwpUrlChangeEvent = CustomEvent<
|
||||
EmbedReplayData & {
|
||||
type: "urlchange";
|
||||
replayNotFoundError: boolean;
|
||||
}
|
||||
>;
|
||||
|
||||
export type ReplayLoadingDetail =
|
||||
| { loading: true }
|
||||
| { loading: false; replayNotFoundError: boolean };
|
||||
|
||||
export type RwpPageLoadingEvent = CustomEvent<
|
||||
Required<Pick<EmbedReplayData, "url" | "ts">> & {
|
||||
type: "page-loading";
|
||||
} & ReplayLoadingDetail
|
||||
>;
|
||||
+5
-1
@@ -58,7 +58,11 @@ export {
|
||||
|
||||
export type { ItemType, URLResource } from "./types";
|
||||
|
||||
export type { EmbedReplayEvent } from "./item";
|
||||
export type {
|
||||
RwpUrlChangeEvent as EmbedReplayEvent,
|
||||
RwpUrlChangeEvent,
|
||||
RwpPageLoadingEvent,
|
||||
} from "./events";
|
||||
|
||||
export * from "./misc";
|
||||
|
||||
|
||||
+40
-24
@@ -57,6 +57,12 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
||||
|
||||
import "./item-info";
|
||||
import { dateTimeFormatter } from "./utils/dateTimeFormatter";
|
||||
import type {
|
||||
ReplayLoadingDetail,
|
||||
RwpPageLoadingEvent,
|
||||
RwpUrlChangeEvent,
|
||||
TabNavEvent,
|
||||
} from "./events";
|
||||
|
||||
const RWP_SCHEME = "search://";
|
||||
|
||||
@@ -90,25 +96,17 @@ export type EmbedReplayData = {
|
||||
waczhash?: string;
|
||||
};
|
||||
|
||||
export type EmbedReplayEvent = EmbedReplayData & {
|
||||
type: "urlchange";
|
||||
replayNotFoundError: boolean;
|
||||
};
|
||||
|
||||
export type TabData = EmbedReplayData & {
|
||||
currList?: number;
|
||||
urlSearchType?: string;
|
||||
currMime?: string;
|
||||
};
|
||||
|
||||
export type TabDataUpdate = {
|
||||
reload: boolean;
|
||||
data: TabData;
|
||||
replaceLoc: boolean;
|
||||
replayNotFoundError: boolean;
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
/**
|
||||
* @fires coll-loaded
|
||||
* @fires update-title
|
||||
* @fires about-show
|
||||
*/
|
||||
class Item extends LitElement {
|
||||
@property({ type: Boolean })
|
||||
inited = false;
|
||||
@@ -347,7 +345,7 @@ class Item extends LitElement {
|
||||
lastUpdate.query !== query ||
|
||||
lastUpdate.title !== title
|
||||
) {
|
||||
const newUpdate: EmbedReplayEvent = {
|
||||
const newUpdate: RwpUrlChangeEvent["detail"] = {
|
||||
type: "urlchange",
|
||||
url,
|
||||
ts,
|
||||
@@ -573,7 +571,7 @@ class Item extends LitElement {
|
||||
return false;
|
||||
}
|
||||
|
||||
onItemTabNav(event: CustomEvent<TabDataUpdate>) {
|
||||
onItemTabNav(event: TabNavEvent) {
|
||||
if (event.detail.reload) {
|
||||
this.onRefresh(null, true);
|
||||
return;
|
||||
@@ -583,7 +581,9 @@ class Item extends LitElement {
|
||||
|
||||
const { data, replaceLoc, replayNotFoundError } = event.detail;
|
||||
|
||||
this.replayNotFoundError = replayNotFoundError;
|
||||
if (replayNotFoundError !== undefined) {
|
||||
this.replayNotFoundError = replayNotFoundError;
|
||||
}
|
||||
|
||||
if (
|
||||
targetId === this.tabData.view ||
|
||||
@@ -1778,16 +1778,32 @@ class Item extends LitElement {
|
||||
}
|
||||
|
||||
async onReplayLoading(
|
||||
event: CustomEvent<{ loading: boolean; url: string; ts: string }>,
|
||||
event: CustomEvent<{ loading: boolean; replayNotFoundError?: boolean }>,
|
||||
) {
|
||||
if (
|
||||
this.embed &&
|
||||
window.parent !== window &&
|
||||
this.isLoading !== event.detail.loading
|
||||
) {
|
||||
window.parent.postMessage({ type: "page-loading", ...event.detail }, "*");
|
||||
const { loading, replayNotFoundError } = event.detail;
|
||||
if (this.embed && window.parent !== window && this.isLoading !== loading) {
|
||||
let loadingDetail: ReplayLoadingDetail;
|
||||
|
||||
if (loading) {
|
||||
loadingDetail = {
|
||||
loading,
|
||||
};
|
||||
} else {
|
||||
loadingDetail = {
|
||||
loading,
|
||||
replayNotFoundError: replayNotFoundError ?? false,
|
||||
};
|
||||
}
|
||||
const msg = {
|
||||
...loadingDetail,
|
||||
type: "page-loading",
|
||||
url: this.tabData.url ?? "",
|
||||
ts: this.tabData.ts ?? "",
|
||||
} satisfies RwpPageLoadingEvent["detail"];
|
||||
|
||||
window.parent.postMessage(msg, "*");
|
||||
}
|
||||
this.isLoading = event.detail.loading;
|
||||
this.isLoading = loading;
|
||||
}
|
||||
|
||||
async onFavIcons(event: CustomEvent<FavIconEventDetail>) {
|
||||
|
||||
+3
-3
@@ -14,6 +14,7 @@ import {
|
||||
dateTimeFormatter,
|
||||
timeFormatter,
|
||||
} from "./utils/dateTimeFormatter";
|
||||
import type { TabNavEvent } from "./events";
|
||||
|
||||
// ===========================================================================
|
||||
class PageEntry extends LitElement {
|
||||
@@ -384,10 +385,9 @@ class PageEntry extends LitElement {
|
||||
return this.onReplay(event, true);
|
||||
}
|
||||
|
||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'data' implicitly has an 'any' type.
|
||||
sendChangeEvent(data, reload: boolean) {
|
||||
sendChangeEvent(data: URLTsChange, reload: boolean) {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("coll-tab-nav", {
|
||||
new CustomEvent<TabNavEvent["detail"]>("coll-tab-nav", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: { data, reload },
|
||||
|
||||
+8
-4
@@ -18,7 +18,8 @@ import fasEdit from "@fortawesome/fontawesome-free/svgs/solid/edit.svg";
|
||||
import type { Sorter } from "./sorter";
|
||||
import type { PageEntry } from "./pageentry";
|
||||
import type { Id, Index } from "flexsearch";
|
||||
import type { ItemType, Page } from "./types";
|
||||
import type { ItemType, Page, URLTsChange } from "./types";
|
||||
import type { TabNavEvent } from "./events";
|
||||
|
||||
const DYNAMIC_PAGE_SIZE = 25;
|
||||
|
||||
@@ -360,9 +361,12 @@ class Pages extends LitElement {
|
||||
this.filteredPages = curated;
|
||||
}
|
||||
|
||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'data' implicitly has an 'any' type.
|
||||
sendChangeEvent(data) {
|
||||
this.dispatchEvent(new CustomEvent("coll-tab-nav", { detail: { data } }));
|
||||
sendChangeEvent(data: URLTsChange) {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent<TabNavEvent["detail"]>("coll-tab-nav", {
|
||||
detail: { data },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'pages' implicitly has an 'any' type.
|
||||
|
||||
+24
-6
@@ -4,9 +4,18 @@ import { property } from "lit/decorators.js";
|
||||
|
||||
import { wrapCss } from "./misc";
|
||||
import rwpLogo from "~assets/brand/replaywebpage-icon-color.svg";
|
||||
import type { ItemType, URLTsChange } from "./types";
|
||||
import type { ItemType } from "./types";
|
||||
import type { ReplayLoadingDetail, TabNavEvent } from "./events";
|
||||
|
||||
// ===========================================================================
|
||||
/**
|
||||
* @fires update-title
|
||||
* @fires coll-tab-nav
|
||||
* @fires update-title
|
||||
* @fires replay-favicons
|
||||
* @fires replay-loading ReplayLoadingDetail
|
||||
* @fires cancel-click-download
|
||||
* @fires update-download-res-url
|
||||
*/
|
||||
class Replay extends LitElement {
|
||||
@property({ type: Object })
|
||||
collInfo: ItemType | Record<string, never> | null = null;
|
||||
@@ -149,14 +158,14 @@ class Replay extends LitElement {
|
||||
(this.replayUrl && changedProperties.has("replayUrl")) ||
|
||||
(this.replayTS && changedProperties.has("replayTS"))
|
||||
) {
|
||||
const data: URLTsChange = {
|
||||
const data = {
|
||||
url: this.replayUrl,
|
||||
ts: this.replayTS,
|
||||
waczhash: this.waczhash,
|
||||
};
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("coll-tab-nav", {
|
||||
new CustomEvent<TabNavEvent["detail"]>("coll-tab-nav", {
|
||||
detail: {
|
||||
replaceLoc: true,
|
||||
data,
|
||||
@@ -279,7 +288,12 @@ class Replay extends LitElement {
|
||||
|
||||
clearLoading(iframe: HTMLIFrameElement | null) {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("replay-loading", { detail: { loading: false } }),
|
||||
new CustomEvent<ReplayLoadingDetail>("replay-loading", {
|
||||
detail: {
|
||||
loading: false,
|
||||
replayNotFoundError: this.replayNotFoundError,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
if (this._loadPoll) {
|
||||
@@ -303,7 +317,11 @@ class Replay extends LitElement {
|
||||
setLoading() {
|
||||
this.clearHilite(true);
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("replay-loading", { detail: { loading: true } }),
|
||||
new CustomEvent<ReplayLoadingDetail>("replay-loading", {
|
||||
detail: {
|
||||
loading: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+11
-6
@@ -8,9 +8,10 @@ import { marked } from "marked";
|
||||
import { getTS, getReplayLink } from "./pageutils";
|
||||
|
||||
import Split from "split.js";
|
||||
import { type ItemType } from "./types";
|
||||
import type { URLTsChange, ItemType } from "./types";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { dateTimeFormatter } from "./utils/dateTimeFormatter";
|
||||
import type { TabNavEvent } from "./events";
|
||||
|
||||
// ===========================================================================
|
||||
@customElement("wr-coll-story")
|
||||
@@ -375,16 +376,20 @@ class Story extends LitElement {
|
||||
onReplay(event: Event) {
|
||||
event.preventDefault();
|
||||
const data = {
|
||||
url: (event.currentTarget as Element).getAttribute("data-url"),
|
||||
ts: (event.currentTarget as Element).getAttribute("data-ts"),
|
||||
url:
|
||||
(event.currentTarget as Element).getAttribute("data-url") ?? undefined,
|
||||
ts: (event.currentTarget as Element).getAttribute("data-ts") ?? undefined,
|
||||
};
|
||||
this.sendChangeEvent(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'data' implicitly has an 'any' type.
|
||||
sendChangeEvent(data) {
|
||||
this.dispatchEvent(new CustomEvent("coll-tab-nav", { detail: { data } }));
|
||||
sendChangeEvent(data: URLTsChange) {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent<TabNavEvent["detail"]>("coll-tab-nav", {
|
||||
detail: { data },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'event' implicitly has an 'any' type.
|
||||
|
||||
+3
-2
@@ -27,9 +27,10 @@ export type Page = {
|
||||
};
|
||||
|
||||
export type URLTsChange = {
|
||||
url: string;
|
||||
ts: string;
|
||||
url?: string;
|
||||
ts?: string;
|
||||
waczhash?: string;
|
||||
currList?: number;
|
||||
};
|
||||
|
||||
export type ItemType = {
|
||||
|
||||
@@ -10,6 +10,7 @@ import "keyword-mark-element/lib/keyword-mark.js";
|
||||
import { type ItemType } from "./types";
|
||||
import { type URLResource } from "./types";
|
||||
import { dateTimeFormatter } from "./utils/dateTimeFormatter";
|
||||
import type { TabNavEvent } from "./events";
|
||||
|
||||
// ===========================================================================
|
||||
/**
|
||||
@@ -145,7 +146,9 @@ class URLResources extends LitElement {
|
||||
!changedProperties.has("currMime") &&
|
||||
!changedProperties.has("urlSearchType");
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("coll-tab-nav", { detail: { replaceLoc, data } }),
|
||||
new CustomEvent<TabNavEvent["detail"]>("coll-tab-nav", {
|
||||
detail: { replaceLoc, data },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -613,7 +616,11 @@ class URLResources extends LitElement {
|
||||
ts: event.currentTarget.getAttribute("data-ts"),
|
||||
};
|
||||
|
||||
this.dispatchEvent(new CustomEvent("coll-tab-nav", { detail: { data } }));
|
||||
this.dispatchEvent(
|
||||
new CustomEvent<TabNavEvent["detail"]>("coll-tab-nav", {
|
||||
detail: { data },
|
||||
}),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user