import { LitElement, html, css } from 'lit-element'; import { wrapCss, rwpLogo, IS_APP } from './misc'; import { sourceToId, tsToDate } from './pageutils'; import fasBook from '@fortawesome/fontawesome-free/svgs/solid/book.svg'; import farListAlt from '@fortawesome/fontawesome-free/svgs/regular/list-alt.svg'; import farResources from '@fortawesome/fontawesome-free/svgs/solid/puzzle-piece.svg'; import farPages from '@fortawesome/fontawesome-free/svgs/regular/file-image.svg'; 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'; const RWP_SCHEME = "search://"; // =========================================================================== class Coll extends LitElement { constructor() { super(); this.sourceUrl = null; this.inited = false; this.isLoading = false; this.baseApiPrefix = "./wabac/api"; this.baseReplayPrefix = "./wabac"; this.apiPrefix = ""; this.replayPrefix = ""; this.coll = ""; this.collInfo = null; this._replaceLoc = false; this._locUpdateNeeded = false; this._locationHash = ""; this.tabData = {}; this.url = ""; this.ts = ""; this.tabNames = ["pages", "story", "resources", "replay"]; this.menuActive = false; this.hasStory = false; this.editable = false; } static get properties() { return { inited: { type: Boolean }, sourceUrl: { type: String }, loadInfo: { type: Object, attribute: false }, collInfo: { type: Object, attribute: false }, coll: { type: String }, hasStory: { type: Boolean }, isLoading: { type: Boolean }, tabData: { type: Object, attribute: false }, url: { type: String }, ts: { type: String }, isFullscreen: { type: Boolean }, menuActive: { type: Boolean }, embed: { type: String }, editable: { type: Boolean } } } firstUpdated() { //this.doUpdateInfo(); this.inited = true; window.addEventListener("hashchange", (event) => this.onHashChange(event)); this.addEventListener("fullscreenchange", (event) => { this.isFullscreen = !!document.fullscreenElement; }); } updated(changedProperties) { // if (changedProperties.has("url") || changedProperties.has("ts")) { // 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")) { this.doUpdateInfo(); } if (changedProperties.has("tabData")) { if (!this.collInfo || !this.collInfo.coll) { return; } // don't add empty params to shorten query Object.keys(this.tabData). forEach(key => !this.tabData[key] && delete this.tabData[key]); 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) { this._locationHash = newHash; if (this._replaceLoc || Object.keys(changedProperties.get("tabData")).length === 0) { const newLoc = new URL(window.location.href); newLoc.hash = this._locationHash; window.history.replaceState({}, "", newLoc.href); this._replaceLoc = false; } else { window.location.hash = this._locationHash; } if (this.embed && window.parent !== window) { window.parent.postMessage(this.tabData, '*'); } } this._locUpdateNeeded = false; } } async doUpdateInfo() { let coll = this.loadInfo && this.loadInfo.customColl; if (!coll) { const res = await sourceToId(this.sourceUrl); coll = res.coll; } this.coll = coll; const apiPrefix = this.baseApiPrefix + "/" + coll; const replayPrefix = this.baseReplayPrefix + "/" + coll; const resp = await fetch(apiPrefix + "?all=1"); if (resp.status != 200) { this.collInfo = {}; return; } const json = await resp.json(); this.collInfo = {apiPrefix, replayPrefix, coll, ...json}; if (!this.collInfo.title) { this.collInfo.title = this.collInfo.filename; } this.hasStory = this.collInfo.desc || this.collInfo.lists.length; this.dispatchEvent(new CustomEvent("coll-loaded", {detail: { collInfo: this.collInfo, alreadyLoaded: true }})); this.onHashChange(); } onCollLoaded(event) { this.doUpdateInfo(); this.loadInfo = null; this.dispatchEvent(new CustomEvent("coll-loaded", {detail: { sourceUrl: this.sourceUrl, collInfo: this.collInfo, }})); } onHashChange(event) { const hash = window.location.hash; if (hash && hash !== this._locationHash) { this.tabData = Object.fromEntries(new URLSearchParams(hash.slice(1)).entries()); this._locationHash = hash; } if (this.collInfo.coll && !this.tabNames.includes(this.tabData.view)) { const view = this.hasStory ? "story" : (this.collInfo.pages.length ? "pages" : "resources"); this.tabData = { ...this.tabData, view }; } } onTabClick(event) { event.preventDefault(); const hash = event.currentTarget.getAttribute("href"); this.tabData = {...this.tabData, view: hash.slice(1)}; //this.tabData = {view: hash.slice(1)}; return false; } onCollTabNav(event) { if (event.target.id === this.tabData.view) { this.updateTabData(event.detail.data, event.detail.replaceLoc); } } 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() { return wrapCss(css` .icon { vertical-align: text-top; } .back fa-icon { width: 1.5em; vertical-align: bottom; line-height: 0.5em; } li.is-active { font-weight: bold; } .tab-label { display: inline; } @media screen and (max-width: ${!IS_APP ? css`1053px` : css`1163px`}) { .tab-label { display: none; } .main.tabs span.icon { margin: 0px; } } .main.tabs { display: flex; flex-direction: row; margin-bottom: 0px; } .main.tabs li { line-height: 1.5; padding: 8px 0 6px 0; } @media screen and (max-width: 319px) { .main.tabs li a { padding-right: 4px; padding-left: 4px; } } #contents { height: 100%; width: 100%; display: flex; 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; } .grey-disabled { --fa-icon-fill-color: lightgrey; color: lightgrey; } .replay-bar .button:focus { box-shadow: none; } .dropdown .button { padding-right: 0px; } .is-borderless { border: 0px; } .modal { top: 174px; } form { width: 100%; } `; } render() { if (!this.inited) return html``; if (this.collInfo && !this.collInfo.coll) { return html` `; } else if (this.collInfo) { return html` `; } else { return html``; } } renderTabHeader() { if (this.tabData.view === "replay") { return ""; } return html`
`; } renderLocationBar() { const dateStr = tsToDate(this.ts).toLocaleString(); const isReplay = this.tabData.view === "replay"; return html`
${isReplay ? html`

${dateStr}

` : html``}
`; } renderCollTabs() { const isStory = this.tabData.view === 'story'; const isPages = this.tabData.view === 'pages'; const isResources = this.tabData.view === 'resources'; const isReplay = this.tabData.view === 'replay'; return html` ${this.hasStory ? html` ` : ''} ${isReplay ? html` ` : ``} `; } onKeyDown(event) { if (event.key === "Esc" || event.key === "Escape") { event.target.value = this.url; } } 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(event) { event.preventDefault(); if (this.tabData && this.tabData.view === "replay") { this.updateTabData({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(); } } else { window.location.reload(); } } } customElements.define("wr-coll", Coll); export { Coll };