- split file chooser from coll index, insert as header, make file chooser collapsible - revamp collection index to be responsive - add separate sorter component, used for collection index and pages - combine 'curated lists' + pages, with page search + narrative - ensure page + narrative lists are collapsible - page search: support title, url and full text search if available, using flexsearch - page search: keyword highlighting, load all pages, showing in increments of 100 - page and resource search: delay search to 1/4 sec of inactivity to avoid too many queries - electron app: ensure noCache is set to true for local files - embedding: remove separate embed.js, just use ui.js for embed as well - embedding: support embedding iframe in a local origin with just sw.js and ui.js: sw.js serves index.html, <replay-web-page> embed injects ui.js into iframe - sw.js, new service worker entry point - sw and ww inited only from <replay-app-main>, ui.js loaded from <replay-web-page> embed component
164 lines
3.7 KiB
JavaScript
164 lines
3.7 KiB
JavaScript
import { LitElement, html, css } from 'lit-element';
|
|
|
|
import { registerSW } from './pageutils';
|
|
|
|
|
|
var scriptSrc = document.currentScript && document.currentScript.src;
|
|
|
|
|
|
// ===========================================================================
|
|
class Embed extends LitElement
|
|
{
|
|
constructor() {
|
|
super();
|
|
this.replayBase = window.location.origin + "/replay/";
|
|
this.swName = __SW_NAME__;
|
|
this.view = "replay";
|
|
this.ts = "";
|
|
this.url = "";
|
|
this.config = "";
|
|
this.coll = "";
|
|
this.paramString = null;
|
|
this.deepLink = false;
|
|
this.swInited = false;
|
|
|
|
this.doRegister();
|
|
}
|
|
|
|
static get properties() {
|
|
return {
|
|
url: { type: String },
|
|
ts: { type: String },
|
|
source: { type: String },
|
|
|
|
replayBase: { type: String },
|
|
swName: { type: String },
|
|
|
|
title: { type: String },
|
|
|
|
coll: { type: String },
|
|
config: { type: String },
|
|
|
|
swInited: { type: Boolean },
|
|
|
|
paramString: { type: String },
|
|
hashString: { type: String },
|
|
|
|
deepLink: { type: Boolean }
|
|
}
|
|
}
|
|
|
|
async doRegister() {
|
|
await registerSW(this.swName, this.replayBase);
|
|
|
|
this.swInited = true;
|
|
}
|
|
|
|
firstUpdated() {
|
|
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;
|
|
}
|
|
|
|
console.log(event.data);
|
|
|
|
if (!this.deepLink) {
|
|
return;
|
|
}
|
|
|
|
const currHash = new URLSearchParams({
|
|
url: event.data.url,
|
|
ts: event.data.ts,
|
|
});
|
|
const url = new URL(window.location.href);
|
|
url.hash = "#" + currHash.toString();
|
|
window.history.replaceState({}, "", url);
|
|
}
|
|
});
|
|
|
|
if (this.deepLink) {
|
|
this.updateFromHash();
|
|
window.addEventListener("hashchange", (event) => this.updateFromHash());
|
|
}
|
|
}
|
|
|
|
updateFromHash() {
|
|
const qs = new URLSearchParams(window.location.hash.slice(1));
|
|
|
|
if (qs.has("url")) {
|
|
this.url = qs.get("url");
|
|
}
|
|
if (qs.has("ts")) {
|
|
this.ts = qs.get("ts");
|
|
}
|
|
}
|
|
|
|
updated(changedProperties) {
|
|
if (changedProperties.has("url") ||
|
|
changedProperties.has("ts") ||
|
|
changedProperties.has("source")) {
|
|
|
|
this.paramString = new URLSearchParams({
|
|
source: this.source,
|
|
customColl: this.coll,
|
|
config: this.config,
|
|
embed: "true"
|
|
}).toString();
|
|
|
|
this.hashString = new URLSearchParams({
|
|
url: this.url,
|
|
ts: this.ts,
|
|
view: this.view
|
|
}).toString();
|
|
}
|
|
}
|
|
|
|
static get styles() {
|
|
return css`
|
|
iframe {
|
|
width: 100%;
|
|
height: 100%;
|
|
border: 0px;
|
|
padding: 0px;
|
|
margin: 0px;
|
|
}
|
|
:host {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
`;
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
${this.paramString && this.hashString && this.swInited ? html`
|
|
<iframe @load="${this.onLoad}" src="${this.replayBase}?${this.paramString}#${this.hashString}" allow="autoplay *; fullscreen"></iframe>
|
|
` : html``}
|
|
`;
|
|
}
|
|
|
|
onLoad(event) {
|
|
if (this.injected) {
|
|
return;
|
|
}
|
|
if (event.target.contentWindow.customElements.get("replay-app-main")) {
|
|
return;
|
|
}
|
|
const script = event.target.contentDocument.createElement("script");
|
|
//const script = event.target.contentDocument.querySelector("script");
|
|
script.src = scriptSrc;
|
|
event.target.contentDocument.head.appendChild(script);
|
|
this.injected = true;
|
|
}
|
|
}
|
|
|
|
// ===========================================================================
|
|
async function main() {
|
|
customElements.define("replay-web-page", Embed);
|
|
}
|
|
|
|
|
|
main(); |