error fix + embedding extensability (#110)

* embed mode: make embedding options more extensible
ui: unify service worker not available errors, show same error in standard/embed mode, including when loaded over http
- more customizations for extended embed, allow hiding 'browse contents' button
- simplify title updates
- make error page / icon more customizable
- autoupdating in editable mode: don't update if previous one didn't finish, make customizable, don't autoupdate at all over >=100 pages

* dependencies: update ruffle to 2022-07-02

* bump to 1.6.1, update CHANGELIST
This commit is contained in:
Ilya Kreymer
2022-07-05 10:48:32 -07:00
committed by GitHub
parent 61d25c2c3d
commit 54fd92c273
17 changed files with 312 additions and 198 deletions
+34 -10
View File
@@ -65,6 +65,7 @@ class Coll extends LitElement
this.hasStory = false;
this.editable = false;
this.browsable = true;
this.showSidebar = localStorage.getItem("pages:showSidebar") === "1";
this.splitter = null;
@@ -73,7 +74,11 @@ class Coll extends LitElement
this.favIconUrl = "";
this.autoUpdateInterval = 10;
this._autoUpdater = null;
this.appName = "ReplayWeb.page";
this.appVersion = VERSION;
this.appLogo = rwpLogo;
}
@@ -102,13 +107,17 @@ class Coll extends LitElement
embed: { type: String },
editable: { type: Boolean },
browsable: { type: Boolean },
isVisible: { type: Boolean },
favIconUrl: {type: String },
appName: { type: String },
appVersion: { type: String },
appLogo: { type: String },
autoUpdateInterval: { type: Number }
};
}
@@ -129,6 +138,18 @@ class Coll extends LitElement
}
}
async runUpdateLoop() {
try {
// only autoupdate if interval is set, and number of pages < 100 to avoid messing up scrolling
while (this.editable && this.autoUpdateInterval && (!this.collInfo || this.collInfo.pages.length < 100)) {
await new Promise(resolve => setTimeout(resolve, this.autoUpdateInterval * 1000));
await this.doUpdateInfo(true);
}
} finally {
this._autoUpdater = null;
}
}
updated(changedProperties) {
// if (changedProperties.has("url") || changedProperties.has("ts")) {
// if (this.url.startsWith("rwp?")) {
@@ -142,10 +163,8 @@ class Coll extends LitElement
this.doUpdateInfo();
}
if (changedProperties.has("editable")) {
if (this.editable) {
this._pollColl = setInterval(() => this.doUpdateInfo(true), 10000);
} else if (this._pollColl) {
clearInterval(this._pollColl);
if (this.editable && this.autoUpdateInterval && !this._autoUpdater) {
this._autoUpdater = this.runUpdateLoop();
}
}
if (changedProperties.has("tabData")) {
@@ -369,7 +388,11 @@ class Coll extends LitElement
}
static get styles() {
return wrapCss(css`
return wrapCss(Coll.compStyles);
}
static get compStyles() {
return css`
:host {
display: flex;
flex-direction: column;
@@ -450,8 +473,7 @@ class Coll extends LitElement
flex: auto;
}
${Coll.replayBarStyles}
`);
${Coll.replayBarStyles}`;
}
static get replayBarStyles() {
@@ -760,12 +782,13 @@ class Coll extends LitElement
` : ""}
</span>
</a>
${this.browsable ? html`
<a href="#" role="button" class="button narrow is-borderless is-hidden-mobile ${!isReplay ? "grey-disabled" : ""}" @click="${this.onShowPages}" @keyup="${clickOnSpacebarPress}"
?disabled="${!isReplay}" title="Browse Contents" aria-label="Browse Contents" aria-controls="contents">
<span class="icon is-small">
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${farListAlt}"></fa-icon>
</span>
</a>
</a>` : ""}
${this.renderExtraToolbar(false)}
<form @submit="${this.onSubmit}">
<div class="control is-expanded ${showFavIcon ? "has-icons-left" : ""}">
@@ -813,12 +836,13 @@ class Coll extends LitElement
</span>
<span>Reload</span>
</a>
${this.browsable ? html`
<a href="#" role="button" class="dropdown-item is-hidden-tablet ${!isReplay ? "grey-disabled" : ""}" @click="${this.onShowPages}" @keyup="${clickOnSpacebarPress}">
<span class="icon is-small">
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${farListAlt}"></fa-icon>
</span>
<span>Browse Contents</span>
</a>
</a>` : ""}
${this.renderExtraToolbar(true)}
${!this.editable ? html`
<hr class="dropdown-divider is-hidden-desktop">
@@ -845,7 +869,7 @@ class Coll extends LitElement
<a href="#" role="button" class="dropdown-item" @click="${this.onAbout}">
<fa-icon class="menu-logo" size="1.0rem" aria-hidden="true" .svg=${this.appLogo}></fa-icon>
<span>&nbsp;About ${this.appName}</span>
<span class="menu-version">(${VERSION})</span>
<span class="menu-version">(${this.appVersion})</span>
</a>
</div>
</div>
+61 -23
View File
@@ -8,6 +8,8 @@ import { wrapCss, rwpLogo } from "./misc";
var scriptSrc = document.currentScript && document.currentScript.src;
var defaultReplayFile = "";
// ===========================================================================
class Embed extends LitElement
@@ -15,13 +17,16 @@ 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.view = "replay";
this.ts = "";
this.url = "";
this.query = "";
this.config = "";
this.customConfig = null;
this.coll = "";
this.paramString = null;
this.deepLink = false;
@@ -30,6 +35,11 @@ class Embed extends LitElement
this.reloadCount = 0;
this.noSandbox = false;
this.noWebWorker = false;
this.logo = rwpLogo;
}
static setDefaultReplayFile(replayfile) {
defaultReplayFile = replayfile;
}
static get properties() {
@@ -39,6 +49,8 @@ class Embed extends LitElement
query: { type: String },
source: { type: String },
src: { type: String },
view: { type: String },
embed: { type: String },
@@ -72,27 +84,33 @@ class Embed extends LitElement
}
}
handleMessage(event) {
const iframe = this.renderRoot.querySelector("iframe");
if (iframe && event.source === iframe.contentWindow) {
if (!event.data.view) {
return;
}
if (event.data.title) {
this.title = event.data.title;
}
if (!this.deepLink) {
return;
}
const currHash = new URLSearchParams(event.data);
const url = new URL(window.location.href);
url.hash = "#" + currHash.toString();
window.history.replaceState({}, "", url);
}
}
firstUpdated() {
this.doRegister();
window.addEventListener("message", (event) => {
const iframe = this.renderRoot.querySelector("iframe");
if (iframe && event.source === iframe.contentWindow) {
if (event.data.title) {
this.title = event.data.title;
}
if (!this.deepLink) {
return;
}
const currHash = new URLSearchParams(event.data);
const url = new URL(window.location.href);
url.hash = "#" + currHash.toString();
window.history.replaceState({}, "", url);
}
});
window.addEventListener("message", (event) => this.handleMessage(event));
if (this.deepLink) {
this.updateFromHash();
@@ -117,21 +135,41 @@ class Embed extends LitElement
}
}
mergeConfigs() {
if (!this.customConfig) {
return this.config;
}
if (this.config) {
const config = {...this.customConfig, ...JSON.parse(this.config)};
return JSON.stringify(config);
} else {
return JSON.stringify(this.customConfig);
}
}
updated(changedProperties) {
if (changedProperties.has("url") ||
changedProperties.has("ts") ||
changedProperties.has("query") ||
changedProperties.has("view") ||
changedProperties.has("source")) {
changedProperties.has("source") ||
changedProperties.has("src")) {
this.embed = this.embed || "default";
if (this.src) {
this.source = this.src;
}
const source = new URL(this.source, document.baseURI);
const config = this.mergeConfigs();
const params = {
source,
customColl: this.coll,
config: this.config,
config,
basePageUrl: window.location.href.split("#")[0],
embed: this.embed,
};
@@ -186,7 +224,7 @@ class Embed extends LitElement
allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts\
allow-same-origin allow-forms" : undefined)}"
@load="${this.onLoad}" src="${this.replaybase}?${this.paramString}#${this.hashString}" allow="autoplay *; fullscreen"
@load="${this.onLoad}" src="${this.replaybase}${this.replayfile}?${this.paramString}#${this.hashString}" allow="autoplay *; fullscreen"
title="Replay of ${this.title ? `${this.title}:` :""} ${this.url}"></iframe>
` : html``}
@@ -194,7 +232,7 @@ class Embed extends LitElement
${this.errorMessage ? html`
<section class="full-width">
<div class="has-text-centered">
<fa-icon class="logo" id="wrlogo" size="2.5rem" .svg=${rwpLogo} aria-hidden="true"></fa-icon>
<fa-icon class="logo" id="wrlogo" size="2.5rem" .svg=${this.logo} aria-hidden="true"></fa-icon>
</div>
<div class="error">${this.errorMessage}</div>
</section>
@@ -213,7 +251,7 @@ class Embed extends LitElement
this.reloadCount = 0;
if (win.customElements.get("replay-app-main")) {
if (win.customElements.get(this.mainElementName)) {
return;
}
+23 -12
View File
@@ -3,7 +3,7 @@ import { wrapCss, IS_APP } from "./misc";
import prettyBytes from "pretty-bytes";
import { parseURLSchemeHostPath } from "./pageutils";
import { getSWErrorMsg, parseURLSchemeHostPath } from "./pageutils";
// ===========================================================================
@@ -125,15 +125,11 @@ class Loader extends LitElement
this.percent = this.currentSize = this.totalSize = 0;
if (!navigator.serviceWorker) {
const noSWError = getSWErrorMsg();
if (noSWError) {
this.state = "errored";
if (window.location.protocol === "http:") {
this.error = `\
Sorry, the ReplayWeb.page system must be loaded from an HTTPS URL, but was loaded from: ${window.location.host}.
Please try loading this page from an HTTPS URL`;
} else {
this.error = "Sorry, this browser is not supported. Please try a different browser\n(If you're using Firefox, try without Private Mode)";
}
this.error = noSWError;
this.errorAllowRetry = false;
return;
}
@@ -176,6 +172,10 @@ You can select a file to upload from the main page by clicking the 'Choose File.
source = {sourceUrl, loadUrl: url.href};
}
break;
case "proxy":
sourceUrl = "proxy:" + sourceUrl.slice("proxy://".length);
break;
}
} catch (e) {
console.log(e);
@@ -189,10 +189,21 @@ You can select a file to upload from the main page by clicking the 'Choose File.
this.state = "started";
const msg = {"msg_type": "addColl", "name": this.coll, skipExisting: true, file: source};
const msg = {
msg_type: "addColl",
name: this.coll,
skipExisting: true,
file: source
};
if (this.loadInfo && this.loadInfo.extraConfig) {
msg.extraConfig = this.loadInfo.extraConfig;
if (this.loadInfo) {
if (this.loadInfo.extraConfig) {
msg.extraConfig = this.loadInfo.extraConfig;
}
// todo: too special case?
if (sourceUrl.startsWith("proxy:") && msg.extraConfig && msg.extraConfig.recording) {
msg.type = "recordingproxy";
}
}
if (!navigator.serviceWorker.controller) {
+4 -2
View File
@@ -138,12 +138,14 @@ class WrModal extends LitElement
super();
this.title = "";
this.bgClass = "";
this.noBgClose = false;
}
static get properties() {
return {
title: { type: String },
bgClass: { type: String }
bgClass: { type: String },
noBgClose: { type: Boolean }
};
}
@@ -167,7 +169,7 @@ class WrModal extends LitElement
render() {
return html`
<div class="modal is-active">
<div class="modal-background" @click="${this.onClose}"></div>
<div class="modal-background" @click="${() => !this.noBgClose && this.onClose()}"></div>
<div class="modal-card">
<header class="modal-card-head ${this.bgClass}">
<p class="modal-card-title is-3">${this.title}</p>
+25 -6
View File
@@ -1,5 +1,11 @@
import { register } from "register-service-worker";
let appName = "ReplayWeb.page";
// ===========================================================================
function setAppName(newAppName) {
appName = newAppName;
}
// ===========================================================================
function registerSW(name = "sw.js", scope = "./") {
@@ -10,10 +16,9 @@ function registerSW(name = "sw.js", scope = "./") {
reject = rej;
});
if (!navigator.serviceWorker) {
const errMsg = `Sorry, ReplayWeb.page won't work in this browser as Service Workers are not supported.
Please try a different browser.
(Service Workers are disabled in Firefox in Private Mode. If Using Private Mode in Firefox, try regular mode)`;
const errMsg = getSWErrorMsg();
if (errMsg) {
console.error(errMsg);
reject(errMsg);
}
@@ -27,13 +32,27 @@ Please try a different browser.
error (error) {
console.error("Error during service worker registration:", error);
reject(`ReplayWeb.page could not be loaded due to the following error:\n${error.toString()}`);
reject(`${appName} could not be loaded due to the following error:\n${error.toString()}`);
}
});
return p;
}
function getSWErrorMsg() {
if (navigator.serviceWorker) {
return null;
}
if (window.location.protocol === "http:") {
return `\
Sorry, the ${appName} system must be loaded from an HTTPS URL, but was loaded from: ${window.location.host}.
Please try loading this page from an HTTPS URL`;
} else {
return `Sorry, ${appName} won't work in this browser as Service Workers are not supported.
Please try a different browser.
(Service Workers are disabled in Firefox in Private Mode. If Using Private Mode in Firefox, try regular mode)`;
}
}
// ===========================================================================
async function digestMessage(message, hashtype) {
@@ -137,4 +156,4 @@ function parseURLSchemeHostPath(url) {
export { digestMessage, tsToDate, getTS, getPageDateTS, getReplayLink, sourceToId, parseURLSchemeHostPath,
registerSW };
registerSW, getSWErrorMsg, setAppName };
+16 -6
View File
@@ -10,6 +10,7 @@ class Replay extends LitElement
super();
this.replayUrl = "";
this.replayTS = "";
this.actualTS = "";
this.url = "";
this.ts = "";
this.title = "";
@@ -32,6 +33,7 @@ class Replay extends LitElement
// actual replay url
replayUrl: { type: String },
replayTS: { type: String },
actualTS: { type: String },
title: { type: String },
iframeUrl: { type: String },
@@ -107,6 +109,18 @@ class Replay extends LitElement
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail: {replaceLoc: true, data}}));
}
if (this.title && (changedProperties.has("title") || changedProperties.has("actualTS"))) {
const detail = {
title: this.title,
url: this.replayUrl,
// send actual ts even if live
ts: this.actualTS,
replayTitle: true
};
this.dispatchEvent(new CustomEvent("update-title", {bubbles: true, composed: true, detail}));
}
}
setDisablePointer(disable) {
@@ -122,7 +136,8 @@ class Replay extends LitElement
if (iframe && event.source === iframe.contentWindow) {
if (event.data.wb_type === "load" || event.data.wb_type === "replace-url") {
this.replayTS = event.data.ts;
this.replayTS = event.data.is_live ? "" : event.data.ts;
this.actualTS = event.data.ts;
this.replayUrl = event.data.url;
this.title = event.data.title || this.title;
this.clearLoading(iframe.contentWindow);
@@ -135,11 +150,6 @@ class Replay extends LitElement
this.title = event.data.title;
}
}
if (this.title) {
const detail = {title: this.title, replayTitle: true};
this.dispatchEvent(new CustomEvent("update-title", {bubbles: true, composed: true, detail}));
}
}
onReAuthed(event) {
+1 -1
View File
@@ -2,7 +2,7 @@ import { LitElement, html, css, unsafeCSS } from "lit";
import { wrapCss } from "./misc";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import marked from "marked";
import { marked } from "marked";
import { getTS, getReplayLink } from "./pageutils";