add location bar to be part of collection,
use rwp:// scheme to indicate search pages
This commit is contained in:
+360
-12
@@ -1,5 +1,5 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from 'lit-element';
|
||||||
import { wrapCss, IS_APP } from './misc';
|
import { wrapCss, rwpLogo, IS_APP } from './misc';
|
||||||
|
|
||||||
import { sourceToId } from './pageutils';
|
import { sourceToId } from './pageutils';
|
||||||
|
|
||||||
@@ -10,6 +10,21 @@ import farResources from '@fortawesome/fontawesome-free/svgs/regular/file-code.s
|
|||||||
import farPlayCircle from '@fortawesome/fontawesome-free/svgs/regular/play-circle.svg';
|
import farPlayCircle from '@fortawesome/fontawesome-free/svgs/regular/play-circle.svg';
|
||||||
|
|
||||||
|
|
||||||
|
import { tsToDate } from './pageutils';
|
||||||
|
|
||||||
|
import fasRefresh from '@fortawesome/fontawesome-free/svgs/solid/redo-alt.svg';
|
||||||
|
import fasSearch from '@fortawesome/fontawesome-free/svgs/solid/search.svg';
|
||||||
|
import fasFullscreen from '@fortawesome/fontawesome-free/svgs/solid/desktop.svg';
|
||||||
|
import fasUnfullscreen from '@fortawesome/fontawesome-free/svgs/solid/compress-arrows-alt.svg';
|
||||||
|
|
||||||
|
import fasLeft from '@fortawesome/fontawesome-free/svgs/solid/arrow-left.svg';
|
||||||
|
import fasRight from '@fortawesome/fontawesome-free/svgs/solid/arrow-right.svg';
|
||||||
|
import fasMenuV from '@fortawesome/fontawesome-free/svgs/solid/ellipsis-v.svg';
|
||||||
|
|
||||||
|
|
||||||
|
const RWP_SCHEME = "rwp://";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
class Coll extends LitElement
|
class Coll extends LitElement
|
||||||
{
|
{
|
||||||
@@ -33,9 +48,13 @@ class Coll extends LitElement
|
|||||||
this._locationHash = "";
|
this._locationHash = "";
|
||||||
|
|
||||||
this.tabData = {};
|
this.tabData = {};
|
||||||
|
this.url = "";
|
||||||
|
this.ts = "";
|
||||||
|
|
||||||
this.tabNames = ["pages", "story", "resources", "replay"];
|
this.tabNames = ["pages", "story", "resources", "replay"];
|
||||||
|
|
||||||
|
this.menuActive = false;
|
||||||
|
|
||||||
this.hasStory = false;
|
this.hasStory = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,8 +71,11 @@ class Coll extends LitElement
|
|||||||
|
|
||||||
tabData: { type: Object, attribute: false },
|
tabData: { type: Object, attribute: false },
|
||||||
|
|
||||||
replayUrl: { type: String },
|
url: { type: String },
|
||||||
replayTS: { type: String },
|
ts: { type: String },
|
||||||
|
|
||||||
|
isFullscreen: { type: Boolean },
|
||||||
|
menuActive: { type: Boolean },
|
||||||
|
|
||||||
embed: { type: String },
|
embed: { type: String },
|
||||||
editable: { type: Boolean }
|
editable: { type: Boolean }
|
||||||
@@ -64,12 +86,20 @@ class Coll extends LitElement
|
|||||||
//this.doUpdateInfo();
|
//this.doUpdateInfo();
|
||||||
this.inited = true;
|
this.inited = true;
|
||||||
window.addEventListener("hashchange", (event) => this.onHashChange(event));
|
window.addEventListener("hashchange", (event) => this.onHashChange(event));
|
||||||
|
|
||||||
|
this.addEventListener("fullscreenchange", (event) => {
|
||||||
|
this.isFullscreen = !!document.fullscreenElement;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
if (changedProperties.has("replayUrl") || changedProperties.has("replayTS")) {
|
// if (changedProperties.has("url") || changedProperties.has("ts")) {
|
||||||
this.tabData = {view: "replay", url: this.replayUrl, ts: this.replayTS};
|
// if (this.url.startsWith("rwp?")) {
|
||||||
}
|
// this.tabData = Object.fromEntries(new URLSearchParams(this.url.slice(4)).entries());
|
||||||
|
// } else {
|
||||||
|
// this.tabData = {view: "replay", url: this.url, ts: this.ts};
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if (changedProperties.has("sourceUrl")) {
|
if (changedProperties.has("sourceUrl")) {
|
||||||
this.doUpdateInfo();
|
this.doUpdateInfo();
|
||||||
@@ -84,6 +114,10 @@ class Coll extends LitElement
|
|||||||
forEach(key => !this.tabData[key] && delete this.tabData[key]);
|
forEach(key => !this.tabData[key] && delete this.tabData[key]);
|
||||||
|
|
||||||
const newHash = "#" + new URLSearchParams(this.tabData).toString();
|
const newHash = "#" + new URLSearchParams(this.tabData).toString();
|
||||||
|
|
||||||
|
if (this.tabData.view !== "replay") {
|
||||||
|
this.url = RWP_SCHEME + decodeURIComponent(this._paramsToString(this.tabData));
|
||||||
|
}
|
||||||
if (newHash !== this._locationHash) {
|
if (newHash !== this._locationHash) {
|
||||||
this._locationHash = newHash;
|
this._locationHash = newHash;
|
||||||
if (this._replaceLoc || Object.keys(changedProperties.get("tabData")).length === 0) {
|
if (this._replaceLoc || Object.keys(changedProperties.get("tabData")).length === 0) {
|
||||||
@@ -166,17 +200,28 @@ class Coll extends LitElement
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const hash = event.currentTarget.getAttribute("href");
|
const hash = event.currentTarget.getAttribute("href");
|
||||||
this.tabData = {...this.tabData, view: hash.slice(1)};
|
this.tabData = {...this.tabData, view: hash.slice(1)};
|
||||||
|
//this.tabData = {view: hash.slice(1)};
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onCollTabNav(event) {
|
onCollTabNav(event) {
|
||||||
if (event.target.id === this.tabData.view) {
|
if (event.target.id === this.tabData.view) {
|
||||||
this.tabData = {view: this.tabData.view, ...event.detail.data};
|
this.updateTabData(event.detail.data, event.detail.replaceLoc);
|
||||||
this._replaceLoc = !this._locUpdateNeeded && event.detail.replaceLoc;
|
|
||||||
this._locUpdateNeeded = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTabData(data, replaceLoc = false) {
|
||||||
|
this.tabData = {view: this.tabData.view, ...data};
|
||||||
|
if (this.tabData.url) {
|
||||||
|
this.url = this.tabData.url || "";
|
||||||
|
}
|
||||||
|
if (this.tabData.ts) {
|
||||||
|
this.ts = this.tabData.ts || "";
|
||||||
|
}
|
||||||
|
this._replaceLoc = !this._locUpdateNeeded && replaceLoc;
|
||||||
|
this._locUpdateNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return wrapCss(css`
|
return wrapCss(css`
|
||||||
.icon {
|
.icon {
|
||||||
@@ -189,7 +234,7 @@ class Coll extends LitElement
|
|||||||
line-height: 0.5em;
|
line-height: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-active {
|
li.is-active {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,9 +282,76 @@ class Coll extends LitElement
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
${Coll.replayBarStyles}
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get replayBarStyles() {
|
||||||
|
return css`
|
||||||
|
.replay-bar {
|
||||||
|
padding: 1em;
|
||||||
|
max-width: none;
|
||||||
|
border-bottom: solid .1rem #97989A;
|
||||||
|
width: 100%;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
input#url {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#datetime {
|
||||||
|
position: absolute;
|
||||||
|
right: 1em;
|
||||||
|
z-index: 10;
|
||||||
|
background: linear-gradient(90deg, rgba(255, 255, 255, 0), #FFF 15%, #FFF);
|
||||||
|
margin: -35px 0 0 0px;
|
||||||
|
padding-left: 3em;
|
||||||
|
line-height: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-head {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.menu-logo {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.menu-version {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
.dropdown-item.info {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus + #datetime {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.replay-bar .button:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown .button {
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-borderless {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
top: 174px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.inited) return html``;
|
if (!this.inited) return html``;
|
||||||
|
|
||||||
@@ -283,6 +395,7 @@ class Coll extends LitElement
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>` : ``}
|
</div>` : ``}
|
||||||
|
${this.renderLocationBar()}
|
||||||
${this.renderCollTabs()}
|
${this.renderCollTabs()}
|
||||||
</nav>`;
|
</nav>`;
|
||||||
} else {
|
} else {
|
||||||
@@ -290,6 +403,106 @@ class Coll extends LitElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderLocationBar() {
|
||||||
|
const dateStr = tsToDate(this.ts).toLocaleString();
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="replay-bar">
|
||||||
|
<div class="field has-addons">
|
||||||
|
<button id="fullscreen" class="button is-borderless is-hidden-mobile" @click="${this.onFullscreenToggle}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${this.isFullscreen ? fasUnfullscreen : fasFullscreen}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button class="button is-borderless is-hidden-touch" @click="${this.onGoBack}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasLeft}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button class="button is-borderless is-hidden-touch" @click="${this.onGoForward}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRight}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button id="refresh" class="button is-borderless ${this.isLoading ? 'is-loading' : 'is-hidden-mobile'}" @click="${this.onRefresh}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
${!this.isLoading ? html`
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRefresh}"></fa-icon>
|
||||||
|
` : ``}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button class="button is-borderless is-hidden-touch" @click="${this.onGoPages}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${farListAlt}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<form @submit="${this.onSubmit}">
|
||||||
|
<div class="control is-expanded">
|
||||||
|
<input id="url" class="input" type="text" @keydown="${this.onKeyDown}" .value="${this.url}" placeholder="https://... Enter a URL to replay from the archive here"/>
|
||||||
|
${this.tabData.view === "replay" ? html`<p id="datetime" class="control is-hidden-mobile">${dateStr}</p>` : html``}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="dropdown is-right ${this.menuActive ? 'is-active' : ''}" @click="${(e) => this.menuActive = false}">
|
||||||
|
<div class="dropdown-trigger">
|
||||||
|
<button class="${this.embed ? '' : 'is-hidden-tablet'} button is-borderless" aria-haspopup="true" aria-controls="menu-dropdown" @click="${this.onMenu}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasMenuV}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown-menu" id="menu-dropdown" role="menu">
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a class="dropdown-item is-hidden-tablet" @click="${this.onFullscreenToggle}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${this.isFullscreen ? fasUnfullscreen : fasFullscreen}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
<span>Full Screen</span>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item is-hidden-desktop" @click="${this.onGoBack}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasLeft}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
<span>Back</span>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item is-hidden-desktop" @click="${this.onGoForward}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRight}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
<span>Forward</span>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item is-hidden-tablet" @click="${this.onRefresh}">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRefresh}"></fa-icon>
|
||||||
|
</span>
|
||||||
|
<span>Reload</span>
|
||||||
|
</a>
|
||||||
|
<hr class="dropdown-divider is-hidden-desktop">
|
||||||
|
<a class="dropdown-item" @click="${this.onPurgeCache}">
|
||||||
|
Purge Cache + Full Reload
|
||||||
|
</a>
|
||||||
|
${dateStr ? html`
|
||||||
|
<hr class="dropdown-divider is-hidden-desktop">
|
||||||
|
<div class="dropdown-item info is-hidden-desktop">
|
||||||
|
<span class="menu-head">Capture Date</span>${dateStr}
|
||||||
|
</div>` : ``}
|
||||||
|
${this.embed ? html`
|
||||||
|
<hr class="dropdown-divider">
|
||||||
|
<a href="https://replayweb.page/" target="_blank" class="dropdown-item info">
|
||||||
|
<fa-icon class="menu-logo" size="1.0rem" .svg=${rwpLogo}></fa-icon>
|
||||||
|
<span> About ReplayWeb.page</span>
|
||||||
|
<span class="menu-version">(${__VERSION__})</span>
|
||||||
|
</a>
|
||||||
|
` : ``}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
renderCollTabs() {
|
renderCollTabs() {
|
||||||
const isStory = this.tabData.view === 'story';
|
const isStory = this.tabData.view === 'story';
|
||||||
const isPages = this.tabData.view === 'pages';
|
const isPages = this.tabData.view === 'pages';
|
||||||
@@ -309,14 +522,14 @@ class Coll extends LitElement
|
|||||||
.active="${isPages}"
|
.active="${isPages}"
|
||||||
.editable="${this.editable}"
|
.editable="${this.editable}"
|
||||||
currList="${this.tabData.currList || 0}"
|
currList="${this.tabData.currList || 0}"
|
||||||
query="${this.tabData.query || this.tabData.url || ""}"
|
query="${this.tabData.query || ""}"
|
||||||
@coll-tab-nav="${this.onCollTabNav}" id="pages"
|
@coll-tab-nav="${this.onCollTabNav}" id="pages"
|
||||||
class="${isPages ? '' : 'is-hidden'}">
|
class="${isPages ? '' : 'is-hidden'}">
|
||||||
</wr-page-view>
|
</wr-page-view>
|
||||||
|
|
||||||
<wr-coll-resources .collInfo="${this.collInfo}"
|
<wr-coll-resources .collInfo="${this.collInfo}"
|
||||||
.active="${isResources}"
|
.active="${isResources}"
|
||||||
query="${this.tabData.query || this.tabData.url || ""}"
|
query="${this.tabData.query || ""}"
|
||||||
urlSearchType="${this.tabData.urlSearchType || ""}"
|
urlSearchType="${this.tabData.urlSearchType || ""}"
|
||||||
.currMime="${this.tabData.currMime || ""}"
|
.currMime="${this.tabData.currMime || ""}"
|
||||||
@coll-tab-nav="${this.onCollTabNav}" id="resources"
|
@coll-tab-nav="${this.onCollTabNav}" id="resources"
|
||||||
@@ -335,6 +548,141 @@ class Coll extends LitElement
|
|||||||
` : ``}
|
` : ``}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onKeyDown(event) {
|
||||||
|
if (event.key === "Esc" || event.key === "Escape") {
|
||||||
|
event.target.value = this.replayUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenu(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.menuActive = !this.menuActive;
|
||||||
|
|
||||||
|
if (this.menuActive) {
|
||||||
|
document.addEventListener("click", () => {
|
||||||
|
this.menuActive = false;
|
||||||
|
}, {once: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFullscreenToggle() {
|
||||||
|
this.menuActive = false;
|
||||||
|
if (!this.isFullscreen) {
|
||||||
|
this.requestFullscreen();
|
||||||
|
} else {
|
||||||
|
document.exitFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onGoBack() {
|
||||||
|
this.menuActive = false;
|
||||||
|
window.history.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
onGoForward() {
|
||||||
|
this.menuActive = false;
|
||||||
|
window.history.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
onGoPages() {
|
||||||
|
this.navigateTo(RWP_SCHEME + "view=pages");
|
||||||
|
}
|
||||||
|
|
||||||
|
onReAuthed(event) {
|
||||||
|
this.reauthWait = (async () => {
|
||||||
|
const headers = event.detail.headers;
|
||||||
|
|
||||||
|
const resp = await fetch(`${this.collInfo.apiPrefix}/updateAuth`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({headers})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.showAuth) {
|
||||||
|
this.onRefresh(null, true);
|
||||||
|
this.showAuth = false;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
async onPurgeCache(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const resp = await fetch(`${this.collInfo.apiPrefix}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resp.status === 200 && window.parent) {
|
||||||
|
window.parent.location.reload();
|
||||||
|
} else {
|
||||||
|
console.warn("purge failed: " + resp.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const value = this.renderRoot.querySelector("input").value;
|
||||||
|
this.navigateTo(value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateTo(value) {
|
||||||
|
if (value.startsWith("http://") || value.startsWith("https://")) {
|
||||||
|
this.url = value;
|
||||||
|
this._replaceLoc = !this._locUpdateNeeded;
|
||||||
|
this._locUpdateNeeded = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
let data;
|
||||||
|
if (!value.startsWith(RWP_SCHEME)) {
|
||||||
|
data = {query: value, view: "pages"};
|
||||||
|
} else {
|
||||||
|
data = this._stringToParams(value);
|
||||||
|
}
|
||||||
|
//this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail: {replaceLoc: false, data}}));
|
||||||
|
this.updateTabData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stringToParams(value) {
|
||||||
|
const q = new URLSearchParams(value.slice(RWP_SCHEME.length));
|
||||||
|
const data = {};
|
||||||
|
|
||||||
|
for (const param of ["query", "view", "currList", "currMime", "urlSearchType"]) {
|
||||||
|
if (q.has(param)) {
|
||||||
|
data[param] = q.get(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_paramsToString(value) {
|
||||||
|
const q = new URLSearchParams();
|
||||||
|
|
||||||
|
for (const param of ["query", "view", "currList", "currMime", "urlSearchType"]) {
|
||||||
|
if (param in value) {
|
||||||
|
q.set(param, value[param]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
onRefresh(event, forceReload) {
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.menuActive = false;
|
||||||
|
|
||||||
|
if (this.tabData.view === "replay") {
|
||||||
|
const replay = this.renderRoot.querySelector("wr-coll-replay");
|
||||||
|
if (replay) {
|
||||||
|
replay.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("wr-coll", Coll);
|
customElements.define("wr-coll", Coll);
|
||||||
|
|||||||
+20
-286
@@ -1,15 +1,6 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from 'lit-element';
|
||||||
import { wrapCss, rwpLogo } from './misc';
|
import { wrapCss } from './misc';
|
||||||
|
|
||||||
import { tsToDate } from './pageutils';
|
|
||||||
|
|
||||||
import fasRefresh from '@fortawesome/fontawesome-free/svgs/solid/redo-alt.svg';
|
|
||||||
import fasFullscreen from '@fortawesome/fontawesome-free/svgs/solid/desktop.svg';
|
|
||||||
import fasUnfullscreen from '@fortawesome/fontawesome-free/svgs/solid/compress-arrows-alt.svg';
|
|
||||||
|
|
||||||
import fasLeft from '@fortawesome/fontawesome-free/svgs/solid/arrow-left.svg';
|
|
||||||
import fasRight from '@fortawesome/fontawesome-free/svgs/solid/arrow-right.svg';
|
|
||||||
import fasMenuV from '@fortawesome/fontawesome-free/svgs/solid/ellipsis-v.svg';
|
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -24,8 +15,6 @@ class Replay extends LitElement
|
|||||||
this.ts = "";
|
this.ts = "";
|
||||||
this.title = "";
|
this.title = "";
|
||||||
|
|
||||||
this.menuActive = false;
|
|
||||||
|
|
||||||
this.showAuth = false;
|
this.showAuth = false;
|
||||||
this.reauthWait = null;
|
this.reauthWait = null;
|
||||||
}
|
}
|
||||||
@@ -35,7 +24,7 @@ class Replay extends LitElement
|
|||||||
collInfo: {type: Object },
|
collInfo: {type: Object },
|
||||||
sourceUrl: { type: String },
|
sourceUrl: { type: String },
|
||||||
|
|
||||||
// external url set by parent
|
// external url set from parent
|
||||||
url: { type: String },
|
url: { type: String },
|
||||||
ts: { type: String },
|
ts: { type: String },
|
||||||
|
|
||||||
@@ -48,10 +37,6 @@ class Replay extends LitElement
|
|||||||
isLoading: { type: Boolean },
|
isLoading: { type: Boolean },
|
||||||
|
|
||||||
showAuth: { type: Boolean },
|
showAuth: { type: Boolean },
|
||||||
|
|
||||||
embed: { type: String },
|
|
||||||
isFullscreen: { type: Boolean },
|
|
||||||
menuActive: { type: Boolean }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,19 +51,6 @@ class Replay extends LitElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addEventListener("fullscreenchange", (event) => {
|
|
||||||
this.isFullscreen = !!document.fullscreenElement;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onFullscreenToggle() {
|
|
||||||
this.menuActive = false;
|
|
||||||
if (!this.isFullscreen) {
|
|
||||||
this.requestFullscreen();
|
|
||||||
} else {
|
|
||||||
document.exitFullscreen();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doSetIframeUrl() {
|
doSetIframeUrl() {
|
||||||
@@ -144,33 +116,6 @@ class Replay extends LitElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const value = this.renderRoot.querySelector("input").value;
|
|
||||||
//this.replayUrl = value;
|
|
||||||
this.url = value;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
onRefresh(event, forceReload) {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isLoading && !forceReload) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.menuActive = false;
|
|
||||||
|
|
||||||
const iframe = this.renderRoot.querySelector("iframe");
|
|
||||||
|
|
||||||
if (iframe) {
|
|
||||||
this.waitForLoad();
|
|
||||||
iframe.contentWindow.location.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForLoad() {
|
waitForLoad() {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this._loadPoll = window.setInterval(() => {
|
this._loadPoll = window.setInterval(() => {
|
||||||
@@ -196,6 +141,19 @@ class Replay extends LitElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
if (this.isLoading && !forceReload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const iframe = this.renderRoot.querySelector("iframe");
|
||||||
|
|
||||||
|
if (iframe) {
|
||||||
|
this.waitForLoad();
|
||||||
|
iframe.contentWindow.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return wrapCss(css`
|
return wrapCss(css`
|
||||||
:host {
|
:host {
|
||||||
@@ -211,33 +169,6 @@ class Replay extends LitElement
|
|||||||
border: 0px;
|
border: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-bar {
|
|
||||||
padding: 1em;
|
|
||||||
max-width: none;
|
|
||||||
border-bottom: solid .1rem #97989A;
|
|
||||||
width: 100%;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-bar {
|
|
||||||
padding: 0.25em;
|
|
||||||
max-width: none;
|
|
||||||
border-bottom: solid .1rem #97989A;
|
|
||||||
text-align: center;
|
|
||||||
height: 44px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input#url {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav.intro-panel.panel {
|
|
||||||
min-width: 40%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.intro-panel .panel-heading {
|
.intro-panel .panel-heading {
|
||||||
font-size: 1.0em;
|
font-size: 1.0em;
|
||||||
}
|
}
|
||||||
@@ -247,157 +178,17 @@ class Replay extends LitElement
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#datetime {
|
nav.intro-panel.panel {
|
||||||
position: absolute;
|
min-width: 40%;
|
||||||
right: 1em;
|
display: flex;
|
||||||
z-index: 10;
|
flex-direction: column;
|
||||||
background: linear-gradient(90deg, rgba(255, 255, 255, 0), #FFF 15%, #FFF);
|
margin: auto;
|
||||||
margin: -35px 0 0 0px;
|
|
||||||
padding-left: 3em;
|
|
||||||
line-height: 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-head {
|
|
||||||
font-size: 10px;
|
|
||||||
font-weight: bold;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.menu-logo {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.menu-version {
|
|
||||||
font-size: 10px;
|
|
||||||
}
|
|
||||||
.dropdown-item.info {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:focus + #datetime {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.replay-bar .button:focus {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown .button {
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-borderless {
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
top: 174px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const dateStr = tsToDate(this.replayTS).toLocaleString();
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${this.embed !== "replayonly" ? html`
|
|
||||||
<div class="replay-bar">
|
|
||||||
<div class="field has-addons">
|
|
||||||
<button id="fullscreen" class="button is-borderless is-hidden-mobile" @click="${this.onFullscreenToggle}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${this.isFullscreen ? fasUnfullscreen : fasFullscreen}"></fa-icon>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
${this.embed ? html`
|
|
||||||
<button class="button is-borderless is-hidden-touch" @click="${this.onGoBack}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasLeft}"></fa-icon>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button class="button is-borderless is-hidden-touch" @click="${this.onGoForward}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRight}"></fa-icon>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
` : ``}
|
|
||||||
<button id="refresh" class="button is-borderless ${this.isLoading ? 'is-loading' : 'is-hidden-mobile'}" @click="${this.onRefresh}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
${!this.isLoading ? html`
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRefresh}"></fa-icon>
|
|
||||||
` : ``}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<form @submit="${this.onSubmit}">
|
|
||||||
<div class="control is-expanded">
|
|
||||||
<input id="url" class="input" type="text" @keydown="${this.onKeyDown}" .value="${this.replayUrl}" placeholder="https://... Enter a URL to replay from the archive here"/>
|
|
||||||
<p id="datetime" class="control is-hidden-mobile">${dateStr}</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="dropdown is-right ${this.menuActive ? 'is-active' : ''}" @click="${(e) => this.menuActive = false}">
|
|
||||||
<div class="dropdown-trigger">
|
|
||||||
<button class="${this.embed ? '' : 'is-hidden-tablet'} button is-borderless" aria-haspopup="true" aria-controls="menu-dropdown" @click="${this.onMenu}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasMenuV}"></fa-icon>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown-menu" id="menu-dropdown" role="menu">
|
|
||||||
<div class="dropdown-content">
|
|
||||||
<a class="dropdown-item is-hidden-tablet" @click="${this.onFullscreenToggle}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${this.isFullscreen ? fasUnfullscreen : fasFullscreen}"></fa-icon>
|
|
||||||
</span>
|
|
||||||
<span>Full Screen</span>
|
|
||||||
</a>
|
|
||||||
${this.embed ? html`
|
|
||||||
<a class="dropdown-item is-hidden-desktop" @click="${this.onGoBack}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasLeft}"></fa-icon>
|
|
||||||
</span>
|
|
||||||
<span>Back</span>
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item is-hidden-desktop" @click="${this.onGoForward}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRight}"></fa-icon>
|
|
||||||
</span>
|
|
||||||
<span>Forward</span>
|
|
||||||
</a>` : ``}
|
|
||||||
<a class="dropdown-item is-hidden-tablet" @click="${this.onRefresh}">
|
|
||||||
<span class="icon is-small">
|
|
||||||
<fa-icon size="1.0em" class="has-text-grey" .svg="${fasRefresh}"></fa-icon>
|
|
||||||
</span>
|
|
||||||
<span>Reload</span>
|
|
||||||
</a>
|
|
||||||
${this.embed ? html`
|
|
||||||
<hr class="dropdown-divider is-hidden-desktop">
|
|
||||||
<a class="dropdown-item" @click="${this.onPurgeCache}">
|
|
||||||
Purge Cache + Full Reload
|
|
||||||
</a>` : ``}
|
|
||||||
${dateStr ? html`
|
|
||||||
<hr class="dropdown-divider is-hidden-desktop">
|
|
||||||
<div class="dropdown-item info is-hidden-desktop">
|
|
||||||
<span class="menu-head">Capture Date</span>${dateStr}
|
|
||||||
</div>` : ``}
|
|
||||||
${this.embed ? html`
|
|
||||||
<hr class="dropdown-divider">
|
|
||||||
<a href="https://replayweb.page/" target="_blank" class="dropdown-item info">
|
|
||||||
<fa-icon class="menu-logo" size="1.0rem" .svg=${rwpLogo}></fa-icon>
|
|
||||||
<span> About ReplayWeb.page</span>
|
|
||||||
<span class="menu-version">(${__VERSION__})</span>
|
|
||||||
</a>
|
|
||||||
` : ``}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>` : html`
|
|
||||||
`}
|
|
||||||
|
|
||||||
${this.iframeUrl ? html`
|
${this.iframeUrl ? html`
|
||||||
<iframe @message="${this.onReplayMessage}" allow="autoplay 'self'; fullscreen" allowfullscreen
|
<iframe @message="${this.onReplayMessage}" allow="autoplay 'self'; fullscreen" allowfullscreen
|
||||||
@@ -430,63 +221,6 @@ class Replay extends LitElement
|
|||||||
` : ``}
|
` : ``}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown(event) {
|
|
||||||
if (event.key === "Esc" || event.key === "Escape") {
|
|
||||||
event.target.value = this.replayUrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMenu(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
this.menuActive = !this.menuActive;
|
|
||||||
|
|
||||||
if (this.menuActive) {
|
|
||||||
document.addEventListener("click", () => {
|
|
||||||
this.menuActive = false;
|
|
||||||
}, {once: true});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onGoBack() {
|
|
||||||
this.menuActive = false;
|
|
||||||
window.history.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
onGoForward() {
|
|
||||||
this.menuActive = false;
|
|
||||||
window.history.forward();
|
|
||||||
}
|
|
||||||
|
|
||||||
onReAuthed(event) {
|
|
||||||
this.reauthWait = (async () => {
|
|
||||||
const headers = event.detail.headers;
|
|
||||||
|
|
||||||
const resp = await fetch(`${this.collInfo.apiPrefix}/updateAuth`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({headers})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.showAuth) {
|
|
||||||
this.onRefresh(null, true);
|
|
||||||
this.showAuth = false;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
async onPurgeCache(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const resp = await fetch(`${this.collInfo.apiPrefix}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (resp.status === 200 && window.parent) {
|
|
||||||
window.parent.location.reload();
|
|
||||||
} else {
|
|
||||||
console.warn("purge failed: " + resp.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("wr-coll-replay", Replay);
|
customElements.define("wr-coll-replay", Replay);
|
||||||
|
|||||||
Reference in New Issue
Block a user