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:
+34
-10
@@ -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> About ${this.appName}</span>
|
||||
<span class="menu-version">(${VERSION})</span>
|
||||
<span class="menu-version">(${this.appVersion})</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+61
-23
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user