- add 'replayNotFoundError' field to 'urlchange' (propagating 'archive-not-found' postMessage message from wabac.js) to embed frame, with url/ts, for 404 pages - propagate 'page-loading' with loading true/false, to indicate when a page started/finished loading. (URL not available here) - Only send one urlchange event per URL change (keep track of change). - Also ensure multi timestamp change uses replaceHistory to avoid an extra navigation. - replay-web-page embed: send rwp-url-change and rwp-page-loading custom events from webcomponent Fixes #333
This commit is contained in:
committed by
Ilya Kreymer
parent
f3506a1575
commit
105562abf9
+16
-4
@@ -11,15 +11,14 @@ import { wrapCss, updateFaviconLinks } from "./misc";
|
|||||||
import { SWManager } from "./swmanager";
|
import { SWManager } from "./swmanager";
|
||||||
import { property } from "lit/decorators.js";
|
import { property } from "lit/decorators.js";
|
||||||
import type { FavIconEventDetail } from "./types";
|
import type { FavIconEventDetail } from "./types";
|
||||||
import type { EmbedReplayData } from "./item";
|
import type { EmbedReplayData, EmbedReplayEvent } from "./item";
|
||||||
|
|
||||||
type IframeMessage = MessageEvent<
|
type IframeMessage = MessageEvent<
|
||||||
| ({
|
| EmbedReplayEvent
|
||||||
type: "urlchange";
|
|
||||||
} & EmbedReplayData)
|
|
||||||
| ({
|
| ({
|
||||||
type: "favicons";
|
type: "favicons";
|
||||||
} & FavIconEventDetail)
|
} & FavIconEventDetail)
|
||||||
|
| { loading: boolean; type: "page-loading" }
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const scriptSrc =
|
const scriptSrc =
|
||||||
@@ -136,6 +135,19 @@ class Embed extends LitElement {
|
|||||||
if (this.deepLink) {
|
if (this.deepLink) {
|
||||||
this.handleUrlChangeMessage(event.data);
|
this.handleUrlChangeMessage(event.data);
|
||||||
}
|
}
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent<EmbedReplayEvent>("rwp-url-change", {
|
||||||
|
detail: event.data,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "page-loading":
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent<{ loading: boolean }>("rwp-page-loading", {
|
||||||
|
detail: event.data,
|
||||||
|
}),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "favicons":
|
case "favicons":
|
||||||
|
|||||||
+70
-35
@@ -93,6 +93,11 @@ export type EmbedReplayData = {
|
|||||||
query?: string;
|
query?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type EmbedReplayEvent = EmbedReplayData & {
|
||||||
|
type: "urlchange";
|
||||||
|
replayNotFoundError: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type TabData = EmbedReplayData & {
|
export type TabData = EmbedReplayData & {
|
||||||
multiTs?: string[];
|
multiTs?: string[];
|
||||||
currList?: number;
|
currList?: number;
|
||||||
@@ -100,6 +105,13 @@ export type TabData = EmbedReplayData & {
|
|||||||
currMime?: string;
|
currMime?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TabDataUpdate = {
|
||||||
|
reload: boolean;
|
||||||
|
data: TabData;
|
||||||
|
replaceLoc: boolean;
|
||||||
|
replayNotFoundError: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
class Item extends LitElement {
|
class Item extends LitElement {
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
@@ -174,6 +186,9 @@ class Item extends LitElement {
|
|||||||
@property({ type: String })
|
@property({ type: String })
|
||||||
swName: string | null = null;
|
swName: string | null = null;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
replayNotFoundError = false;
|
||||||
|
|
||||||
private splitter: Split.Instance | null = null;
|
private splitter: Split.Instance | null = null;
|
||||||
|
|
||||||
private _replaceLoc = false;
|
private _replaceLoc = false;
|
||||||
@@ -194,6 +209,8 @@ class Item extends LitElement {
|
|||||||
resources: "URLs",
|
resources: "URLs",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _lastUrlUpdate: EmbedReplayData | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -248,19 +265,16 @@ class Item extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const json = await resp.json();
|
const json = await resp.json();
|
||||||
this.updateTabData({ multiTs: json.timestamps });
|
this.updateTabData({ multiTs: json.timestamps }, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
willUpdate(changedProperties: Map<string, Record<string, unknown>>) {
|
willUpdate(changedProperties: Map<string, Record<string, unknown>>) {
|
||||||
// TODO: Fix this the next time the file is edited.
|
if (changedProperties.has("tabData")) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
if (changedProperties.has("tabData") && this.tabData) {
|
|
||||||
// Format tab data from URL query params
|
// Format tab data from URL query params
|
||||||
const tabData = {};
|
const tabData: TabData = {};
|
||||||
Object.entries(this.tabData).forEach(([key, value]) => {
|
Object.entries(this.tabData).forEach(([key, value]) => {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
if (key === "multiTs" && typeof value === "string") {
|
if (key === "multiTs" && typeof value === "string") {
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7053 - Element implicitly has an 'any' type because expression of type '"multiTs"' can't be used to index type '{}'.
|
|
||||||
tabData[key] = value.split(",");
|
tabData[key] = value.split(",");
|
||||||
} else {
|
} else {
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7053 - Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
|
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7053 - Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
|
||||||
@@ -271,9 +285,7 @@ class Item extends LitElement {
|
|||||||
|
|
||||||
const prevTabData = changedProperties.get("tabData");
|
const prevTabData = changedProperties.get("tabData");
|
||||||
if (this.tabData.url && this.tabData.url !== prevTabData?.url) {
|
if (this.tabData.url && this.tabData.url !== prevTabData?.url) {
|
||||||
// TODO: Fix this the next time the file is edited.
|
void this.getMultiTimestamps();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.getMultiTimestamps();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,10 +344,28 @@ class Item extends LitElement {
|
|||||||
}
|
}
|
||||||
if (this.embed && window.parent !== window) {
|
if (this.embed && window.parent !== window) {
|
||||||
const { url, ts, view, query, title }: EmbedReplayData = this.tabData;
|
const { url, ts, view, query, title }: EmbedReplayData = this.tabData;
|
||||||
window.parent.postMessage(
|
const lastUpdate = this._lastUrlUpdate;
|
||||||
{ type: "urlchange", url, ts, view, query, title },
|
const replayNotFoundError = this.replayNotFoundError;
|
||||||
"*",
|
if (
|
||||||
);
|
!lastUpdate ||
|
||||||
|
lastUpdate.url !== url ||
|
||||||
|
lastUpdate.ts !== ts ||
|
||||||
|
lastUpdate.view !== view ||
|
||||||
|
lastUpdate.query !== query ||
|
||||||
|
lastUpdate.title !== title
|
||||||
|
) {
|
||||||
|
const newUpdate: EmbedReplayEvent = {
|
||||||
|
type: "urlchange",
|
||||||
|
url,
|
||||||
|
ts,
|
||||||
|
view,
|
||||||
|
query,
|
||||||
|
title,
|
||||||
|
replayNotFoundError,
|
||||||
|
};
|
||||||
|
window.parent.postMessage(newUpdate, "*");
|
||||||
|
this._lastUrlUpdate = newUpdate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._locUpdateNeeded = false;
|
this._locUpdateNeeded = false;
|
||||||
@@ -542,35 +572,28 @@ class Item extends LitElement {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'event' implicitly has an 'any' type.
|
onItemTabNav(event: CustomEvent<TabDataUpdate>) {
|
||||||
onItemTabNav(event) {
|
|
||||||
if (event.detail.reload) {
|
if (event.detail.reload) {
|
||||||
this.onRefresh(null, true);
|
this.onRefresh(null, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const targetId = (event.target as HTMLElement).id;
|
||||||
|
|
||||||
|
const { data, replaceLoc, replayNotFoundError } = event.detail;
|
||||||
|
|
||||||
|
this.replayNotFoundError = replayNotFoundError;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
event.target.id === this.tabData.view ||
|
targetId === this.tabData.view ||
|
||||||
(event.target.id === "replay" && this.tabData.url)
|
(targetId === "replay" && this.tabData.url) ||
|
||||||
|
(this.showSidebar && this.tabData.url)
|
||||||
) {
|
) {
|
||||||
this.updateTabData(
|
this.updateTabData(data, replaceLoc);
|
||||||
event.detail.data,
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
event.detail.replaceLoc /*, false */,
|
|
||||||
);
|
|
||||||
} else if (this.showSidebar && this.tabData.url) {
|
|
||||||
this.updateTabData(
|
|
||||||
event.detail.data,
|
|
||||||
// TODO: Fix this the next time the file is edited.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
||||||
event.detail.replaceLoc /*, true */,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'data' implicitly has an 'any' type.
|
updateTabData(data: TabData, replaceLoc = false) {
|
||||||
updateTabData(data, replaceLoc = false /*, merge = false*/) {
|
|
||||||
this.tabData = { ...this.tabData, ...data };
|
this.tabData = { ...this.tabData, ...data };
|
||||||
if (this.tabData.url) {
|
if (this.tabData.url) {
|
||||||
this.url = this.tabData.url || "";
|
this.url = this.tabData.url || "";
|
||||||
@@ -961,8 +984,7 @@ class Item extends LitElement {
|
|||||||
ts="${this.tabData.ts || ""}"
|
ts="${this.tabData.ts || ""}"
|
||||||
@coll-tab-nav="${this.onItemTabNav}"
|
@coll-tab-nav="${this.onItemTabNav}"
|
||||||
id="replay"
|
id="replay"
|
||||||
@replay-loading="${(e: CustomEvent<{ loading: boolean }>) =>
|
@replay-loading="${this.onReplayLoading}"
|
||||||
(this.isLoading = e.detail.loading)}"
|
|
||||||
@replay-favicons="${this.onFavIcons}"
|
@replay-favicons="${this.onFavIcons}"
|
||||||
>
|
>
|
||||||
</wr-coll-replay>
|
</wr-coll-replay>
|
||||||
@@ -1653,6 +1675,19 @@ class Item extends LitElement {
|
|||||||
this.showSidebar = false;
|
this.showSidebar = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onReplayLoading(
|
||||||
|
event: CustomEvent<{ loading: boolean; url: string; ts: string }>,
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
this.embed &&
|
||||||
|
window.parent !== window &&
|
||||||
|
this.isLoading !== event.detail.loading
|
||||||
|
) {
|
||||||
|
window.parent.postMessage({ type: "page-loading", ...event.detail }, "*");
|
||||||
|
}
|
||||||
|
this.isLoading = event.detail.loading;
|
||||||
|
}
|
||||||
|
|
||||||
async onFavIcons(event: CustomEvent<FavIconEventDetail>) {
|
async onFavIcons(event: CustomEvent<FavIconEventDetail>) {
|
||||||
if (this.embed && window.parent !== window) {
|
if (this.embed && window.parent !== window) {
|
||||||
window.parent.postMessage({ type: "favicons", ...event.detail }, "*");
|
window.parent.postMessage({ type: "favicons", ...event.detail }, "*");
|
||||||
@@ -1749,7 +1784,7 @@ class Item extends LitElement {
|
|||||||
|
|
||||||
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'value' implicitly has an 'any' type.
|
// @ts-expect-error [// TODO: Fix this the next time the file is edited.] - TS7006 - Parameter 'value' implicitly has an 'any' type.
|
||||||
navigateTo(value) {
|
navigateTo(value) {
|
||||||
let data;
|
let data: TabData;
|
||||||
|
|
||||||
if (value.startsWith("http://") || value.startsWith("https://")) {
|
if (value.startsWith("http://") || value.startsWith("https://")) {
|
||||||
data = { url: value };
|
data = { url: value };
|
||||||
|
|||||||
+13
-2
@@ -39,6 +39,9 @@ class Replay extends LitElement {
|
|||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
showAuth = false;
|
showAuth = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
replayNotFoundError = false;
|
||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- requestPermission() type mismatch
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- requestPermission() type mismatch
|
||||||
authFileHandle: any = null;
|
authFileHandle: any = null;
|
||||||
@@ -140,7 +143,13 @@ class Replay extends LitElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent("coll-tab-nav", { detail: { replaceLoc: true, data } }),
|
new CustomEvent("coll-tab-nav", {
|
||||||
|
detail: {
|
||||||
|
replaceLoc: true,
|
||||||
|
data,
|
||||||
|
replayNotFoundError: this.replayNotFoundError,
|
||||||
|
},
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,12 +189,14 @@ class Replay extends LitElement {
|
|||||||
if (iframe && event.source === iframe.contentWindow) {
|
if (iframe && event.source === iframe.contentWindow) {
|
||||||
if (
|
if (
|
||||||
event.data.wb_type === "load" ||
|
event.data.wb_type === "load" ||
|
||||||
event.data.wb_type === "replace-url"
|
event.data.wb_type === "replace-url" ||
|
||||||
|
event.data.wb_type === "archive-not-found"
|
||||||
) {
|
) {
|
||||||
this.replayTS = event.data.is_live ? "" : event.data.ts;
|
this.replayTS = event.data.is_live ? "" : event.data.ts;
|
||||||
this.actualTS = event.data.ts;
|
this.actualTS = event.data.ts;
|
||||||
this.replayUrl = event.data.url;
|
this.replayUrl = event.data.url;
|
||||||
this.title = event.data.title || this.title;
|
this.title = event.data.title || this.title;
|
||||||
|
this.replayNotFoundError = event.data.wb_type === "archive-not-found";
|
||||||
this.clearLoading(iframe.contentWindow);
|
this.clearLoading(iframe.contentWindow);
|
||||||
|
|
||||||
if (event.data.icons) {
|
if (event.data.icons) {
|
||||||
|
|||||||
Reference in New Issue
Block a user