refactor components, save arguments via query

replay in new tab!
add frontendExternal
This commit is contained in:
Ilya Kreymer
2020-04-26 21:37:27 -07:00
parent 769cd020d8
commit 23deeb81e0
+387 -194
View File
@@ -17,41 +17,23 @@ class AppMain extends LitElement
constructor() { constructor() {
super(); super();
this.coll = ""; this.sourceUrl = null;
this.collInfo = {}; this.pageParams = {};
this.loadInfo = {};
this.updateRoute();
} }
static get properties() { static get properties() {
return { return {
pageState: { type: String },
pageParams: { type: Object }, pageParams: { type: Object },
coll: { type: String }, sourceUrl: { type: String },
collInfo: { type: Object }
} }
} }
async updateRoute() { firstUpdated() {
this.initRoute();
}
initRoute() {
this.pageParams = new URLSearchParams(window.location.search); this.pageParams = new URLSearchParams(window.location.search);
const source = this.pageParams.get("source");
if (source) {
const {url, coll} = await this.sourceToId(source);
this.coll = coll;
const resp = await fetch(`/wabac/api/${coll}`);
if (resp.status != 200) {
this.sourceUrl = source;
this.pageState = "load";
} else {
const json = await resp.json();
this.collInfo = json;
this.pageState = "coll";
}
return;
}
// Google Drive // Google Drive
let state = this.pageParams.get("state"); let state = this.pageParams.get("state");
@@ -72,53 +54,22 @@ class AppMain extends LitElement
} }
} }
this.sourceUrl = this.pageParams.get("source") || "";
this.pageState = "index";
}
async sourceToId(url) {
try {
url = new URL(url, window.location.origin).href;
} catch(e) {}
const digest = await digestMessage(url, 'SHA-256');
const coll = "id-" + digest.slice(0, 12);
return {url, coll};
}
onCollLoaded(event) {
this.updateRoute();
} }
render() { render() {
return html` return html`
<link href="./dist/frontend.css" rel="stylesheet"/> <link href="./dist/frontend.css" rel="stylesheet"/>
<section class="section"> <section class="container">
<div class="level"> <div class="level">
<h1 class="level-item has-text-centered title is-1 is-family-sans-serif has-text-weight-bold">Webrecorder Viewer</h1> <h1 class="level-item has-text-centered title is-1 is-family-sans-serif has-text-weight-bold">Webrecorder Viewer</h1>
</div> </div>
</section> </section>
${this.renderContent()} ${this.sourceUrl ? html`
<wr-coll sourceUrl="${this.sourceUrl}"></wr-coll>
` : this.sourceUrl === "" ? html`<wr-index></wr-index>` : html``}
`; `;
} }
renderContent() {
switch (this.pageState) {
case "load":
return html`<wr-loader .coll="${this.coll}" .sourceUrl="${this.sourceUrl}" @coll-loaded=${this.onCollLoaded}></wr-loader>`;
case "coll":
return html`<wr-coll style="flex: 1" .coll="${this.coll}" .collInfo="${this.collInfo}"></wr-coll>`;
case "index":
return html`<wr-index style="flex: 1" .coll="${this.coll}" .collInfo="${this.collInfo}"></wr-index>`;
default:
return html``;
}
}
//createRenderRoot() { return this; }
} }
// =========================================================================== // ===========================================================================
@@ -247,8 +198,6 @@ class WrLoader extends LitElement
return html`<progress class="progress is-primary is-large" style="max-width: 400px"/>`; return html`<progress class="progress is-primary is-large" style="max-width: 400px"/>`;
} }
} }
//createRenderRoot() { return this; }
} }
// =========================================================================== // ===========================================================================
@@ -266,33 +215,7 @@ class WrIndex extends LitElement
} }
static get styles() { static get styles() {
return css` return css``;
fa-icon {
cursor: pointer;
display: inline-flex;
}
fa-icon.fa-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear; }
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg); }
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
`;
} }
firstUpdated() { firstUpdated() {
@@ -353,8 +276,6 @@ class WrIndex extends LitElement
</section> </section>
`; `;
} }
//createRenderRoot() { return this; }
} }
// =========================================================================== // ===========================================================================
@@ -362,118 +283,278 @@ class WrColl extends LitElement
{ {
constructor() { constructor() {
super(); super();
this.sourceUrl = null;
this.baseApiPrefix = "/wabac/api";
this.baseReplayPrefix = "/wabac";
this.apiPrefix = "";
this.replayPrefix = "";
this.coll = ""; this.coll = "";
this.offset = 0;
this.currList = 0; this.collInfo = null;
this.bookmarks = {};
this.collInfo = {lists: []};
this.currList = null;
this.lastST = 0;
this.hasCurated = false; this.hasCurated = false;
this.currTab = "";
this.clickTime = 0; this.tabData = {};
} }
static get properties() { static get properties() {
return { return {
hasCurated: { type: Boolean }, sourceUrl: { type: String },
collInfo: { type: Object }, collInfo: { type: Object },
coll: { type: String }, coll: { type: String },
bookmarks: { type: Object },
currList: { type: Number },
currTab: { type: String }
}
}
async doLoadBookmarks() { hasCurated: { type: Boolean },
this.hasCurated = (this.collInfo.lists && this.collInfo.lists.length);
this.bookmarks = {};
if (!this.hasCurated) { tabData: { type: Object }
return;
}
const resp = await fetch(`/wabac/api/${this.coll}/bookmarks?offset=${this.offset}`);
const json = await resp.json();
this.total = json.total;
for (const bookmark of json.bookmarks) {
if (!this.bookmarks[bookmark.list]) {
this.bookmarks[bookmark.list] = [];
}
this.bookmarks[bookmark.list].push(bookmark);
} }
} }
firstUpdated() { firstUpdated() {
window.addEventListener("hashchange", () => this.onHashChange()); window.addEventListener("hashchange", (event) => this.onHashChange(event));
this.doUpdateInfo().then(() => this.onHashChange());
}
async sourceToId(url) {
try {
url = new URL(url, window.location.origin).href;
} catch(e) {}
const digest = await digestMessage(url, 'SHA-256');
const coll = "id-" + digest.slice(0, 12);
return {url, coll};
}
updated(changedProperties) {
if (changedProperties.get("sourceUrl")) {
this.doUpdateInfo();
}
if (changedProperties.get("tabData")) {
this._manualHash = true;
// don't add empty params to shorten query
Object.keys(this.tabData).
forEach(key => !this.tabData[key] && delete this.tabData[key]);
window.location.hash = "#" + new URLSearchParams(this.tabData).toString();
}
}
async doUpdateInfo() {
const {url, coll} = await this.sourceToId(this.sourceUrl);
this.coll = coll;
const apiPrefix = this.baseApiPrefix + "/" + coll;
const replayPrefix = this.baseReplayPrefix + "/" + coll;
const resp = await fetch(apiPrefix);
if (resp.status != 200) {
this.collInfo = {};
this.hasCurated = false;
return;
}
const json = await resp.json();
this.collInfo = {apiPrefix, replayPrefix, coll, ...json};
if (!this.collInfo.title) { if (!this.collInfo.title) {
this.collInfo.title = "Archive from " + this.collInfo.displayName; this.collInfo.title = "Archive from " + this.collInfo.displayName;
} }
this.doLoadBookmarks().then(() => this.onHashChange()); this.hasCurated = (this.collInfo.lists && this.collInfo.lists.length);
} }
onHashChange() { onCollLoaded(event) {
const hash = window.location.hash; this.doUpdateInfo();
if (!hash) { }
this.currTab = this.hasCurated ? "curated" : "resources";
onHashChange(event) {
if (this._manualHash) {
this._manualHash = false;
return; return;
} }
const hash = window.location.hash;
if (hash === "#resources") { if (hash) {
this.currTab = "resources"; this.tabData = Object.fromEntries(new URLSearchParams(hash.slice(1)).entries());
} else if (hash === "#curated") {
this.currTab = "curated";
} }
if (!this.tabData.currTab) {
if (hash.startsWith("#list-")) { this.tabData = {...this.tabData, currTab: this.hasCurated ? "curated" : "resources"};
const id = hash.slice(6);
this.currTab = "curated";
this.scrollToList(id);
}
}
updated(changedProperties) {
if (changedProperties.get("lists")) {
this.doLoadBookmarks();
} }
} }
onTabClick(event) { onTabClick(event) {
event.preventDefault(); event.preventDefault();
const hash = event.target.getAttribute("href"); const hash = event.target.getAttribute("href");
//this.currTab = hash.slice(1); this.tabData = {...this.tabData, currTab: hash.slice(1)};
window.location.hash = hash;
return false; return false;
} }
onCollTabNav(event) {
this.tabData = {...this.tabData, ...event.detail};
}
render() { render() {
return html` return html`
<link href="./dist/frontend.css" rel="stylesheet"/> <link href="./dist/frontend.css" rel="stylesheet"/>
${this.renderColl()}
`;
}
renderColl() {
if (this.collInfo && !this.collInfo.coll) {
return html`<wr-loader .coll="${this.coll}" .sourceUrl="${this.sourceUrl}" @coll-loaded=${this.onCollLoaded}></wr-loader>`;
} else if (this.collInfo) {
return html`
<nav class="panel is-primary"> <nav class="panel is-primary">
<div class="panel-heading">${this.collInfo.title} <div class="panel-heading">${this.collInfo.title}
<a @click="${this.deleteColl}" class="is-pulled-right delete"></a> <a @click="${this.deleteColl}" class="is-pulled-right delete"></a>
</div> </div>
<p class="panel-tabs is-boxed"> <p class="panel-tabs is-boxed">
${this.hasCurated ? html` ${this.hasCurated ? html`
<a @click="${this.onTabClick}" href="#curated" class="is-size-6 ${this.currTab === 'curated' ? 'is-active' : ''}">Curated Pages</a> <a @click="${this.onTabClick}" href="#curated" class="is-size-6 ${this.tabData.currTab === 'curated' ? 'is-active' : ''}">Curated Pages</a>
` : ``}
<a @click="${this.onTabClick}" href="#resources" class="is-size-6 ${this.tabData.currTab === 'resources' ? 'is-active' : ''}">URL Resources</a>
${this.tabData.replayUrl ? html`
<a @click="${this.onTabClick}" href="#replay" class="is-size-6 ${this.tabData.currTab === 'replay' ? 'is-active' : ''}">Replay!</a>
` : ``} ` : ``}
<a @click="${this.onTabClick}" href="#resources" class="is-size-6 ${this.currTab === 'resources' ? 'is-active' : ''}">URL Resources</a>
</p> </p>
${this.hasCurated ? html` ${this.renderCollTabs()}
<section id="curated" class="panel-block " style="display: ${this.currTab == 'curated' ? 'flex' : 'none'}"> </nav>`;
} else {
return html``;
}
}
renderCollTabs() {
return html`
<wr-coll-curated .collInfo="${this.collInfo}"
currList="${this.tabData.currList || 0}"
@coll-tab-nav="${this.onCollTabNav}" id="curated" class="panel-block ${this.tabData.currTab === 'curated' ? '' : 'is-hidden'}"
></wr-coll-curated>
<wr-coll-resources .collInfo="${this.collInfo}"
urlSearch="${this.tabData.urlSearch || ""}"
urlSearchType="${this.tabData.urlSearchType || ""}"
currMime="${this.tabData.currMime || ""}"
@coll-tab-nav="${this.onCollTabNav}" id="resources" class="panel-block is-paddingless ${this.tabData.currTab === 'resources' ? '' : 'is-hidden'}">
</wr-coll-resources>
${this.tabData.currTab === "replay" ? html`
<wr-replay-page .collInfo="${this.collInfo}" replayUrl="${this.tabData.replayUrl}" replayTS="${this.tabData.replayTS}">
</wr-replay-page>
` : ``}
`;
switch (this.tabData.currTab) {
case "curated":
return html`
<wr-coll-curated .collInfo="${this.collInfo}"
currList="${this.tabData.currList || 0}"
@coll-tab-nav="${this.onCollTabNav}" id="curated" class="panel-block"
></wr-coll-curated>`;
case "resources":
return html`
<wr-coll-resources .collInfo=${this.collInfo}
urlSearch="${this.tabData.urlSearch || ""}"
urlSearchType="${this.tabData.urlSearchType || "exact"}"
currMime="${this.tabData.currMime || ""}"
@coll-tab-nav="${this.onCollTabNav}" id="resources" class="panel-block is-paddingless">
</wr-coll-resources>`;
default:
return html``;
}
}
}
// ===========================================================================
class WrCuratedPages extends LitElement
{
constructor() {
super();
this.collInfo = null;
this.currList = 0;
this.curatedPages = {};
this.offset = 0;
this.lastST = 0;
this.clickTime = 0;
}
static get properties() {
return {
collInfo: { type: Object },
curatedPages: { type: Object },
currList: { type: Number },
}
}
static get styles() {
return css`
.column {
max-height: calc(100vh - 145px);
}
#content {
margin-top: 10px;
max-height: calc(100vh - 155px);
}
`;
}
firstUpdated() {
this.doLoadCurated();
}
updated(changedProperties) {
if (changedProperties.get("collInfo")) {
this.doLoadCurated();
}
}
async doLoadCurated() {
this.curatedPages = {};
const resp = await fetch(`${this.collInfo.apiPrefix}/curatedPages?offset=${this.offset}`);
const json = await resp.json();
this.total = json.total;
for (const curated of json.curatedPages) {
if (!this.curatedPages[curated.list]) {
this.curatedPages[curated.list] = [];
}
this.curatedPages[curated.list].push(curated);
}
if (this.currList) {
this.scrollToList(this.currList);
}
}
render() {
return html`
<link href="./dist/frontend.css" rel="stylesheet"/>
<div class="columns"> <div class="columns">
<div class="column is-one-third" style="max-height: calc(100vh - 241px)"> <div class="column is-one-third">
<div class="menu" style="overflow-y: auto; height: 100%;"> <div class="menu" style="overflow-y: auto; height: 100%;">
<ul class="menu-list"> <ul class="menu-list">
<li> <li>
<a href="#list-0" class="${!this.currList ? 'is-active' : ''}" <a href="#list-0" class="${!this.currList ? 'is-active' : ''}"
@click=${(e) => this.scrollToList(0)}>${this.collInfo.title}</a> @click=${this.onClickScroll}>${this.collInfo.title}</a>
<ul class="menu-list">${this.collInfo.lists.map(list => html` <ul class="menu-list">${this.collInfo.lists.map(list => html`
<li> <li>
<a @click=${this.onClickScroll} href="#list-${list.id}" <a @click=${this.onClickScroll} href="#list-${list.id}"
@@ -485,22 +566,27 @@ class WrColl extends LitElement
</ul> </ul>
</div> </div>
</div> </div>
<div id="content" @scroll=${this.onScroll} class="column main-scroll" style="max-height: calc(100vh - 241px)"> <div id="content" @scroll=${this.onScroll} class="column main-scroll">
<section id="list-0" class="container"> <section id="list-0" class="container">
<h2 class="title is-3">${this.collInfo.title}</h2> <h2 class="title is-3">${this.collInfo.title}</h2>
${unsafeHTML(marked(this.collInfo.desc))} ${this.collInfo.desc ? unsafeHTML(marked(this.collInfo.desc)) : ''}
</section> </section>
${this.renderContent()} ${this.renderContent()}
</div> </div>
</div> </div>
</section>
` : ``}
<wr-coll-resources .coll=${this.coll} id="resources" class="panel-block is-paddingless" style="display: ${this.currTab == 'resources' ? 'initial' : 'none'}">
</wr-coll-resources>
</nav>
`; `;
} }
onReplay(event) {
event.preventDefault();
const detail = {replayUrl: event.currentTarget.getAttribute("data-url"),
replayTS: event.currentTarget.getAttribute("data-ts"),
currTab: "replay"
}
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail}));
return false;
}
renderContent() { renderContent() {
return html` return html`
${this.collInfo.lists.map((list, i) => html` ${this.collInfo.lists.map((list, i) => html`
@@ -510,15 +596,15 @@ class WrColl extends LitElement
<hr/> <hr/>
<div class="content">${list.desc}</div> <div class="content">${list.desc}</div>
<ol style="margin-left: 30px"> <ol style="margin-left: 30px">
${this.bookmarks[list.id] ? this.bookmarks[list.id].map((b) => html` ${this.curatedPages[list.id] ? this.curatedPages[list.id].map((p) => html`
<li><article class="media"> <li><article class="media">
<div class="media-content"> <div class="media-content">
<a href="${this.bookmarkUrl(b)}"> <a @click="${this.onReplay}" data-url="${p.url}" data-ts="${getTS(p.date)}" href="${this.collInfo.replayPrefix}/${getTS(p.date)}/${p.url}">
<p>${b.title}</p> <p>${p.title}</p>
<p>${b.url}</p> <p>${p.url}</p>
</a> </a>
<p>${b.date}</p> <p>${p.date}</p>
<p>${b.desc}</p> <p>${p.desc}</p>
</div> </div>
</article></li> </article></li>
`) : html``} `) : html``}
@@ -530,11 +616,14 @@ class WrColl extends LitElement
} }
onClickScroll(event) { onClickScroll(event) {
event.preventDefault();
this.scrollToList(event.target.getAttribute("data-list")); this.scrollToList(event.target.getAttribute("data-list"));
return false;
} }
scrollToList(id) { scrollToList(id) {
this.currList = Number(id); this.currList = Number(id);
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail: {currList: this.currList || undefined}}));
const opts = {behavior: "smooth", block: "start", inline: "nearest"}; const opts = {behavior: "smooth", block: "start", inline: "nearest"};
this.clickTime = new Date().getTime(); this.clickTime = new Date().getTime();
this.renderRoot.getElementById("list-" + this.currList).scrollIntoView(opts); this.renderRoot.getElementById("list-" + this.currList).scrollIntoView(opts);
@@ -565,6 +654,7 @@ class WrColl extends LitElement
if (next && next != curr) { if (next && next != curr) {
if (next.id.startsWith("list-")) { if (next.id.startsWith("list-")) {
this.currList = Number(next.id.slice(5)); this.currList = Number(next.id.slice(5));
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail: {currList: this.currList}}));
} }
} }
@@ -578,12 +668,6 @@ class WrColl extends LitElement
sel.scrollIntoView(opts); sel.scrollIntoView(opts);
} }
} }
bookmarkUrl(b) {
return `/wabac/${this.coll}/${getTS(b.date)}/${b.url}`;
}
//createRenderRoot() { return this; }
} }
// =========================================================================== // ===========================================================================
@@ -591,15 +675,19 @@ class WrResources extends LitElement
{ {
constructor() { constructor() {
super(); super();
this.collInfo = null;
this.currMime = "text/html,text/xhtml"; this.currMime = "text/html,text/xhtml";
this.results = []; this.urlSearch = "";
this.urlSearchType = "";
this.filteredResults = []; this.filteredResults = [];
this.results = [];
this.tryMore = false; this.tryMore = false;
this.loading = false; this.loading = false;
this.urlSearch = "";
this.urlSearchType = "exact";
this.filters = [ this.filters = [
{name: "HTML", filter: "text/html,text/xhtml"}, {name: "HTML", filter: "text/html,text/xhtml"},
{name: "Images", filter: "image/"}, {name: "Images", filter: "image/"},
@@ -611,17 +699,27 @@ class WrResources extends LitElement
static get properties() { static get properties() {
return { return {
coll: { type: String }, collInfo: { type: Object },
currMime: { type: String }, currMime: { type: String },
//filterText: { type: String }, urlSearch: { type: String },
urlSearchType: { type: String },
filteredResults: { type: Array }, filteredResults: { type: Array },
//loading: { type: Boolean }
} }
} }
static get styles() { static get styles() {
return css` return css`
:host {
display: flex;
flex-direction: column;
}
.notification {
width: 100%;
}
.main-scroll {
max-height: calc(100vh - 295px);
width: 100vw;
}
table { table {
table-layout: fixed; table-layout: fixed;
word-wrap: break-word; word-wrap: break-word;
@@ -640,8 +738,16 @@ class WrResources extends LitElement
.col-ts { .col-ts {
width: 16%; width: 16%;
max-width: 16%; max-width: 16%;
min-width: 16%;
word-break: break-word; word-break: break-word;
} }
td.col-mime {
width: 10%;
word-break: break-word;
}
td.col-status {
text-align: center;
}
.loading-cog { .loading-cog {
width: 100vw; width: 100vw;
display: flex; display: flex;
@@ -658,13 +764,20 @@ class WrResources extends LitElement
const url = (this.urlSearchType !== "contains" ? this.urlSearch : ""); const url = (this.urlSearchType !== "contains" ? this.urlSearch : "");
const prefix = url && this.urlSearchType === "prefix" ? 1 : 0; const prefix = url && this.urlSearchType === "prefix" ? 1 : 0;
const detail = {urlSearch: this.urlSearch,
currMime: this.currMime,
urlSearchType: this.urlSearchType};
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail}));
const params = new URLSearchParams({ const params = new URLSearchParams({
mime: this.currMime, mime: this.currMime,
url, url,
prefix, prefix,
count count
}).toString(); }).toString();
let resp = await fetch(`/wabac/api/${this.coll}/urls?${params}`);
let resp = await fetch(`${this.collInfo.apiPrefix}/urls?${params}`);
resp = await resp.json(); resp = await resp.json();
this.results = resp.urls; this.results = resp.urls;
this.tryMore = (resp.urls.length === count); this.tryMore = (resp.urls.length === count);
@@ -696,7 +809,7 @@ class WrResources extends LitElement
count count
}).toString(); }).toString();
let resp = await fetch(`/wabac/api/${this.coll}/urls?${params}`); let resp = await fetch(`${this.collInfo.apiPrefix}/urls?${params}`);
resp = await resp.json(); resp = await resp.json();
this.results = this.results.concat(resp.urls); this.results = this.results.concat(resp.urls);
console.log(resp.urls.length); console.log(resp.urls.length);
@@ -705,7 +818,7 @@ class WrResources extends LitElement
this.loading = false; this.loading = false;
} }
onChangeSearch(event) { onChangeTypeSearch(event) {
this.currMime = event.target.value; this.currMime = event.target.value;
this.doLoadResources(); this.doLoadResources();
} }
@@ -746,9 +859,9 @@ class WrResources extends LitElement
<div class="notification level is-marginless"> <div class="notification level is-marginless">
<div class="control level-left"> <div class="control level-left">
<div> <div>
<input type="text" style="width: 400px" class="input level-item" @input="${this.onChangeUrlSearch}" type="text" placeholder="Search URL"> <input type="text" style="width: 400px" class="input level-item" @input="${this.onChangeUrlSearch}" value="${this.urlSearch}" type="text" placeholder="Search URL">
<div class="control"> <div class="control">
<label class="radio has-text-left"><input type="radio" name="urltype" value="exact" ?checked="${this.urlSearchType === 'exact'}" @click="${this.onClickUrlType}">&nbsp;Exact</label> <label class="radio has-text-left"><input type="radio" name="urltype" value="exact" ?checked="${this.urlSearchType === ''}" @click="${this.onClickUrlType}">&nbsp;Exact</label>
<label class="radio has-text-left"><input type="radio" name="urltype" value="prefix" ?checked="${this.urlSearchType === 'prefix'}" @click="${this.onClickUrlType}">&nbsp;Prefix</label> <label class="radio has-text-left"><input type="radio" name="urltype" value="prefix" ?checked="${this.urlSearchType === 'prefix'}" @click="${this.onClickUrlType}">&nbsp;Prefix</label>
<label class="radio has-text-left"><input type="radio" name="urltype" value="contains" ?checked="${this.urlSearchType === 'contains'}" @click="${this.onClickUrlType}">&nbsp;Contains</label> <label class="radio has-text-left"><input type="radio" name="urltype" value="contains" ?checked="${this.urlSearchType === 'contains'}" @click="${this.onClickUrlType}">&nbsp;Contains</label>
</div> </div>
@@ -761,7 +874,7 @@ class WrResources extends LitElement
<label class="radio has-text-left"> <label class="radio has-text-left">
<input type="radio" name="mime" <input type="radio" name="mime"
value="${filter.filter}" value="${filter.filter}"
@click="${this.onChangeSearch}" @click="${this.onChangeTypeSearch}"
?checked="${filter.filter === this.currMime}" ?checked="${filter.filter === this.currMime}"
> >
${filter.name} ${filter.name}
@@ -775,18 +888,18 @@ class WrResources extends LitElement
<tr> <tr>
<th class="col-url">URL</th> <th class="col-url">URL</th>
<th class="col-ts">Timestamp</th> <th class="col-ts">Timestamp</th>
<th>Mime</th> <th class="col-mime">Mime</th>
<th>Status</th> <th class="col-status">Status</th>
</tr> </tr>
</thead> </thead>
<tbody class="main-scroll" @scroll="${this.onScroll}" style="max-height: calc(100vh - 391px); width: 100vw"> <tbody class="main-scroll" @scroll="${this.onScroll}">
${this.filteredResults.length ? ${this.filteredResults.length ?
this.filteredResults.map((result) => html` this.filteredResults.map((result) => html`
<tr> <tr>
<td class="col-url"><a href="/wabac/${this.coll}/${result.ts}/${result.url}">${result.url}</a></td> <td class="col-url"><a @click="${this.onReplay}" data-url="${result.url}" data-ts="${result.ts}" href="${this.collInfo.replayPrefix}/${result.ts}/${result.url}">${result.url}</a></td>
<td class="col-ts">${new Date(result.date).toLocaleString()}</td> <td class="col-ts">${new Date(result.date).toLocaleString()}</td>
<td>${result.mime}</td> <td class="col-mime">${result.mime}</td>
<td>${result.status}</td> <td class="col-status">${result.status}</td>
</tr> </tr>
`) : html`<div class="section"><i>No Results Found.</i></div>`} `) : html`<div class="section"><i>No Results Found.</i></div>`}
</tbody> </tbody>
@@ -794,6 +907,48 @@ class WrResources extends LitElement
</div> </div>
`; `;
} }
onReplay(event) {
event.preventDefault();
const detail = {replayUrl: event.currentTarget.getAttribute("data-url"),
replayTS: event.currentTarget.getAttribute("data-ts"),
currTab: "replay"
}
this.dispatchEvent(new CustomEvent("coll-tab-nav", {detail}));
return false;
}
}
// ===========================================================================
class WrReplayPage extends LitElement
{
static get properties() {
return {
collInfo: {type: Object },
replayUrl: { type: String },
replayTS: { type: String }
}
}
static get styles() {
return css`
host: {
display: flex;
}
iframe {
width: 100vw;
height: calc(100vh - 150px);
}
`;
}
render() {
return html`
<iframe src="${this.collInfo.replayPrefix}/${this.replayTS || ""}mp_/${this.replayUrl}"></iframe>
`;
}
} }
// =========================================================================== // ===========================================================================
@@ -876,18 +1031,56 @@ class WrGdrive extends LitElement
} }
} }
// ===========================================================================
class WrCollProxy extends LitElement
{
constructor() {
super();
this.currTab = "replay";
this.replayTS = "";
}
static get properties() {
return {
replayUrl: { type: String },
replayTS: { type: String },
source: { type: String },
paramString: { type: String }
}
}
firstUpdated() {
this.paramString = new URLSearchParams({
replayUrl: this.replayUrl,
replayTS: this.replayTS,
source: this.source,
currTab: this.currTab
});
}
render() {
return html`
<iframe src="http://localhost:9990/?${this.paramString}"></iframe>
`;
}
}
// =========================================================================== // ===========================================================================
// =========================================================================== // ===========================================================================
async function main() { async function main() {
const swPromise = initSW("swonly.js?replayPrefix=wabac&stats=true"); const swPromise = initSW("./dist/swonly.js?replayPrefix=wabac&stats=true");
await swPromise; await swPromise;
customElements.define("app-main", AppMain); customElements.define("app-main", AppMain);
customElements.define("wr-index", WrIndex); customElements.define("wr-index", WrIndex);
customElements.define("wr-loader", WrLoader); customElements.define("wr-loader", WrLoader);
customElements.define("wr-coll", WrColl); customElements.define("wr-coll", WrColl);
customElements.define("wr-coll-proxy", WrCollProxy);
customElements.define("wr-coll-resources", WrResources); customElements.define("wr-coll-resources", WrResources);
customElements.define("wr-coll-curated", WrCuratedPages);
customElements.define("wr-replay-page", WrReplayPage);
customElements.define("wr-gdrive", WrGdrive); customElements.define("wr-gdrive", WrGdrive);
} }