1.4.0 Release (#45)
* customizations for chooser, coll-index and appmain to support usage in archiveweb.page - chooser: support panel/message view - move apiPrefix to misc - make coll-index extensible, overridable styles, filtering * api changes: make configurable in coll-index, now using '/w/' instead of '/wabac/', '/c/' prefix for coll apis * lint pass! * bulma: update to 0.9.2, fix delete spinner with latest bulma * ui fixes: - show 'Loading Archives...' on initial load until first api response succeeds - fix typo in oncontrollerchange not actually resolving the promise! * embed sandbox: add other allow options, except top-nav - first api load: keep loading message until first successful api load - don't reset hash on purge to keep current page - sw config: fix typo with latest wabac.js - embed: add 'noSandbox' option to avoid adding sandbox to iframe, needed to show PDFs, add more allow rules (all except top-navigation) * ui improvements: - refresh: ensure location refresh from hitting enter in location bar always resets url - pageentry doubleclick: ensure double-clicking on page in sidebar always triggers reload, even if current page - pageentry typo fix: fix missing var causing selection error (fixes webrecorder/archivewebpage#25) - lint: don't include 'event' as global - use latest wabac.js 2.7.0-beta.1 * add CHANGES for 1.4.0, add 'noSandbox' to embedding options - electron app: fix path to 'w/' - bump electron to 11.4.3 * docs: autoload current version from package.json - chooser: support .json files for multiwacz (experimental) - update CHANGES.md - add missing .eslintrc.js file * bump version to 1.4.0
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
module.exports = {
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2018,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"no-restricted-globals": [
|
||||||
|
2,
|
||||||
|
"event", "error"
|
||||||
|
],
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"linebreak-style": [
|
||||||
|
"error",
|
||||||
|
"unix"
|
||||||
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"double"
|
||||||
|
],
|
||||||
|
"semi": [
|
||||||
|
"error",
|
||||||
|
"always"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
+17
@@ -1,5 +1,22 @@
|
|||||||
## CHANGES
|
## CHANGES
|
||||||
|
|
||||||
|
v1.4.0
|
||||||
|
- Embed: add 'noSandbox' option to not add sandbox to embed iframe
|
||||||
|
- UI: Double-clicking on page entry causes reload.
|
||||||
|
- UI: Fix location bar enter not always reloading specified URL
|
||||||
|
- UI: Fix 'Purge and Reload' to reload current page
|
||||||
|
- UI: Fix initial load not properly waiting for service worker
|
||||||
|
- UI: Show 'Loading Archives...' on initial load, until first API response succeeds, instead of 'No Archives'
|
||||||
|
- Fidelity: Improved fuzzy matching for dynamic sites
|
||||||
|
- Fidelity: Fix for multipart/form-data replay dropping certain query params
|
||||||
|
- Fidelity: don't remove spaces in css urls
|
||||||
|
- Fidelity: Better detection of JSON responses served in response to 'Accept: application/json' but with wrong content-type
|
||||||
|
- Docs: copy package.json to 'data' to allow access to version in UI, use latest fixed version in Collec
|
||||||
|
- API: Switch from /wabac/ -> /w/ for replay paths, make path configurable
|
||||||
|
- Extensibility: Make file chooser, collection list more extensible/stylable (for use with archiveweb.page)
|
||||||
|
- Lint pass on code base
|
||||||
|
- Dependencies: wabac 2.7.0, bulma 0.9.2, electron 11.4.3
|
||||||
|
|
||||||
v1.3.15
|
v1.3.15
|
||||||
- Fidelity: fix encoding issues with UTF-8 encoded JS/CSS introduced in 1.3.13 (fixed via wabac 2.6.9)
|
- Fidelity: fix encoding issues with UTF-8 encoded JS/CSS introduced in 1.3.13 (fixed via wabac 2.6.9)
|
||||||
- Dependencies: wabac 2.6.9
|
- Dependencies: wabac 2.6.9
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ logo: "/assets/logo.svg"
|
|||||||
plugins:
|
plugins:
|
||||||
- jekyll-remote-theme
|
- jekyll-remote-theme
|
||||||
|
|
||||||
|
|
||||||
version:
|
|
||||||
- 1.3.12
|
|
||||||
|
|
||||||
#baseUrl: '/'
|
#baseUrl: '/'
|
||||||
|
|
||||||
exclude:
|
exclude:
|
||||||
|
|||||||
+6
-5
@@ -23,7 +23,7 @@ the following snippet to your HTML page:
|
|||||||
my-web-archive-embed.html
|
my-web-archive-embed.html
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://cdn.jsdelivr.net/npm/replaywebpage@{{ site.version }}/ui.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/replaywebpage@{{ site.data.package.version }}/ui.js"></script>
|
||||||
<replay-web-page source="s3://webrecorder-builds/warcs/netpreserve-twitter.warc"
|
<replay-web-page source="s3://webrecorder-builds/warcs/netpreserve-twitter.warc"
|
||||||
url="https://twitter.com/netpreserve"></replay-web-page>
|
url="https://twitter.com/netpreserve"></replay-web-page>
|
||||||
```
|
```
|
||||||
@@ -39,7 +39,7 @@ one-line script
|
|||||||
./replay/sw.js
|
./replay/sw.js
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
importScripts("https://cdn.jsdelivr.net/npm/replaywebpage@{{ site.version }}/sw.js");
|
importScripts("https://cdn.jsdelivr.net/npm/replaywebpage@{{ site.data.package.version }}/sw.js");
|
||||||
```
|
```
|
||||||
|
|
||||||
Thus, if the HTML snippet was added to `https://my-site.example.com/path/my-web-archive-embed.html`
|
Thus, if the HTML snippet was added to `https://my-site.example.com/path/my-web-archive-embed.html`
|
||||||
@@ -71,16 +71,17 @@ The `<replay-web-page>` tag is a web component and supports a number of addition
|
|||||||
| `replayBase` | Location of the `sw.js` file, defaults to `./replay/` as mentioned above, but can be overridden. |
|
| `replayBase` | Location of the `sw.js` file, defaults to `./replay/` as mentioned above, but can be overridden. |
|
||||||
| `coll` | Internal id for this collection, usually generated automatically.
|
| `coll` | Internal id for this collection, usually generated automatically.
|
||||||
| `config` | Extra per collection config options (such as custom fuzzy matching rules, TODO add more info!) |
|
| `config` | Extra per collection config options (such as custom fuzzy matching rules, TODO add more info!) |
|
||||||
|
| `noSandbox` | (`true` / `false`) if set to true, don't wrap iframe in `sandbox`. Used as extra precaution to avoid escaping iframe, but prevents PDFs from loading in embed archive. Set for archives of known/trusted sites. |
|
||||||
|
|
||||||
|
|
||||||
### Versioning
|
### Versioning
|
||||||
|
|
||||||
Note that the above example uses the paths as, which is a CDN for Javascript packages at a specific version:
|
Note that the above example uses the paths as, which is a CDN for Javascript packages at a specific version:
|
||||||
|
|
||||||
- `https://cdn.jsdelivr.net/npm/replaywebpage@{{ site.version }}/ui.js`
|
- `https://cdn.jsdelivr.net/npm/replaywebpage@{{ site.data.package.version }}/ui.js`
|
||||||
- `https://cdn.jsdelivr.net/npm/replaywebpage@{{ site.version }}/sw.js`
|
- `https://cdn.jsdelivr.net/npm/replaywebpage@{{ site.data.package.version }}/sw.js`
|
||||||
|
|
||||||
These URLs point to a specific version of ReplayWeb.page software released on NPM, eg. `{{ site.version }}`, meaning that your replay should stay stable, even if ReplayWeb.page is updated.
|
These URLs point to a specific version of ReplayWeb.page software released on NPM, eg. `{{ site.data.package.version }}`, meaning that your replay should stay stable, even if ReplayWeb.page is updated.
|
||||||
|
|
||||||
Although ReplayWeb.page strives to remain backwards compatible, this addresses any potential issue of older embeds breaking when the replay system is updated.
|
Although ReplayWeb.page strives to remain backwards compatible, this addresses any potential issue of older embeds breaking when the replay system is updated.
|
||||||
|
|
||||||
|
|||||||
+6
-5
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "replaywebpage",
|
"name": "replaywebpage",
|
||||||
"productName": "ReplayWeb.page",
|
"productName": "ReplayWeb.page",
|
||||||
"version": "1.3.15",
|
"version": "1.4.0",
|
||||||
"description": "Serverless Web Archive Replay",
|
"description": "Serverless Web Archive Replay",
|
||||||
"repository": "https://github.com/webrecorder/replayweb.page",
|
"repository": "https://github.com/webrecorder/replayweb.page",
|
||||||
"homepage": "https://replayweb.page/",
|
"homepage": "https://replayweb.page/",
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.13.0",
|
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||||
"@webrecorder/wabac": "^2.6.9",
|
"@webrecorder/wabac": "^2.7.0",
|
||||||
"bulma": "^0.9.0",
|
"bulma": "^0.9.2",
|
||||||
"electron-log": "^4.3.0",
|
"electron-log": "^4.3.0",
|
||||||
"electron-updater": "^4.3.5",
|
"electron-updater": "^4.3.5",
|
||||||
"fetch-ndjson": "^1.1.0",
|
"fetch-ndjson": "^1.1.0",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"copy-webpack-plugin": "^6.3.0",
|
"copy-webpack-plugin": "^6.3.0",
|
||||||
"css-loader": "^3.5.3",
|
"css-loader": "^3.5.3",
|
||||||
"electron": "^11.3.0",
|
"electron": "^11.4.3",
|
||||||
"electron-builder": "^22.7.0",
|
"electron-builder": "^22.7.0",
|
||||||
"electron-notarize": "^1.0.0",
|
"electron-notarize": "^1.0.0",
|
||||||
"http-server": "^0.12.3",
|
"http-server": "^0.12.3",
|
||||||
@@ -62,7 +62,8 @@
|
|||||||
"start-jekyll": "yarn run build-docs && bundle exec jekyll serve",
|
"start-jekyll": "yarn run build-docs && bundle exec jekyll serve",
|
||||||
"dist": "yarn run build && yarn run pack",
|
"dist": "yarn run build && yarn run pack",
|
||||||
"dist-dev": "yarn run build-dev && yarn run pack",
|
"dist-dev": "yarn run build-dev && yarn run pack",
|
||||||
"release": "yarn run build && electron-builder"
|
"release": "yarn run build && electron-builder",
|
||||||
|
"lint": "eslint ./src/ webpack.config.js"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"afterSign": "build/notarize.js",
|
"afterSign": "build/notarize.js",
|
||||||
|
|||||||
+34
-30
@@ -1,11 +1,11 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { wrapCss, rwpLogo, IS_APP, clickOnSpacebarPress } from './misc';
|
import { wrapCss, rwpLogo, IS_APP, VERSION, clickOnSpacebarPress } from "./misc";
|
||||||
|
|
||||||
import { registerSW } from './pageutils';
|
import { registerSW } from "./pageutils";
|
||||||
|
|
||||||
import fasHelp from '@fortawesome/fontawesome-free/svgs/solid/question-circle.svg';
|
import fasHelp from "@fortawesome/fontawesome-free/svgs/solid/question-circle.svg";
|
||||||
import fasArrowLeft from '@fortawesome/fontawesome-free/svgs/solid/arrow-left.svg';
|
import fasArrowLeft from "@fortawesome/fontawesome-free/svgs/solid/arrow-left.svg";
|
||||||
import fasArrowRight from '@fortawesome/fontawesome-free/svgs/solid/arrow-right.svg';
|
import fasArrowRight from "@fortawesome/fontawesome-free/svgs/solid/arrow-right.svg";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -16,7 +16,7 @@ class ReplayWebApp extends LitElement
|
|||||||
this.sourceUrl = null;
|
this.sourceUrl = null;
|
||||||
this.collTitle = null;
|
this.collTitle = null;
|
||||||
this.showAbout = false;
|
this.showAbout = false;
|
||||||
this.pageParams = {};
|
this.pageParams = new URLSearchParams();
|
||||||
|
|
||||||
this.inited = false;
|
this.inited = false;
|
||||||
this.navMenuShown = false;
|
this.navMenuShown = false;
|
||||||
@@ -25,6 +25,9 @@ class ReplayWebApp extends LitElement
|
|||||||
this.pageTitle = "";
|
this.pageTitle = "";
|
||||||
this.pageReplay = false;
|
this.pageReplay = false;
|
||||||
|
|
||||||
|
this.loadInfo = null;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
registerSW(__SW_NAME__);
|
registerSW(__SW_NAME__);
|
||||||
|
|
||||||
this.safariKeyframes();
|
this.safariKeyframes();
|
||||||
@@ -52,7 +55,7 @@ class ReplayWebApp extends LitElement
|
|||||||
pageTitle: { type: String },
|
pageTitle: { type: String },
|
||||||
pageReplay: { type: Boolean },
|
pageReplay: { type: Boolean },
|
||||||
source: { type: String }
|
source: { type: String }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
@@ -168,30 +171,30 @@ class ReplayWebApp extends LitElement
|
|||||||
<span class="no-wrap is-size-6"> /
|
<span class="no-wrap is-size-6"> /
|
||||||
${this.pageReplay ? html`<i>${this.pageTitle}</i>` : this.pageTitle}
|
${this.pageReplay ? html`<i>${this.pageTitle}</i>` : this.pageTitle}
|
||||||
</span>
|
</span>
|
||||||
` : ``}
|
` : ""}
|
||||||
`: html`
|
`: html`
|
||||||
<span class="navbar-item wr-logo-item">
|
<span class="navbar-item wr-logo-item">
|
||||||
<fa-icon id="wrlogo" size="1.0rem" .svg=${this.mainLogo} aria-hidden="true"></fa-icon>
|
<fa-icon id="wrlogo" size="1.0rem" .svg=${this.mainLogo} aria-hidden="true"></fa-icon>
|
||||||
</span>
|
</span>
|
||||||
`}
|
`}
|
||||||
<a href="#" role="button" id="menu-button" @click="${this.onNavMenu}" @keyup="${clickOnSpacebarPress}"
|
<a href="#" role="button" id="menu-button" @click="${this.onNavMenu}" @keyup="${clickOnSpacebarPress}"
|
||||||
class="navbar-burger burger ${this.navMenuShown ? 'is-active' : ''}" aria-label="main menu" aria-haspopup="true" aria-expanded="${this.navMenuShown}">
|
class="navbar-burger burger ${this.navMenuShown ? "is-active" : ""}" aria-label="main menu" aria-haspopup="true" aria-expanded="${this.navMenuShown}">
|
||||||
<span aria-hidden="true"></span>
|
<span aria-hidden="true"></span>
|
||||||
<span aria-hidden="true"></span>
|
<span aria-hidden="true"></span>
|
||||||
<span aria-hidden="true"></span>
|
<span aria-hidden="true"></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
${!this.sourceUrl ? html`
|
${!this.sourceUrl ? html`
|
||||||
<div class="navbar-menu ${this.navMenuShown ? 'is-active' : ''}">
|
<div class="navbar-menu ${this.navMenuShown ? "is-active" : ""}">
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
${IS_APP ? html`
|
${IS_APP ? html`
|
||||||
<a role="button" href="#" class="navbar-item arrow-button" title="Go Back" @click="${(e) => window.history.back()}" @keyup="${clickOnSpacebarPress}">
|
<a role="button" href="#" class="navbar-item arrow-button" title="Go Back" @click="${() => window.history.back()}" @keyup="${clickOnSpacebarPress}">
|
||||||
<fa-icon size="1.0rem" .svg="${fasArrowLeft}" aria-hidden="true"></fa-icon><span class="menu-only is-size-7"> Go Back</span>
|
<fa-icon size="1.0rem" .svg="${fasArrowLeft}" aria-hidden="true"></fa-icon><span class="menu-only is-size-7"> Go Back</span>
|
||||||
</a>
|
</a>
|
||||||
<a role="button" href="#" class="navbar-item arrow-button" title="Go Forward" @click="${(e) => window.history.forward()}" @keyup="${clickOnSpacebarPress}">
|
<a role="button" href="#" class="navbar-item arrow-button" title="Go Forward" @click="${() => window.history.forward()}" @keyup="${clickOnSpacebarPress}">
|
||||||
<fa-icon size="1.0rem" .svg="${fasArrowRight}" aria-hidden="true"></fa-icon><span class="menu-only is-size-7"> Go Forward</span>
|
<fa-icon size="1.0rem" .svg="${fasArrowRight}" aria-hidden="true"></fa-icon><span class="menu-only is-size-7"> Go Forward</span>
|
||||||
</a>
|
</a>
|
||||||
` : ``}
|
` : ""}
|
||||||
</div>
|
</div>
|
||||||
${!this.embed ? html`
|
${!this.embed ? html`
|
||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
@@ -211,8 +214,8 @@ class ReplayWebApp extends LitElement
|
|||||||
-- NB: the About modal is currently inaccessible to people using keyboards or screen readers.
|
-- NB: the About modal is currently inaccessible to people using keyboards or screen readers.
|
||||||
-- Should all the JS and infrastructure for accessible modals be added, or should About be a normal page?
|
-- Should all the JS and infrastructure for accessible modals be added, or should About be a normal page?
|
||||||
-->
|
-->
|
||||||
<a href="?terms" @click="${(e) => { e.preventDefault(); this.showAbout = true} }"class="navbar-item is-size-6">About
|
<a href="?terms" @click="${(e) => { e.preventDefault(); this.showAbout = true;} }"class="navbar-item is-size-6">About
|
||||||
</a>`
|
</a>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderColl() {
|
renderColl() {
|
||||||
@@ -225,7 +228,7 @@ class ReplayWebApp extends LitElement
|
|||||||
@replay-favicons=${this.onFavIcons}
|
@replay-favicons=${this.onFavIcons}
|
||||||
@update-title=${this.onTitle}
|
@update-title=${this.onTitle}
|
||||||
@coll-loaded=${this.onCollLoaded}
|
@coll-loaded=${this.onCollLoaded}
|
||||||
@about-show=${(e) => this.showAbout = true}></wr-coll>`;
|
@about-show=${() => this.showAbout = true}></wr-coll>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHomeIndex() {
|
renderHomeIndex() {
|
||||||
@@ -233,7 +236,7 @@ class ReplayWebApp extends LitElement
|
|||||||
<wr-coll-index>
|
<wr-coll-index>
|
||||||
${!IS_APP ? html`
|
${!IS_APP ? html`
|
||||||
<p slot="header" class="tagline is-size-5 has-text-centered">Explore and Replay Interactive Archived Webpages Directly in your Browser. <i><a target="_blank" href="./docs/examples">(See Examples)</a></i></p>
|
<p slot="header" class="tagline is-size-5 has-text-centered">Explore and Replay Interactive Archived Webpages Directly in your Browser. <i><a target="_blank" href="./docs/examples">(See Examples)</a></i></p>
|
||||||
` : ``}
|
` : ""}
|
||||||
<wr-chooser slot="header" @load-start=${this.onStartLoad}></wr-chooser>
|
<wr-chooser slot="header" @load-start=${this.onStartLoad}></wr-chooser>
|
||||||
</wr-coll-index>`;
|
</wr-coll-index>`;
|
||||||
}
|
}
|
||||||
@@ -244,17 +247,17 @@ class ReplayWebApp extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${!this.embed || this.embed === "full" ? this.renderNavBar() : ''}
|
${!this.embed || this.embed === "full" ? this.renderNavBar() : ""}
|
||||||
|
|
||||||
${this.sourceUrl ? this.renderColl() : this.renderHomeIndex()}
|
${this.sourceUrl ? this.renderColl() : this.renderHomeIndex()}
|
||||||
|
|
||||||
${this.showAbout ? this.renderAbout() : ``}
|
${this.showAbout ? this.renderAbout() : ""}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this.initRoute();
|
this.initRoute();
|
||||||
window.addEventListener("popstate", (event) => {
|
window.addEventListener("popstate", () => {
|
||||||
this.initRoute();
|
this.initRoute();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -266,7 +269,7 @@ class ReplayWebApp extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
onFavIcons(event) {
|
onFavIcons(event) {
|
||||||
const head = document.querySelector('head');
|
const head = document.querySelector("head");
|
||||||
const oldLinks = document.querySelectorAll("link[rel*='icon']");
|
const oldLinks = document.querySelectorAll("link[rel*='icon']");
|
||||||
|
|
||||||
for (const link of oldLinks) {
|
for (const link of oldLinks) {
|
||||||
@@ -274,7 +277,7 @@ class ReplayWebApp extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const icon of event.detail.icons) {
|
for (const icon of event.detail.icons) {
|
||||||
const link = document.createElement('link');
|
const link = document.createElement("link");
|
||||||
link.rel = icon.rel;
|
link.rel = icon.rel;
|
||||||
link.href = icon.href;
|
link.href = icon.href;
|
||||||
head.appendChild(link);
|
head.appendChild(link);
|
||||||
@@ -285,7 +288,7 @@ class ReplayWebApp extends LitElement
|
|||||||
// This is a workaround, since this app's routing doesn't permit normal
|
// This is a workaround, since this app's routing doesn't permit normal
|
||||||
// following of in-page anchors.
|
// following of in-page anchors.
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.renderRoot.querySelector("#skip-main-target").focus()
|
this.renderRoot.querySelector("#skip-main-target").focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
onNavMenu(event) {
|
onNavMenu(event) {
|
||||||
@@ -348,7 +351,7 @@ class ReplayWebApp extends LitElement
|
|||||||
|
|
||||||
if (this.pageParams.get("config")) {
|
if (this.pageParams.get("config")) {
|
||||||
if (!this.loadInfo) {
|
if (!this.loadInfo) {
|
||||||
this.loadInfo = {}
|
this.loadInfo = {};
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.loadInfo.extraConfig = JSON.parse(this.pageParams.get("config"));
|
this.loadInfo.extraConfig = JSON.parse(this.pageParams.get("config"));
|
||||||
@@ -359,7 +362,7 @@ class ReplayWebApp extends LitElement
|
|||||||
|
|
||||||
if (this.pageParams.get("basePageUrl")) {
|
if (this.pageParams.get("basePageUrl")) {
|
||||||
if (!this.loadInfo) {
|
if (!this.loadInfo) {
|
||||||
this.loadInfo = {extraConfig: {}}
|
this.loadInfo = {extraConfig: {}};
|
||||||
}
|
}
|
||||||
if (!this.loadInfo.extraConfig) {
|
if (!this.loadInfo.extraConfig) {
|
||||||
this.loadInfo.extraConfig = {};
|
this.loadInfo.extraConfig = {};
|
||||||
@@ -369,18 +372,19 @@ class ReplayWebApp extends LitElement
|
|||||||
|
|
||||||
if (this.pageParams.get("customColl")) {
|
if (this.pageParams.get("customColl")) {
|
||||||
if (!this.loadInfo) {
|
if (!this.loadInfo) {
|
||||||
this.loadInfo = {}
|
this.loadInfo = {};
|
||||||
}
|
}
|
||||||
this.loadInfo.customColl = this.pageParams.get("customColl");
|
this.loadInfo.customColl = this.pageParams.get("customColl");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_APP && this.sourceUrl.startsWith("file://")) {
|
if (IS_APP && this.sourceUrl.startsWith("file://")) {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const url = new URL(__APP_FILE_SERVE_PREFIX__);
|
const url = new URL(__APP_FILE_SERVE_PREFIX__);
|
||||||
url.searchParams.set("filename", this.sourceUrl.slice("file://".length));
|
url.searchParams.set("filename", this.sourceUrl.slice("file://".length));
|
||||||
this.loadInfo = {
|
this.loadInfo = {
|
||||||
sourceUrl: this.sourceUrl,
|
sourceUrl: this.sourceUrl,
|
||||||
loadUrl: url.href,
|
loadUrl: url.href,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,7 +460,7 @@ class ReplayWebApp extends LitElement
|
|||||||
<div class="modal-background" @click="${this.onAboutClose}"></div>
|
<div class="modal-background" @click="${this.onAboutClose}"></div>
|
||||||
<div class="modal-card">
|
<div class="modal-card">
|
||||||
<header class="modal-card-head">
|
<header class="modal-card-head">
|
||||||
<p class="modal-card-title">About ReplayWeb.page ${IS_APP ? 'App' : ''}</p>
|
<p class="modal-card-title">About ReplayWeb.page ${IS_APP ? "App" : ""}</p>
|
||||||
<button class="delete" aria-label="close" @click="${this.onAboutClose}"></button>
|
<button class="delete" aria-label="close" @click="${this.onAboutClose}"></button>
|
||||||
</header>
|
</header>
|
||||||
<section class="modal-card-body">
|
<section class="modal-card-body">
|
||||||
@@ -465,7 +469,7 @@ class ReplayWebApp extends LitElement
|
|||||||
<div style="display: flex">
|
<div style="display: flex">
|
||||||
<div class="has-text-centered" style="width: 220px">
|
<div class="has-text-centered" style="width: 220px">
|
||||||
<wr-anim-logo class="logo" size="48px"></wr-anim-logo>
|
<wr-anim-logo class="logo" size="48px"></wr-anim-logo>
|
||||||
<div style="font-size: smaller; margin-bottom: 1em">${IS_APP ? 'App' : ''} v${__VERSION__}</div>
|
<div style="font-size: smaller; margin-bottom: 1em">${IS_APP ? "App" : ""} v${VERSION}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${IS_APP ? html`
|
${IS_APP ? html`
|
||||||
|
|||||||
+39
-22
@@ -1,7 +1,7 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { IS_APP, wrapCss } from './misc';
|
import { IS_APP, wrapCss } from "./misc";
|
||||||
|
|
||||||
import fasUpload from '@fortawesome/fontawesome-free/svgs/solid/upload.svg';
|
import fasUpload from "@fortawesome/fontawesome-free/svgs/solid/upload.svg";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -14,12 +14,18 @@ class Chooser extends LitElement
|
|||||||
this.file = null;
|
this.file = null;
|
||||||
|
|
||||||
this.hasNativeFS = !!window.showOpenFilePicker && !IS_APP;
|
this.hasNativeFS = !!window.showOpenFilePicker && !IS_APP;
|
||||||
|
|
||||||
|
this.newFullImport = false;
|
||||||
|
|
||||||
|
this.noHead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
fileDisplayName: { type: String }
|
fileDisplayName: { type: String },
|
||||||
}
|
newFullImport: { type: Boolean },
|
||||||
|
noHead: { type: Boolean }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onChooseFile(event) {
|
onChooseFile(event) {
|
||||||
@@ -40,16 +46,17 @@ class Chooser extends LitElement
|
|||||||
const options = {
|
const options = {
|
||||||
types: [
|
types: [
|
||||||
{
|
{
|
||||||
description: 'WARC, WACZ, HAR and WBN Files',
|
description: "WARC, WACZ, HAR and WBN Files",
|
||||||
accept: {
|
accept: {
|
||||||
'application/warc': ['.warc', '.gz'],
|
"application/warc": [".warc", ".gz"],
|
||||||
'application/har': ['.har'],
|
"application/har": [".har"],
|
||||||
'application/wacz': ['.wacz'],
|
"application/wacz": [".wacz"],
|
||||||
'application/wbn': ['.wbn']
|
"application/wbn": [".wbn"],
|
||||||
|
"application/json": [".json"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
|
||||||
const [fileHandle] = await window.showOpenFilePicker(options);
|
const [fileHandle] = await window.showOpenFilePicker(options);
|
||||||
this.fileHandle = fileHandle;
|
this.fileHandle = fileHandle;
|
||||||
@@ -71,12 +78,13 @@ class Chooser extends LitElement
|
|||||||
loadInfo.isFile = true;
|
loadInfo.isFile = true;
|
||||||
// file.path only available in electron app
|
// file.path only available in electron app
|
||||||
if (this.file.path) {
|
if (this.file.path) {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const url = new URL(__APP_FILE_SERVE_PREFIX__);
|
const url = new URL(__APP_FILE_SERVE_PREFIX__);
|
||||||
url.searchParams.set("filename", this.file.path);
|
url.searchParams.set("filename", this.file.path);
|
||||||
loadInfo.loadUrl = url.href;
|
loadInfo.loadUrl = url.href;
|
||||||
loadInfo.noCache = true;
|
loadInfo.noCache = true;
|
||||||
} else if (this.fileHandle) {
|
} else if (this.fileHandle) {
|
||||||
loadInfo.loadUrl = this.fileDisplayName + "-" + this.randomId();
|
loadInfo.loadUrl = this.fileDisplayName;
|
||||||
loadInfo.extra = {fileHandle: this.fileHandle};
|
loadInfo.extra = {fileHandle: this.fileHandle};
|
||||||
loadInfo.noCache = false;
|
loadInfo.noCache = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -88,6 +96,8 @@ class Chooser extends LitElement
|
|||||||
loadInfo.name = this.fileDisplayName;
|
loadInfo.name = this.fileDisplayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadInfo.newFullImport = this.newFullImport;
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent("load-start", {detail: loadInfo}));
|
this.dispatchEvent(new CustomEvent("load-start", {detail: loadInfo}));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -119,11 +129,18 @@ class Chooser extends LitElement
|
|||||||
}
|
}
|
||||||
.panel-heading {
|
.panel-heading {
|
||||||
background-color: #cff3ff;
|
background-color: #cff3ff;
|
||||||
|
}
|
||||||
|
.message-header {
|
||||||
|
background-color: #cff3ff;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.heading-size {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
form {
|
form {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
p.control.is-expanded {
|
p.control.is-expanded {
|
||||||
width: min-content;
|
width: min-content;
|
||||||
@@ -149,20 +166,20 @@ class Chooser extends LitElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
};
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<section class="section less-padding">
|
<section class="section ${this.noHead ? "is-paddingless" : "less-padding"}">
|
||||||
<div class="panel">
|
<div class="${this.noHead ? "" : "panel"}">
|
||||||
<h4 class="panel-heading">Load Web Archive</h4>
|
<div class="${this.noHead ? "is-hidden" : "panel-heading"} heading-size">${this.newFullImport ? "Import Existing" : "Load"} Web Archive</div>
|
||||||
<div class="extra-padding panel-block file has-name">
|
<div class="${this.noHead ? "" : "panel-body extra-padding"} file has-name ${this.noHead ? "is-small" : ""}">
|
||||||
<form class="is-flex" @submit="${this.onStartLoad}">
|
<form class="is-flex" @submit="${this.onStartLoad}">
|
||||||
<label class="file-label">
|
<label class="file-label">
|
||||||
${!this.hasNativeFS ? html`
|
${!this.hasNativeFS ? html`
|
||||||
<input class="file-input"
|
<input class="file-input"
|
||||||
@click="${(e) => e.currentTarget.value = null}"
|
@click="${(e) => e.currentTarget.value = null}"
|
||||||
@change=${this.onChooseFile} type="file" id="fileupload" name="fileupload">` : ``}
|
@change=${this.onChooseFile} type="file" id="fileupload" name="fileupload">` : ""}
|
||||||
<span class="file-cta" @click="${this.onChooseNativeFile}">
|
<span class="file-cta" @click="${this.onChooseNativeFile}">
|
||||||
<span class="file-icon">
|
<span class="file-icon">
|
||||||
<fa-icon size="0.9em" .svg=${fasUpload} aria-hidden="true"></fa-icon>
|
<fa-icon size="0.9em" .svg=${fasUpload} aria-hidden="true"></fa-icon>
|
||||||
@@ -175,16 +192,16 @@ class Chooser extends LitElement
|
|||||||
|
|
||||||
<div class="field has-addons">
|
<div class="field has-addons">
|
||||||
<p class="control is-expanded">
|
<p class="control is-expanded">
|
||||||
<input class="file-name input" type="text"
|
<input class="file-name input ${this.noHead ? "is-small" : ""}" type="text"
|
||||||
name="filename" id="filename"
|
name="filename" id="filename"
|
||||||
pattern="((file|http|https|ipfs|s3):\/\/.*\.(warc|warc.gz|zip|wacz|har|wbn))|(googledrive:\/\/.+)"
|
pattern="((file|http|https|ipfs|s3):\/\/.*\.(warc|warc.gz|zip|wacz|har|wbn|json))|(googledrive:\/\/.+)"
|
||||||
.value="${this.fileDisplayName}"
|
.value="${this.fileDisplayName}"
|
||||||
@input="${this.onInput}"
|
@input="${this.onInput}"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
placeholder="Enter a URL or click 'Choose File' to select a WARC, WACZ, HAR or WBN archive source">
|
placeholder="${this.newFullImport ? "Click 'Choose File' to select a local archive to import" : "Enter a URL or click 'Choose File' to select a WARC, WACZ, HAR or WBN archive source"}">
|
||||||
</p>
|
</p>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button type="submit" class="button is-hidden-mobile is-primary">Load</button>
|
<button type="submit" class="button is-hidden-mobile is-primary ${this.noHead ? "is-small" : ""}">${this.newFullImport ? "Import" : "Load"}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+66
-35
@@ -1,14 +1,14 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { wrapCss } from './misc';
|
import { wrapCss, apiPrefix } from "./misc";
|
||||||
|
|
||||||
import prettyBytes from 'pretty-bytes';
|
import prettyBytes from "pretty-bytes";
|
||||||
|
|
||||||
import fasCopy from '@fortawesome/fontawesome-free/svgs/regular/copy.svg';
|
import fasCopy from "@fortawesome/fontawesome-free/svgs/regular/copy.svg";
|
||||||
|
|
||||||
import fasArrowUp from '@fortawesome/fontawesome-free/svgs/solid/angle-double-up.svg';
|
import fasArrowUp from "@fortawesome/fontawesome-free/svgs/solid/angle-double-up.svg";
|
||||||
import fasArrowDown from '@fortawesome/fontawesome-free/svgs/solid/angle-double-down.svg';
|
import fasArrowDown from "@fortawesome/fontawesome-free/svgs/solid/angle-double-down.svg";
|
||||||
|
|
||||||
import fasSearch from '@fortawesome/fontawesome-free/svgs/solid/search.svg';
|
import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -19,7 +19,7 @@ class CollIndex extends LitElement
|
|||||||
|
|
||||||
this.colls = [];
|
this.colls = [];
|
||||||
this.filteredColls = [];
|
this.filteredColls = [];
|
||||||
this.sortedColls = [];
|
this.sortedColls = null;
|
||||||
|
|
||||||
this.query = "";
|
this.query = "";
|
||||||
|
|
||||||
@@ -29,6 +29,9 @@ class CollIndex extends LitElement
|
|||||||
|
|
||||||
this.dateName = "Date Loaded";
|
this.dateName = "Date Loaded";
|
||||||
this.headerName = "Loaded Archives";
|
this.headerName = "Loaded Archives";
|
||||||
|
|
||||||
|
this.typeFilter = "";
|
||||||
|
this.indexParams = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
get sortKeys() {
|
get sortKeys() {
|
||||||
@@ -62,8 +65,8 @@ class CollIndex extends LitElement
|
|||||||
_deleting: { type: Object },
|
_deleting: { type: Object },
|
||||||
|
|
||||||
dateName: { type: String },
|
dateName: { type: String },
|
||||||
headerName: { type: String }
|
headerName: { type: String },
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
@@ -90,6 +93,7 @@ class CollIndex extends LitElement
|
|||||||
for (const coll of this.colls) {
|
for (const coll of this.colls) {
|
||||||
if (coll.sourceUrl.indexOf(this.query) >= 0 ||
|
if (coll.sourceUrl.indexOf(this.query) >= 0 ||
|
||||||
coll.filename.indexOf(this.query) >= 0 ||
|
coll.filename.indexOf(this.query) >= 0 ||
|
||||||
|
(coll.loadUrl && coll.loadUrl.indexOf(this.query) >= 0) ||
|
||||||
(coll.title && coll.title.indexOf(this.query) >= 0)) {
|
(coll.title && coll.title.indexOf(this.query) >= 0)) {
|
||||||
this.filteredColls.push(coll);
|
this.filteredColls.push(coll);
|
||||||
}
|
}
|
||||||
@@ -97,18 +101,23 @@ class CollIndex extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadColls() {
|
async loadColls() {
|
||||||
const resp = await fetch("./wabac/api/index");
|
const resp = await fetch(`${apiPrefix}/coll-index?${this.indexParams}`);
|
||||||
try {
|
try {
|
||||||
|
if (resp.status !== 200) {
|
||||||
|
throw new Error("Invalid API Response");
|
||||||
|
}
|
||||||
const json = await resp.json();
|
const json = await resp.json();
|
||||||
this.colls = json.colls.map((coll) => {
|
this.colls = json.colls.map((coll) => {
|
||||||
coll.title = coll.title || coll.filename;
|
coll.title = coll.title || coll.filename;
|
||||||
return coll;
|
return coll;
|
||||||
});
|
});
|
||||||
} catch (e) {
|
|
||||||
// likely no sw registered yet
|
|
||||||
}
|
|
||||||
|
|
||||||
this._deleting = {};
|
this._deleting = {};
|
||||||
|
this.sortedColls = [];
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
// likely no sw registered yet, or waiting for new sw to register
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onDeleteColl(event) {
|
async onDeleteColl(event) {
|
||||||
@@ -130,7 +139,7 @@ class CollIndex extends LitElement
|
|||||||
this._deleting[coll.sourceUrl] = true;
|
this._deleting[coll.sourceUrl] = true;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
|
|
||||||
const resp = await fetch(`./wabac/api/${coll.id}`, {method: 'DELETE'});
|
const resp = await fetch(`${apiPrefix}/c/${coll.id}`, {method: "DELETE"});
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
const json = await resp.json();
|
const json = await resp.json();
|
||||||
this.colls = json.colls;
|
this.colls = json.colls;
|
||||||
@@ -139,7 +148,11 @@ class CollIndex extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return wrapCss(css`
|
return wrapCss(CollIndex.compStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get compStyles() {
|
||||||
|
return css`
|
||||||
:host {
|
:host {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@@ -170,6 +183,11 @@ class CollIndex extends LitElement
|
|||||||
fa-icon {
|
fa-icon {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-color {
|
||||||
|
background-color: rgb(210, 249, 214);
|
||||||
|
}
|
||||||
|
|
||||||
.copy {
|
.copy {
|
||||||
color: black;
|
color: black;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@@ -207,7 +225,8 @@ class CollIndex extends LitElement
|
|||||||
.coll-block {
|
.coll-block {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.delete {
|
.delete-button {
|
||||||
|
width: 32px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
@@ -229,31 +248,38 @@ class CollIndex extends LitElement
|
|||||||
height: 269px;
|
height: 269px;
|
||||||
margin-top: -269px;
|
margin-top: -269px;
|
||||||
}
|
}
|
||||||
`);
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHeader() {
|
||||||
|
return html`<h2 class="panel-heading panel-color"><span>${this.headerName}</span></h2>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSearchHeader() {
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const hasHeader = this.childElementCount > 0;
|
const hasHeader = this.childElementCount > 0;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<header class="${this.hideHeader ? 'closed' : ''}">
|
<header class="${this.hideHeader ? "closed" : ""}">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
</header>
|
</header>
|
||||||
<section class="section no-top-padding">
|
<section class="section no-top-padding">
|
||||||
<div class="sort-header is-small">
|
<div class="sort-header is-small">
|
||||||
${hasHeader ? html`
|
${hasHeader ? html`
|
||||||
<button @click=${(e) => this.hideHeader = !this.hideHeader} class="collapse button is-small">
|
<button @click=${() => this.hideHeader = !this.hideHeader} class="collapse button is-small">
|
||||||
<span class="icon"><fa-icon .svg=${this.hideHeader ? fasArrowDown : fasArrowUp}></span>
|
<span class="icon"><fa-icon .svg=${this.hideHeader ? fasArrowDown : fasArrowUp}></span>
|
||||||
<span>${this.hideHeader ? 'Show ' : 'Hide'} <span class="is-sr-only">Header</span></span>
|
<span>${this.hideHeader ? "Show " : "Hide"} <span class="is-sr-only">Header</span></span>
|
||||||
</button>` : ``}
|
</button>` : ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="panel is-light">
|
<div class="panel">
|
||||||
<h2 class="panel-heading"><span>${this.headerName}</span>
|
${this.renderHeader()}
|
||||||
</h2>
|
|
||||||
|
|
||||||
${this.colls.length ? html`
|
${this.colls.length ? html`
|
||||||
<div class="panel-block sort-header is-small">
|
<div class="panel-block sort-header is-small">
|
||||||
<div class="control has-icons-left">
|
${this.renderSearchHeader()}
|
||||||
|
<div class="control has-icons-left has-addons">
|
||||||
<input type="text" class="input is-small" @input="${(e) => this.query = e.currentTarget.value}" .value="${this.query}" type="text"
|
<input type="text" class="input is-small" @input="${(e) => this.query = e.currentTarget.value}" .value="${this.query}" type="text"
|
||||||
placeholder="Search by Archive Title or Source">
|
placeholder="Search by Archive Title or Source">
|
||||||
<span class="icon is-left is-small"><fa-icon .svg="${fasSearch}"/></span>
|
<span class="icon is-left is-small"><fa-icon .svg="${fasSearch}"/></span>
|
||||||
@@ -268,13 +294,13 @@ class CollIndex extends LitElement
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="coll-list">
|
<div class="coll-list">
|
||||||
${this.sortedColls.map((coll, i) => html`
|
${this.sortedColls && this.sortedColls.map((coll, i) => html`
|
||||||
<div class="coll-block panel-block">
|
<div class="coll-block panel-block">
|
||||||
${this.renderCollInfo(coll)}
|
${this.renderCollInfo(coll)}
|
||||||
${!this._deleting[coll.sourceUrl] ? html`
|
${!this._deleting[coll.sourceUrl] ? html`
|
||||||
<button class="delete" aria-label="Unload Collection" title="Unload Collection" data-coll-index="${i}" @click="${this.onDeleteColl}"></button>
|
<button class="delete delete-button" aria-label="Unload Collection" title="Unload Collection" data-coll-index="${i}" @click="${this.onDeleteColl}"></button>
|
||||||
` : html`
|
` : html`
|
||||||
<span class="button delete is-loading is-static">Deleting</span`}
|
<span class="button delete-button is-loading is-static">Deleting</span`}
|
||||||
</div>
|
</div>
|
||||||
`)}
|
`)}
|
||||||
</div>
|
</div>
|
||||||
@@ -282,7 +308,8 @@ class CollIndex extends LitElement
|
|||||||
` : html`
|
` : html`
|
||||||
|
|
||||||
<div class="panel-block extra-padding">
|
<div class="panel-block extra-padding">
|
||||||
${this.renderEmpty()}
|
${this.sortedColls === null ? html`<i>Loading Archives...</i>` :
|
||||||
|
this.renderEmpty()}
|
||||||
</div>
|
</div>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
@@ -314,11 +341,15 @@ class CollInfo extends LitElement
|
|||||||
coll: { type: Object },
|
coll: { type: Object },
|
||||||
detailed: { type: Boolean },
|
detailed: { type: Boolean },
|
||||||
canDelete: { type: Boolean }
|
canDelete: { type: Boolean }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return wrapCss(css`
|
return wrapCss(CollInfo.compStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get compStyles() {
|
||||||
|
return css`
|
||||||
.columns {
|
.columns {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -369,7 +400,7 @@ class CollInfo extends LitElement
|
|||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
`);
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -396,7 +427,7 @@ class CollInfo extends LitElement
|
|||||||
<span class="source-text"><p class="minihead">Source</p>${coll.sourceUrl} </span>
|
<span class="source-text"><p class="minihead">Source</p>${coll.sourceUrl} </span>
|
||||||
<a @click="${(e) => this.onCopy(e, coll.sourceUrl)}" class="copy"><fa-icon .svg="${fasCopy}"/></a>
|
<a @click="${(e) => this.onCopy(e, coll.sourceUrl)}" class="copy"><fa-icon .svg="${fasCopy}"/></a>
|
||||||
${coll.sourceUrl && coll.sourceUrl.startsWith("googledrive://") ? html`
|
${coll.sourceUrl && coll.sourceUrl.startsWith("googledrive://") ? html`
|
||||||
<p><i>(${coll.filename})</i></p>` : ''}
|
<p><i>(${coll.filename})</i></p>` : ""}
|
||||||
</div>
|
</div>
|
||||||
${detailed ? html`
|
${detailed ? html`
|
||||||
<div class="column"><p class="minihead">Filename</p>${coll.filename}</div>` : html``}
|
<div class="column"><p class="minihead">Filename</p>${coll.filename}</div>` : html``}
|
||||||
|
|||||||
+94
-84
@@ -1,28 +1,28 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { wrapCss, rwpLogo, IS_APP, clickOnSpacebarPress } from './misc';
|
import { wrapCss, rwpLogo, IS_APP, VERSION, clickOnSpacebarPress, apiPrefix, replayPrefix } from "./misc";
|
||||||
|
|
||||||
import { sourceToId, tsToDate, getPageDateTS } from './pageutils';
|
import { sourceToId, tsToDate, getPageDateTS } from "./pageutils";
|
||||||
|
|
||||||
import fasBook from '@fortawesome/fontawesome-free/svgs/solid/book.svg';
|
import fasBook from "@fortawesome/fontawesome-free/svgs/solid/book.svg";
|
||||||
|
|
||||||
import farListAlt from '@fortawesome/fontawesome-free/svgs/regular/list-alt.svg';
|
import farListAlt from "@fortawesome/fontawesome-free/svgs/regular/list-alt.svg";
|
||||||
import farResources from '@fortawesome/fontawesome-free/svgs/solid/puzzle-piece.svg';
|
import farResources from "@fortawesome/fontawesome-free/svgs/solid/puzzle-piece.svg";
|
||||||
import farPages from '@fortawesome/fontawesome-free/svgs/regular/file-image.svg';
|
import farPages from "@fortawesome/fontawesome-free/svgs/regular/file-image.svg";
|
||||||
import fasInfoIcon from '@fortawesome/fontawesome-free/svgs/solid/info-circle.svg';
|
import fasInfoIcon from "@fortawesome/fontawesome-free/svgs/solid/info-circle.svg";
|
||||||
import fasSync from '@fortawesome/fontawesome-free/svgs/solid/sync-alt.svg';
|
import fasSync from "@fortawesome/fontawesome-free/svgs/solid/sync-alt.svg";
|
||||||
|
|
||||||
import fasRefresh from '@fortawesome/fontawesome-free/svgs/solid/redo-alt.svg';
|
import fasRefresh from "@fortawesome/fontawesome-free/svgs/solid/redo-alt.svg";
|
||||||
import fasFullscreen from '@fortawesome/fontawesome-free/svgs/solid/desktop.svg';
|
import fasFullscreen from "@fortawesome/fontawesome-free/svgs/solid/desktop.svg";
|
||||||
import fasUnfullscreen from '@fortawesome/fontawesome-free/svgs/solid/compress-arrows-alt.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 fasLeft from "@fortawesome/fontawesome-free/svgs/solid/arrow-left.svg";
|
||||||
import fasRight from '@fortawesome/fontawesome-free/svgs/solid/arrow-right.svg';
|
import fasRight from "@fortawesome/fontawesome-free/svgs/solid/arrow-right.svg";
|
||||||
import fasMenuV from '@fortawesome/fontawesome-free/svgs/solid/ellipsis-v.svg';
|
import fasMenuV from "@fortawesome/fontawesome-free/svgs/solid/ellipsis-v.svg";
|
||||||
|
|
||||||
import fasAngleLeft from '@fortawesome/fontawesome-free/svgs/solid/angle-left.svg';
|
import fasAngleLeft from "@fortawesome/fontawesome-free/svgs/solid/angle-left.svg";
|
||||||
import fasAngleRight from '@fortawesome/fontawesome-free/svgs/solid/angle-right.svg';
|
import fasAngleRight from "@fortawesome/fontawesome-free/svgs/solid/angle-right.svg";
|
||||||
|
|
||||||
import Split from 'split.js';
|
import Split from "split.js";
|
||||||
|
|
||||||
|
|
||||||
const RWP_SCHEME = "search://";
|
const RWP_SCHEME = "search://";
|
||||||
@@ -37,11 +37,6 @@ class Coll extends LitElement
|
|||||||
this.inited = false;
|
this.inited = false;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
|
||||||
this.baseApiPrefix = "./wabac/api";
|
|
||||||
this.baseReplayPrefix = "./wabac";
|
|
||||||
this.apiPrefix = "";
|
|
||||||
this.replayPrefix = "";
|
|
||||||
|
|
||||||
this.coll = "";
|
this.coll = "";
|
||||||
|
|
||||||
this.collInfo = null;
|
this.collInfo = null;
|
||||||
@@ -61,7 +56,7 @@ class Coll extends LitElement
|
|||||||
"story": "Story",
|
"story": "Story",
|
||||||
"resources": "URLs",
|
"resources": "URLs",
|
||||||
"info": "Archive Info",
|
"info": "Archive Info",
|
||||||
}
|
};
|
||||||
|
|
||||||
this.menuActive = false;
|
this.menuActive = false;
|
||||||
|
|
||||||
@@ -69,7 +64,7 @@ class Coll extends LitElement
|
|||||||
|
|
||||||
this.editable = false;
|
this.editable = false;
|
||||||
|
|
||||||
this.showSidebar = localStorage.getItem(`pages:showSidebar`) === "1";
|
this.showSidebar = localStorage.getItem("pages:showSidebar") === "1";
|
||||||
this.splitter = null;
|
this.splitter = null;
|
||||||
|
|
||||||
this.isVisible = true;
|
this.isVisible = true;
|
||||||
@@ -112,19 +107,19 @@ class Coll extends LitElement
|
|||||||
|
|
||||||
appName: { type: String },
|
appName: { type: String },
|
||||||
appLogo: { type: String },
|
appLogo: { type: String },
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
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.addEventListener("fullscreenchange", () => {
|
||||||
this.isFullscreen = !!document.fullscreenElement;
|
this.isFullscreen = !!document.fullscreenElement;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.embed) {
|
if (this.embed) {
|
||||||
this.observer = new IntersectionObserver((entries, observer) => {
|
this.observer = new IntersectionObserver((entries/*, observer*/) => {
|
||||||
this.isVisible = entries[0].isIntersecting;
|
this.isVisible = entries[0].isIntersecting;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -182,14 +177,14 @@ class Coll extends LitElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.embed && window.parent !== window) {
|
if (this.embed && window.parent !== window) {
|
||||||
window.parent.postMessage(this.tabData, '*');
|
window.parent.postMessage(this.tabData, "*");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._locUpdateNeeded = false;
|
this._locUpdateNeeded = false;
|
||||||
}
|
}
|
||||||
if (changedProperties.has("showSidebar")) {
|
if (changedProperties.has("showSidebar")) {
|
||||||
if (!this.embed) {
|
if (!this.embed) {
|
||||||
localStorage.setItem(`pages:showSidebar`, this.showSidebar ? "1" : "0");
|
localStorage.setItem("pages:showSidebar", this.showSidebar ? "1" : "0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,14 +213,16 @@ class Coll extends LitElement
|
|||||||
onDragEnd() {
|
onDragEnd() {
|
||||||
replay.setDisablePointer(false);
|
replay.setDisablePointer(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
this.splitter = Split([contents, replay], opts);
|
this.splitter = Split([contents, replay], opts);
|
||||||
}
|
}
|
||||||
} else if (this.splitter) {
|
} else if (this.splitter) {
|
||||||
try {
|
try {
|
||||||
this.splitter.destroy();
|
this.splitter.destroy();
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
// ignore, remove splitter
|
||||||
|
}
|
||||||
this.splitter = null;
|
this.splitter = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,10 +243,10 @@ class Coll extends LitElement
|
|||||||
|
|
||||||
this.coll = coll;
|
this.coll = coll;
|
||||||
|
|
||||||
const apiPrefix = this.baseApiPrefix + "/" + coll;
|
const collApiPrefix = apiPrefix + "/c/" + coll;
|
||||||
const replayPrefix = this.baseReplayPrefix + "/" + coll;
|
const collReplayPrefix = replayPrefix + "/" + coll;
|
||||||
|
|
||||||
const resp = await fetch(apiPrefix + "?all=1");
|
const resp = await fetch(collApiPrefix + "?all=1");
|
||||||
|
|
||||||
if (resp.status != 200) {
|
if (resp.status != 200) {
|
||||||
this.collInfo = {};
|
this.collInfo = {};
|
||||||
@@ -258,7 +255,12 @@ class Coll extends LitElement
|
|||||||
|
|
||||||
const json = await resp.json();
|
const json = await resp.json();
|
||||||
|
|
||||||
this.collInfo = {apiPrefix, replayPrefix, coll, ...json};
|
this.collInfo = {
|
||||||
|
apiPrefix: collApiPrefix,
|
||||||
|
replayPrefix: collReplayPrefix,
|
||||||
|
coll,
|
||||||
|
...json
|
||||||
|
};
|
||||||
|
|
||||||
if (!this.collInfo.title) {
|
if (!this.collInfo.title) {
|
||||||
this.collInfo.title = this.collInfo.filename;
|
this.collInfo.title = this.collInfo.filename;
|
||||||
@@ -281,6 +283,9 @@ class Coll extends LitElement
|
|||||||
onCollLoaded(event) {
|
onCollLoaded(event) {
|
||||||
this.doUpdateInfo();
|
this.doUpdateInfo();
|
||||||
this.loadInfo = null;
|
this.loadInfo = null;
|
||||||
|
if (event.detail.sourceUrl) {
|
||||||
|
this.sourceUrl = event.detail.sourceUrl;
|
||||||
|
}
|
||||||
this.dispatchEvent(new CustomEvent("coll-loaded", {detail: {
|
this.dispatchEvent(new CustomEvent("coll-loaded", {detail: {
|
||||||
sourceUrl: this.sourceUrl,
|
sourceUrl: this.sourceUrl,
|
||||||
collInfo: this.collInfo,
|
collInfo: this.collInfo,
|
||||||
@@ -295,7 +300,7 @@ class Coll extends LitElement
|
|||||||
this.collInfo = {...this.collInfo, ...event.detail};
|
this.collInfo = {...this.collInfo, ...event.detail};
|
||||||
}
|
}
|
||||||
|
|
||||||
onHashChange(event) {
|
onHashChange() {
|
||||||
const hash = window.location.hash;
|
const hash = window.location.hash;
|
||||||
if (hash && hash !== this._locationHash) {
|
if (hash && hash !== this._locationHash) {
|
||||||
this.tabData = Object.fromEntries(new URLSearchParams(hash.slice(1)).entries());
|
this.tabData = Object.fromEntries(new URLSearchParams(hash.slice(1)).entries());
|
||||||
@@ -337,6 +342,11 @@ class Coll extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
onCollTabNav(event) {
|
onCollTabNav(event) {
|
||||||
|
if (event.detail.reload) {
|
||||||
|
this.onRefresh(null, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.target.id === this.tabData.view || event.target.id === "replay" && this.tabData.url) {
|
if (event.target.id === this.tabData.view || event.target.id === "replay" && this.tabData.url) {
|
||||||
this.updateTabData(event.detail.data, event.detail.replaceLoc, false);
|
this.updateTabData(event.detail.data, event.detail.replaceLoc, false);
|
||||||
} else if (this.showSidebar && this.tabData.url) {
|
} else if (this.showSidebar && this.tabData.url) {
|
||||||
@@ -344,7 +354,7 @@ class Coll extends LitElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTabData(data, replaceLoc = false, merge = false) {
|
updateTabData(data, replaceLoc = false/*, merge = false*/) {
|
||||||
this.tabData = {...this.tabData, ...data};
|
this.tabData = {...this.tabData, ...data};
|
||||||
if (this.tabData.url) {
|
if (this.tabData.url) {
|
||||||
this.url = this.tabData.url || "";
|
this.url = this.tabData.url || "";
|
||||||
@@ -622,7 +632,7 @@ class Coll extends LitElement
|
|||||||
return html`
|
return html`
|
||||||
${this.renderLocationBar()}
|
${this.renderLocationBar()}
|
||||||
<div id="tabContents">
|
<div id="tabContents">
|
||||||
<div id="contents" class="is-light ${isSidebar ? 'sidebar' : (isReplay ? 'is-hidden' : 'full-pages')}"
|
<div id="contents" class="is-light ${isSidebar ? "sidebar" : (isReplay ? "is-hidden" : "full-pages")}"
|
||||||
role="${isSidebar ? "complementary" : ""}" aria-label="${isSidebar ? "Browse Contents" : ""}">
|
role="${isSidebar ? "complementary" : ""}" aria-label="${isSidebar ? "Browse Contents" : ""}">
|
||||||
${this.renderTabHeader(isSidebar)}
|
${this.renderTabHeader(isSidebar)}
|
||||||
${isSidebar || !isReplay ? this.renderCollTabs(isSidebar) : html``}
|
${isSidebar || !isReplay ? this.renderCollTabs(isSidebar) : html``}
|
||||||
@@ -641,7 +651,7 @@ class Coll extends LitElement
|
|||||||
@replay-favicons="${this.onFavIcons}"
|
@replay-favicons="${this.onFavIcons}"
|
||||||
>
|
>
|
||||||
</wr-coll-replay>
|
</wr-coll-replay>
|
||||||
` : ``}
|
` : ""}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
@@ -655,7 +665,7 @@ class Coll extends LitElement
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<nav class="main tabs is-centered ${isSidebar ? 'sidebar' : ''}" aria-label="tabs">
|
<nav class="main tabs is-centered ${isSidebar ? "sidebar" : ""}" aria-label="tabs">
|
||||||
<ul>
|
<ul>
|
||||||
${isSidebar ? html`
|
${isSidebar ? html`
|
||||||
<li class="sidebar-nav left">
|
<li class="sidebar-nav left">
|
||||||
@@ -664,34 +674,34 @@ class Coll extends LitElement
|
|||||||
<span class="nav-hover" aria-hidden="true">Hide</span>
|
<span class="nav-hover" aria-hidden="true">Hide</span>
|
||||||
<span class="is-sr-only">Hide Sidebar</span>
|
<span class="is-sr-only">Hide Sidebar</span>
|
||||||
</a>
|
</a>
|
||||||
</li>` : ``}
|
</li>` : ""}
|
||||||
|
|
||||||
${this.hasStory ? html`
|
${this.hasStory ? html`
|
||||||
<li class="${this.tabData.view === 'story' ? 'is-active' : ''}">
|
<li class="${this.tabData.view === "story" ? "is-active" : ""}">
|
||||||
<a @click="${this.onTabClick}" href="#story" class="is-size-6" aria-label="Story" aria-current="${this.tabData.view === 'story' ? 'location' : ''}">
|
<a @click="${this.onTabClick}" href="#story" class="is-size-6" aria-label="Story" aria-current="${this.tabData.view === "story" ? "location" : ""}">
|
||||||
<span class="icon"><fa-icon .svg="${fasBook}" aria-hidden="true" title="Story"></fa-icon></span>
|
<span class="icon"><fa-icon .svg="${fasBook}" aria-hidden="true" title="Story"></fa-icon></span>
|
||||||
<span class="tab-label ${isSidebar ? 'is-hidden' : ''}" title="Story">Story</span>
|
<span class="tab-label ${isSidebar ? "is-hidden" : ""}" title="Story">Story</span>
|
||||||
</a>
|
</a>
|
||||||
</li>` : ``}
|
</li>` : ""}
|
||||||
|
|
||||||
<li class="${this.tabData.view === 'pages' ? 'is-active' : ''}">
|
<li class="${this.tabData.view === "pages" ? "is-active" : ""}">
|
||||||
<a @click="${this.onTabClick}" href="#pages" class="is-size-6" aria-label="Pages" aria-current="${this.tabData.view === 'pages' ? 'location' : ''}">
|
<a @click="${this.onTabClick}" href="#pages" class="is-size-6" aria-label="Pages" aria-current="${this.tabData.view === "pages" ? "location" : ""}">
|
||||||
<span class="icon"><fa-icon .svg="${farPages}" aria-hidden="true" title="Pages"></fa-icon></span>
|
<span class="icon"><fa-icon .svg="${farPages}" aria-hidden="true" title="Pages"></fa-icon></span>
|
||||||
<span class="tab-label ${isSidebar ? 'is-hidden' : ''}" title="Pages">Pages</span>
|
<span class="tab-label ${isSidebar ? "is-hidden" : ""}" title="Pages">Pages</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="${this.tabData.view === 'resources' ? 'is-active' : ''}">
|
<li class="${this.tabData.view === "resources" ? "is-active" : ""}">
|
||||||
<a @click="${this.onTabClick}" href="#resources" class="is-size-6" aria-label="URLs" aria-current="${this.tabData.view === 'resources' ? 'location' : ''}">
|
<a @click="${this.onTabClick}" href="#resources" class="is-size-6" aria-label="URLs" aria-current="${this.tabData.view === "resources" ? "location" : ""}">
|
||||||
<span class="icon"><fa-icon .svg="${farResources}" aria-hidden="true" title="URLs"></fa-icon></span>
|
<span class="icon"><fa-icon .svg="${farResources}" aria-hidden="true" title="URLs"></fa-icon></span>
|
||||||
<span class="tab-label ${isSidebar ? 'is-hidden' : ''}" title="URLs">URLs</span>
|
<span class="tab-label ${isSidebar ? "is-hidden" : ""}" title="URLs">URLs</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="${this.tabData.view === 'info' ? 'is-active' : ''}">
|
<li class="${this.tabData.view === "info" ? "is-active" : ""}">
|
||||||
<a @click="${this.onTabClick}" href="#info" class="is-size-6" aria-label="Archive Info" aria-current="${this.tabData.view === 'info' ? 'location' : ''}">
|
<a @click="${this.onTabClick}" href="#info" class="is-size-6" aria-label="Archive Info" aria-current="${this.tabData.view === "info" ? "location" : ""}">
|
||||||
<span class="icon"><fa-icon .svg="${fasInfoIcon}" aria-hidden="true" title="Archive Info"></fa-icon></span>
|
<span class="icon"><fa-icon .svg="${fasInfoIcon}" aria-hidden="true" title="Archive Info"></fa-icon></span>
|
||||||
<span class="tab-label ${isSidebar ? 'is-hidden' : ''}" title="Archive Info">Info</span>
|
<span class="tab-label ${isSidebar ? "is-hidden" : ""}" title="Archive Info">Info</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -702,7 +712,7 @@ class Coll extends LitElement
|
|||||||
<span class="is-sr-only">Expand Sidebar to Full View</span>
|
<span class="is-sr-only">Expand Sidebar to Full View</span>
|
||||||
<fa-icon title="Expand" .svg="${fasAngleRight}" aria-hidden="true"></fa-icon>
|
<fa-icon title="Expand" .svg="${fasAngleRight}" aria-hidden="true"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
</li>` : ``}
|
</li>` : ""}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>`;
|
</nav>`;
|
||||||
}
|
}
|
||||||
@@ -740,15 +750,15 @@ class Coll extends LitElement
|
|||||||
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${fasRight}"></fa-icon>
|
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${fasRight}"></fa-icon>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" role="button" class="button narrow is-borderless ${this.isLoading ? 'is-loading' : 'is-hidden-mobile'}" id="refresh" @click="${this.onRefresh}" @keyup="${clickOnSpacebarPress}"
|
<a href="#" role="button" class="button narrow is-borderless ${this.isLoading ? "is-loading" : "is-hidden-mobile"}" id="refresh" @click="${this.onRefresh}" @keyup="${clickOnSpacebarPress}"
|
||||||
title="Reload" aria-label="Reload">
|
title="Reload" aria-label="Reload">
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
${!this.isLoading ? html`
|
${!this.isLoading ? html`
|
||||||
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${fasRefresh}"></fa-icon>
|
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${fasRefresh}"></fa-icon>
|
||||||
` : ``}
|
` : ""}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" role="button" class="button narrow is-borderless is-hidden-mobile ${!isReplay ? 'grey-disabled' : ''}" @click="${this.onShowPages}" @keyup="${clickOnSpacebarPress}"
|
<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">
|
?disabled="${!isReplay}" title="Browse Contents" aria-label="Browse Contents" aria-controls="contents">
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${farListAlt}"></fa-icon>
|
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${farListAlt}"></fa-icon>
|
||||||
@@ -756,7 +766,7 @@ class Coll extends LitElement
|
|||||||
</a>
|
</a>
|
||||||
${this.renderExtraToolbar(false)}
|
${this.renderExtraToolbar(false)}
|
||||||
<form @submit="${this.onSubmit}">
|
<form @submit="${this.onSubmit}">
|
||||||
<div class="control is-expanded ${showFavIcon ? 'has-icons-left' : ''}">
|
<div class="control is-expanded ${showFavIcon ? "has-icons-left" : ""}">
|
||||||
<input id="url" class="input" type="text" @keydown="${this.onKeyDown}" @blur="${this.onLostFocus}" .value="${this.url}" placeholder="Enter text to search or a URL to replay"/>
|
<input id="url" class="input" type="text" @keydown="${this.onKeyDown}" @blur="${this.onLostFocus}" .value="${this.url}" placeholder="Enter text to search or a URL to replay"/>
|
||||||
${isReplay ? html`<p id="datetime" class="control is-hidden-mobile">${dateStr}</p>` : html``}
|
${isReplay ? html`<p id="datetime" class="control is-hidden-mobile">${dateStr}</p>` : html``}
|
||||||
${showFavIcon ? html`
|
${showFavIcon ? html`
|
||||||
@@ -766,7 +776,7 @@ class Coll extends LitElement
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="dropdown is-right ${this.menuActive ? 'is-active' : ''}" @click="${(e) => this.menuActive = false}">
|
<div class="dropdown is-right ${this.menuActive ? "is-active" : ""}" @click="${() => this.menuActive = false}">
|
||||||
<div class="dropdown-trigger">
|
<div class="dropdown-trigger">
|
||||||
<button class="button is-borderless" aria-haspopup="true" aria-controls="menu-dropdown" aria-expanded="${this.menuActive}" @click="${this.onMenu}"
|
<button class="button is-borderless" aria-haspopup="true" aria-controls="menu-dropdown" aria-expanded="${this.menuActive}" @click="${this.onMenu}"
|
||||||
aria-label="more replay controls">
|
aria-label="more replay controls">
|
||||||
@@ -801,7 +811,7 @@ class Coll extends LitElement
|
|||||||
</span>
|
</span>
|
||||||
<span>Reload</span>
|
<span>Reload</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" role="button" class="dropdown-item is-hidden-tablet ${!isReplay ? 'grey-disabled' : ''}" @click="${this.onShowPages}" @keyup="${clickOnSpacebarPress}">
|
<a href="#" role="button" class="dropdown-item is-hidden-tablet ${!isReplay ? "grey-disabled" : ""}" @click="${this.onShowPages}" @keyup="${clickOnSpacebarPress}">
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${farListAlt}"></fa-icon>
|
<fa-icon size="1.0em" class="has-text-grey" aria-hidden="true" .svg="${farListAlt}"></fa-icon>
|
||||||
</span>
|
</span>
|
||||||
@@ -820,12 +830,12 @@ class Coll extends LitElement
|
|||||||
<hr class="dropdown-divider is-hidden-desktop">
|
<hr class="dropdown-divider is-hidden-desktop">
|
||||||
<div class="dropdown-item info is-hidden-desktop">
|
<div class="dropdown-item info is-hidden-desktop">
|
||||||
<span class="menu-head">Capture Date</span>${dateStr}
|
<span class="menu-head">Capture Date</span>${dateStr}
|
||||||
</div>` : ``}
|
</div>` : ""}
|
||||||
<hr class="dropdown-divider">
|
<hr class="dropdown-divider">
|
||||||
<a href="#" role="button" class="dropdown-item" @click="${this.onAbout}">
|
<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>
|
<fa-icon class="menu-logo" size="1.0rem" aria-hidden="true" .svg=${this.appLogo}></fa-icon>
|
||||||
<span> About ${this.appName}</span>
|
<span> About ${this.appName}</span>
|
||||||
<span class="menu-version">(${__VERSION__})</span>
|
<span class="menu-version">(${VERSION})</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -861,15 +871,15 @@ class Coll extends LitElement
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderExtraToolbar(isDropdown = false) {
|
renderExtraToolbar(/*isDropdown = false*/) {
|
||||||
return '';
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCollTabs(isSidebar) {
|
renderCollTabs(isSidebar) {
|
||||||
const isStory = this.hasStory && this.tabData.view === 'story';
|
const isStory = this.hasStory && this.tabData.view === "story";
|
||||||
const isPages = this.tabData.view === 'pages';
|
const isPages = this.tabData.view === "pages";
|
||||||
const isResources = this.tabData.view === 'resources';
|
const isResources = this.tabData.view === "resources";
|
||||||
const isInfo = this.tabData.view === 'info';
|
const isInfo = this.tabData.view === "info";
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
|
||||||
@@ -881,10 +891,10 @@ class Coll extends LitElement
|
|||||||
currList="${this.tabData.currList || 0}"
|
currList="${this.tabData.currList || 0}"
|
||||||
@coll-tab-nav="${this.onCollTabNav}" id="story"
|
@coll-tab-nav="${this.onCollTabNav}" id="story"
|
||||||
.isSidebar="${isSidebar}"
|
.isSidebar="${isSidebar}"
|
||||||
class="${isStory ? '' : 'is-hidden'} ${isSidebar ? 'sidebar' : ''}"
|
class="${isStory ? "" : "is-hidden"} ${isSidebar ? "sidebar" : ""}"
|
||||||
role="${isSidebar ? '' : 'main'}"
|
role="${isSidebar ? "" : "main"}"
|
||||||
>
|
>
|
||||||
</wr-coll-story>` : ''}
|
</wr-coll-story>` : ""}
|
||||||
|
|
||||||
${isResources ? html`
|
${isResources ? html`
|
||||||
<wr-coll-resources .collInfo="${this.collInfo}"
|
<wr-coll-resources .collInfo="${this.collInfo}"
|
||||||
@@ -894,10 +904,10 @@ class Coll extends LitElement
|
|||||||
.currMime="${this.tabData.currMime || ""}"
|
.currMime="${this.tabData.currMime || ""}"
|
||||||
@coll-tab-nav="${this.onCollTabNav}" id="resources"
|
@coll-tab-nav="${this.onCollTabNav}" id="resources"
|
||||||
.isSidebar="${isSidebar}"
|
.isSidebar="${isSidebar}"
|
||||||
class="is-paddingless ${isResources ? '' : 'is-hidden'} ${isSidebar ? 'sidebar' : ''}"
|
class="is-paddingless ${isResources ? "" : "is-hidden"} ${isSidebar ? "sidebar" : ""}"
|
||||||
role="${isSidebar ? '' : 'main'}"
|
role="${isSidebar ? "" : "main"}"
|
||||||
>
|
>
|
||||||
</wr-coll-resources>` : ``}
|
</wr-coll-resources>` : ""}
|
||||||
|
|
||||||
${isPages ? html`
|
${isPages ? html`
|
||||||
<wr-page-view
|
<wr-page-view
|
||||||
@@ -911,10 +921,10 @@ class Coll extends LitElement
|
|||||||
.ts="${this.tabData.ts || ""}"
|
.ts="${this.tabData.ts || ""}"
|
||||||
@coll-tab-nav="${this.onCollTabNav}" id="pages"
|
@coll-tab-nav="${this.onCollTabNav}" id="pages"
|
||||||
@coll-update="${this.onCollUpdate}"
|
@coll-update="${this.onCollUpdate}"
|
||||||
class="${isPages ? '' : 'is-hidden'} ${isSidebar ? 'sidebar' : ''}"
|
class="${isPages ? "" : "is-hidden"} ${isSidebar ? "sidebar" : ""}"
|
||||||
role="${isSidebar ? '' : 'main'}"
|
role="${isSidebar ? "" : "main"}"
|
||||||
>
|
>
|
||||||
</wr-page-view>` : ``}
|
</wr-page-view>` : ""}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,7 +932,7 @@ class Coll extends LitElement
|
|||||||
// This is a workaround, since this app's routing doesn't permit normal
|
// This is a workaround, since this app's routing doesn't permit normal
|
||||||
// following of in-page anchors.
|
// following of in-page anchors.
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.renderRoot.querySelector("#skip-replay-target").focus()
|
this.renderRoot.querySelector("#skip-replay-target").focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown(event) {
|
onKeyDown(event) {
|
||||||
@@ -1015,7 +1025,7 @@ class Coll extends LitElement
|
|||||||
const deleteURL = this.collInfo.apiPrefix + (reload ? "?reload=1" : "");
|
const deleteURL = this.collInfo.apiPrefix + (reload ? "?reload=1" : "");
|
||||||
|
|
||||||
const resp = await fetch(deleteURL, {
|
const resp = await fetch(deleteURL, {
|
||||||
method: 'DELETE',
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (resp.status !== 200) {
|
if (resp.status !== 200) {
|
||||||
@@ -1027,7 +1037,7 @@ class Coll extends LitElement
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.hash = "";
|
//window.location.hash = "";
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1099,7 +1109,7 @@ class Coll extends LitElement
|
|||||||
return q.toString();
|
return q.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
onRefresh(event) {
|
onRefresh(event, replayOnly = false) {
|
||||||
if (event) {
|
if (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
@@ -1111,7 +1121,7 @@ class Coll extends LitElement
|
|||||||
if (replay) {
|
if (replay) {
|
||||||
replay.refresh();
|
replay.refresh();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!replayOnly) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { ElectronReplayApp } from './electron-replay-app';
|
/*eslint-env node */
|
||||||
import path from 'path';
|
|
||||||
|
import { ElectronReplayApp } from "./electron-replay-app";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
"use strict";
|
/*eslint-env node */
|
||||||
|
|
||||||
import { CollectionLoader } from '@webrecorder/wabac/src/loaders';
|
import { CollectionLoader } from "@webrecorder/wabac/src/loaders";
|
||||||
|
|
||||||
const { ipcRenderer, contextBridge } = require('electron');
|
const { ipcRenderer, contextBridge } = require("electron");
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electron', {'IS_APP': true});
|
contextBridge.exposeInMainWorld("electron", {"IS_APP": true});
|
||||||
|
|
||||||
const dbs = {};
|
const dbs = {};
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ async function getResponse(event, request, coll, ts, channel) {
|
|||||||
ipcRenderer.send(channel, result.status, headers, buffer);
|
ipcRenderer.send(channel, result.status, headers, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.on('getresponse', getResponse);
|
ipcRenderer.on("getresponse", getResponse);
|
||||||
|
|
||||||
export { getDB, getColl, loader };
|
export { getDB, getColl, loader };
|
||||||
|
|
||||||
|
|||||||
+40
-37
@@ -1,29 +1,31 @@
|
|||||||
import fetch from 'node-fetch';
|
/*eslint-env node */
|
||||||
import { Headers } from 'node-fetch';
|
|
||||||
|
|
||||||
import {app, session, BrowserWindow, ipcMain, screen, shell } from 'electron';
|
import fetch from "node-fetch";
|
||||||
|
import { Headers } from "node-fetch";
|
||||||
|
|
||||||
import path from 'path';
|
import {app, session, BrowserWindow, ipcMain, screen, shell } from "electron";
|
||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
import { ArchiveResponse, Rewriter } from '@webrecorder/wabac/src/rewrite';
|
import path from "path";
|
||||||
import { IPFSClient } from '@webrecorder/wabac/src/ipfs';
|
import fs from "fs";
|
||||||
|
|
||||||
import { PassThrough, Readable } from 'stream';
|
import { ArchiveResponse, Rewriter } from "@webrecorder/wabac/src/rewrite";
|
||||||
|
import { IPFSClient } from "@webrecorder/wabac/src/ipfs";
|
||||||
|
|
||||||
|
import { PassThrough, Readable } from "stream";
|
||||||
|
|
||||||
import { autoUpdater } from "electron-updater";
|
import { autoUpdater } from "electron-updater";
|
||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
|
|
||||||
import mime from 'mime-types';
|
import mime from "mime-types";
|
||||||
|
|
||||||
global.Headers = Headers;
|
global.Headers = Headers;
|
||||||
global.fetch = fetch;
|
global.fetch = fetch;
|
||||||
|
|
||||||
const STATIC_PREFIX = "http://localhost:5471/";
|
const STATIC_PREFIX = "http://localhost:5471/";
|
||||||
|
|
||||||
const REPLAY_PREFIX = STATIC_PREFIX + "wabac/";
|
const REPLAY_PREFIX = STATIC_PREFIX + "w/";
|
||||||
|
|
||||||
const URL_RX = /([^\/]+)\/([\d]+)(?:\w\w_)?\/(.*)$/;
|
const URL_RX = /([^/]+)\/([\d]+)(?:\w\w_)?\/(.*)$/;
|
||||||
|
|
||||||
|
|
||||||
let IPFS = null;
|
let IPFS = null;
|
||||||
@@ -76,11 +78,11 @@ class ElectronReplayApp
|
|||||||
get mainWindowWebPreferences() {
|
get mainWindowWebPreferences() {
|
||||||
return {
|
return {
|
||||||
plugins: true,
|
plugins: true,
|
||||||
preload: path.join(__dirname, 'preload.js'),
|
preload: path.join(__dirname, "preload.js"),
|
||||||
nativeWindowOpen: true,
|
nativeWindowOpen: true,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
enableRemoteModule: false
|
enableRemoteModule: false
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get mainWindowUrl() {
|
get mainWindowUrl() {
|
||||||
@@ -95,7 +97,7 @@ class ElectronReplayApp
|
|||||||
console.log("App already running, opening new window in first instance and quitting");
|
console.log("App already running, opening new window in first instance and quitting");
|
||||||
app.quit();
|
app.quit();
|
||||||
} else {
|
} else {
|
||||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
app.on("second-instance", (event, commandLine/*, workingDir*/) => {
|
||||||
// Just create a new window in case of second instance request
|
// Just create a new window in case of second instance request
|
||||||
this.createMainWindow(commandLine);
|
this.createMainWindow(commandLine);
|
||||||
});
|
});
|
||||||
@@ -103,43 +105,43 @@ class ElectronReplayApp
|
|||||||
|
|
||||||
if (includePlugins) {
|
if (includePlugins) {
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'win32':
|
case "win32":
|
||||||
this.pluginPath = path.join(this.projPath, "plugins-win", `pepflashplayer-x86${process.arch === 'x64' ? '_64' : ''}.dll`);
|
this.pluginPath = path.join(this.projPath, "plugins-win", `pepflashplayer-x86${process.arch === "x64" ? "_64" : ""}.dll`);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'darwin':
|
case "darwin":
|
||||||
this.pluginPath = path.join(this.projPath, "plugins-mac", "PepperFlashPlayer.plugin");
|
this.pluginPath = path.join(this.projPath, "plugins-mac", "PepperFlashPlayer.plugin");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'linux':
|
case "linux":
|
||||||
this.pluginPath = path.join(this.projPath, "plugins-mac", "libpepflashplayer.so");
|
this.pluginPath = path.join(this.projPath, "plugins-mac", "libpepflashplayer.so");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.log('platform unsupported: ' + process.platform);
|
console.log("platform unsupported: " + process.platform);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.commandLine.appendSwitch('ppapi-flash-path', this.pluginPath);
|
app.commandLine.appendSwitch("ppapi-flash-path", this.pluginPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('app path', this.appPath);
|
console.log("app path", this.appPath);
|
||||||
console.log('dir name', __dirname);
|
console.log("dir name", __dirname);
|
||||||
console.log('proj path', this.projPath);
|
console.log("proj path", this.projPath);
|
||||||
|
|
||||||
if (includePlugins) {
|
if (includePlugins) {
|
||||||
console.log('plugin path', this.pluginPath);
|
console.log("plugin path", this.pluginPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('app data', app.getPath('appData'));
|
console.log("app data", app.getPath("appData"));
|
||||||
console.log('user data', app.getPath('userData'));
|
console.log("user data", app.getPath("userData"));
|
||||||
|
|
||||||
if (this.profileName) {
|
if (this.profileName) {
|
||||||
app.setPath('userData', path.join(app.getPath('appData'), this.profileName));
|
app.setPath("userData", path.join(app.getPath("appData"), this.profileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
app.on('will-finish-launching', () => {
|
app.on("will-finish-launching", () => {
|
||||||
app.on('open-file', (event, filePath) => {
|
app.on("open-file", (event, filePath) => {
|
||||||
this.openNextFile = filePath;
|
this.openNextFile = filePath;
|
||||||
if (this.mainWindow) {
|
if (this.mainWindow) {
|
||||||
this.createMainWindow(process.argv);
|
this.createMainWindow(process.argv);
|
||||||
@@ -147,7 +149,7 @@ class ElectronReplayApp
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('activate', function () {
|
app.on("activate", function () {
|
||||||
// On macOS it's common to re-create a window in the app when the
|
// On macOS it's common to re-create a window in the app when the
|
||||||
// dock icon is clicked and there are no other windows open.
|
// dock icon is clicked and there are no other windows open.
|
||||||
if (BrowserWindow.getAllWindows().length === 0) {
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
@@ -158,7 +160,7 @@ class ElectronReplayApp
|
|||||||
app.whenReady().then(() => this.onAppReady());
|
app.whenReady().then(() => this.onAppReady());
|
||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on('window-all-closed', function () {
|
app.on("window-all-closed", function () {
|
||||||
// On macOS it is common for applications and their menu bar
|
// On macOS it is common for applications and their menu bar
|
||||||
// to stay active until the user quits explicitly with Cmd + Q
|
// to stay active until the user quits explicitly with Cmd + Q
|
||||||
//if (process.platform !== 'darwin')
|
//if (process.platform !== 'darwin')
|
||||||
@@ -177,8 +179,8 @@ class ElectronReplayApp
|
|||||||
|
|
||||||
this.screenSize = screen.getPrimaryDisplay().workAreaSize;
|
this.screenSize = screen.getPrimaryDisplay().workAreaSize;
|
||||||
|
|
||||||
app.on('web-contents-created', (event, contents) => {
|
app.on("web-contents-created", (event, contents) => {
|
||||||
contents.on('new-window', async (event, navigationUrl) => {
|
contents.on("new-window", async (event, navigationUrl) => {
|
||||||
|
|
||||||
// load docs in native browser for now
|
// load docs in native browser for now
|
||||||
if (navigationUrl === STATIC_PREFIX + "docs") {
|
if (navigationUrl === STATIC_PREFIX + "docs") {
|
||||||
@@ -251,6 +253,7 @@ class ElectronReplayApp
|
|||||||
return this.notFound(request.url, callback);
|
return this.notFound(request.url, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
if (request.url.startsWith(__APP_FILE_SERVE_PREFIX__)) {
|
if (request.url.startsWith(__APP_FILE_SERVE_PREFIX__)) {
|
||||||
const parsedUrl = new URL(request.url);
|
const parsedUrl = new URL(request.url);
|
||||||
|
|
||||||
@@ -330,7 +333,7 @@ class ElectronReplayApp
|
|||||||
notFound(url, callback) {
|
notFound(url, callback) {
|
||||||
console.log("not found: " + url);
|
console.log("not found: " + url);
|
||||||
const data = this._bufferToStream(`Sorry, the url <b>${url}</b> could not be found in this archive.`);
|
const data = this._bufferToStream(`Sorry, the url <b>${url}</b> could not be found in this archive.`);
|
||||||
callback({statusCode: 404, headers: {"Content-Type": 'text/html; charset="utf-8"'}, data});
|
callback({statusCode: 404, headers: {"Content-Type": "text/html; charset=\"utf-8\""}, data});
|
||||||
}
|
}
|
||||||
|
|
||||||
async resolveArchiveResponse(request, callback) {
|
async resolveArchiveResponse(request, callback) {
|
||||||
@@ -340,7 +343,7 @@ class ElectronReplayApp
|
|||||||
const url = request.url;
|
const url = request.url;
|
||||||
|
|
||||||
if (status === 404 && !payload) {
|
if (status === 404 && !payload) {
|
||||||
return notFound(url, callback);
|
return this.notFound(url, callback);
|
||||||
} else {
|
} else {
|
||||||
console.log("got response for: " + url);
|
console.log("got response for: " + url);
|
||||||
}
|
}
|
||||||
@@ -426,7 +429,7 @@ class ElectronReplayApp
|
|||||||
isMaximized: true,
|
isMaximized: true,
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: this.mainWindowWebPreferences,
|
webPreferences: this.mainWindowWebPreferences,
|
||||||
}).once('ready-to-show', () => {
|
}).once("ready-to-show", () => {
|
||||||
theWindow.show();
|
theWindow.show();
|
||||||
theWindow.maximize();
|
theWindow.maximize();
|
||||||
});
|
});
|
||||||
@@ -440,7 +443,7 @@ class ElectronReplayApp
|
|||||||
}
|
}
|
||||||
|
|
||||||
getOpenUrl(argv) {
|
getOpenUrl(argv) {
|
||||||
argv = require('minimist')(argv.slice(process.defaultApp ? 2 : 1));
|
argv = require("minimist")(argv.slice(process.defaultApp ? 2 : 1));
|
||||||
|
|
||||||
const filename = this.openNextFile || argv.filename || argv.f || (argv._.length && argv._[0]);
|
const filename = this.openNextFile || argv.filename || argv.f || (argv._.length && argv._[0]);
|
||||||
this.openNextFile = null;
|
this.openNextFile = null;
|
||||||
|
|||||||
+16
-8
@@ -1,8 +1,9 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
|
import { ifDefined } from "lit-html/directives/if-defined.js";
|
||||||
|
|
||||||
import { registerSW } from './pageutils';
|
import { registerSW } from "./pageutils";
|
||||||
|
|
||||||
import { wrapCss, rwpLogo } from './misc';
|
import { wrapCss, rwpLogo } from "./misc";
|
||||||
|
|
||||||
|
|
||||||
var scriptSrc = document.currentScript && document.currentScript.src;
|
var scriptSrc = document.currentScript && document.currentScript.src;
|
||||||
@@ -14,6 +15,7 @@ class Embed extends LitElement
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.replaybase = "./replay/";
|
this.replaybase = "./replay/";
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
this.swName = __SW_NAME__;
|
this.swName = __SW_NAME__;
|
||||||
this.view = "replay";
|
this.view = "replay";
|
||||||
this.ts = "";
|
this.ts = "";
|
||||||
@@ -26,6 +28,7 @@ class Embed extends LitElement
|
|||||||
this.swInited = false;
|
this.swInited = false;
|
||||||
this.embed = null;
|
this.embed = null;
|
||||||
this.reloadCount = 0;
|
this.reloadCount = 0;
|
||||||
|
this.noSandbox = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -53,7 +56,8 @@ class Embed extends LitElement
|
|||||||
|
|
||||||
deepLink: { type: Boolean },
|
deepLink: { type: Boolean },
|
||||||
noSW: { type: Boolean },
|
noSW: { type: Boolean },
|
||||||
}
|
noSandbox: { type: Boolean }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async doRegister() {
|
async doRegister() {
|
||||||
@@ -91,7 +95,7 @@ class Embed extends LitElement
|
|||||||
|
|
||||||
if (this.deepLink) {
|
if (this.deepLink) {
|
||||||
this.updateFromHash();
|
this.updateFromHash();
|
||||||
window.addEventListener("hashchange", (event) => this.updateFromHash());
|
window.addEventListener("hashchange", () => this.updateFromHash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,9 +174,13 @@ class Embed extends LitElement
|
|||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
${this.paramString && this.hashString && this.swInited ? html`
|
${this.paramString && this.hashString && this.swInited ? html`
|
||||||
<iframe sandbox="allow-downloads allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-scripts allow-same-origin allow-forms"
|
<iframe sandbox="${ifDefined(!this.noSandbox ?
|
||||||
|
"allow-downloads allow-modals allow-orientation-lock allow-pointer-lock\
|
||||||
|
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.paramString}#${this.hashString}" allow="autoplay *; fullscreen"
|
||||||
title="Replay of ${this.title ? `${this.title}:` :``} ${this.url}"></iframe>
|
title="Replay of ${this.title ? `${this.title}:` :""} ${this.url}"></iframe>
|
||||||
|
|
||||||
` : html``}
|
` : html``}
|
||||||
|
|
||||||
@@ -187,7 +195,7 @@ Please try a different browser.\n
|
|||||||
(Service Workers are disabled in Firefox in Private Mode. If Using Private Mode in Firefox, try regular mode).
|
(Service Workers are disabled in Firefox in Private Mode. If Using Private Mode in Firefox, try regular mode).
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
`: ``}`;
|
`: ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad(event) {
|
onLoad(event) {
|
||||||
|
|||||||
+15
-13
@@ -1,7 +1,7 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { wrapCss } from './misc';
|
import { wrapCss } from "./misc";
|
||||||
|
|
||||||
import fabGoogleDrive from '@fortawesome/fontawesome-free/svgs/brands/google-drive.svg';
|
import fabGoogleDrive from "@fortawesome/fontawesome-free/svgs/brands/google-drive.svg";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -21,7 +21,7 @@ class GDrive extends LitElement
|
|||||||
sourceUrl: { type: String },
|
sourceUrl: { type: String },
|
||||||
error: { type: Boolean },
|
error: { type: Boolean },
|
||||||
reauth: { type: Boolean }
|
reauth: { type: Boolean }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
@@ -41,6 +41,7 @@ class GDrive extends LitElement
|
|||||||
try {
|
try {
|
||||||
const sourceUrl = this.sourceUrl;
|
const sourceUrl = this.sourceUrl;
|
||||||
const fileId = sourceUrl.slice("googledrive://".length);
|
const fileId = sourceUrl.slice("googledrive://".length);
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const publicCheckUrl = `${__HELPER_PROXY__}/g/${fileId}`;
|
const publicCheckUrl = `${__HELPER_PROXY__}/g/${fileId}`;
|
||||||
|
|
||||||
let resp = null;
|
let resp = null;
|
||||||
@@ -87,7 +88,7 @@ class GDrive extends LitElement
|
|||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
this.scriptLoaded = true;
|
this.scriptLoaded = true;
|
||||||
this.gauth('none', (response) => {
|
this.gauth("none", (response) => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
if (this.state !== "implicitonly") {
|
if (this.state !== "implicitonly") {
|
||||||
this.state = "trymanual";
|
this.state = "trymanual";
|
||||||
@@ -99,7 +100,7 @@ class GDrive extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClickAuth() {
|
onClickAuth() {
|
||||||
this.gauth('select_account', (response) => {
|
this.gauth("select_account", (response) => {
|
||||||
if (!response.error) {
|
if (!response.error) {
|
||||||
this.authed(response);
|
this.authed(response);
|
||||||
}
|
}
|
||||||
@@ -144,12 +145,12 @@ class GDrive extends LitElement
|
|||||||
` : html`
|
` : html`
|
||||||
${this.error ? html`
|
${this.error ? html`
|
||||||
<div class="error has-text-danger">
|
<div class="error has-text-danger">
|
||||||
<p>${this.reauth ? 'Some resources are loaded on demand from Google Drive, which requires reauthorization.' :
|
<p>${this.reauth ? "Some resources are loaded on demand from Google Drive, which requires reauthorization." :
|
||||||
'Could not access this file with the current Google Drive account.'}</p>
|
"Could not access this file with the current Google Drive account."}</p>
|
||||||
<p>If you have multiple Google Drive accounts, be sure to select the correct one.</p>
|
<p>If you have multiple Google Drive accounts, be sure to select the correct one.</p>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
` : ``}
|
` : ""}
|
||||||
<button class="button is-warning is-rounded" @click="${this.onClickAuth}">
|
<button class="button is-warning is-rounded" @click="${this.onClickAuth}">
|
||||||
<span class="icon"><fa-icon .svg="${fabGoogleDrive}"></fa-icon></span>
|
<span class="icon"><fa-icon .svg="${fabGoogleDrive}"></fa-icon></span>
|
||||||
<span>Authorize Google Drive</span>
|
<span>Authorize Google Drive</span>
|
||||||
@@ -161,15 +162,16 @@ class GDrive extends LitElement
|
|||||||
if (this.state === "trypublic" || this.scriptLoaded) {
|
if (this.state === "trypublic" || this.scriptLoaded) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
const script = document.createElement('script');
|
const script = document.createElement("script");
|
||||||
script.onload = (() => this.onLoad());
|
script.onload = (() => this.onLoad());
|
||||||
script.src = 'https://apis.google.com/js/platform.js';
|
script.src = "https://apis.google.com/js/platform.js";
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
gauth(prompt, callback) {
|
gauth(prompt, callback) {
|
||||||
gapi.load('auth2', () => {
|
self.gapi.load("auth2", () => {
|
||||||
gapi.auth2.authorize({
|
self.gapi.auth2.authorize({
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
client_id: __GDRIVE_CLIENT_ID__,
|
client_id: __GDRIVE_CLIENT_ID__,
|
||||||
scope: "https://www.googleapis.com/auth/drive.file",
|
scope: "https://www.googleapis.com/auth/drive.file",
|
||||||
response_type: "token",
|
response_type: "token",
|
||||||
|
|||||||
+15
-12
@@ -1,9 +1,9 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { wrapCss, IS_APP } from './misc';
|
import { wrapCss, IS_APP } from "./misc";
|
||||||
|
|
||||||
import prettyBytes from 'pretty-bytes';
|
import prettyBytes from "pretty-bytes";
|
||||||
|
|
||||||
import { parseURLSchemeHostPath } from './pageutils';
|
import { parseURLSchemeHostPath } from "./pageutils";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -46,10 +46,10 @@ class Loader extends LitElement
|
|||||||
embed: { type: String },
|
embed: { type: String },
|
||||||
tryFileHandle: { type: Boolean },
|
tryFileHandle: { type: Boolean },
|
||||||
errorAllowRetry: { type: Boolean }
|
errorAllowRetry: { type: Boolean }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated(props) {
|
firstUpdated() {
|
||||||
this.initMessages();
|
this.initMessages();
|
||||||
//this.doLoad();
|
//this.doLoad();
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ Please try loading this page from an HTTPS URL`;
|
|||||||
this.state = "errored";
|
this.state = "errored";
|
||||||
this.error = `\
|
this.error = `\
|
||||||
File URLs can not be entered directly or shared.
|
File URLs can not be entered directly or shared.
|
||||||
You can select a file to upload from the main page by clicking the \'Choose File...\' button.`;
|
You can select a file to upload from the main page by clicking the 'Choose File...' button.`;
|
||||||
this.errorAllowRetry = false;
|
this.errorAllowRetry = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -150,6 +150,7 @@ You can select a file to upload from the main page by clicking the \'Choose File
|
|||||||
|
|
||||||
case "ipfs":
|
case "ipfs":
|
||||||
if (IS_APP) {
|
if (IS_APP) {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const url = new URL(__APP_FILE_SERVE_PREFIX__);
|
const url = new URL(__APP_FILE_SERVE_PREFIX__);
|
||||||
const hash = sourceUrl.split("#", 1)[0];
|
const hash = sourceUrl.split("#", 1)[0];
|
||||||
url.searchParams.set("ipfs", hash.slice("ipfs://".length));
|
url.searchParams.set("ipfs", hash.slice("ipfs://".length));
|
||||||
@@ -165,6 +166,8 @@ You can select a file to upload from the main page by clicking the \'Choose File
|
|||||||
source = {sourceUrl};
|
source = {sourceUrl};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source.newFullImport = (this.loadInfo && this.loadInfo.newFullImport);
|
||||||
|
|
||||||
this.state = "started";
|
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};
|
||||||
@@ -175,7 +178,7 @@ You can select a file to upload from the main page by clicking the \'Choose File
|
|||||||
|
|
||||||
if (!navigator.serviceWorker.controller) {
|
if (!navigator.serviceWorker.controller) {
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
navigator.serviceWorker.addEventListener("controllerchange", () => resolve);
|
navigator.serviceWorker.addEventListener("controllerchange", () => resolve());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +272,7 @@ You can select a file to upload from the main page by clicking the \'Choose File
|
|||||||
${!this.embed ? html`
|
${!this.embed ? html`
|
||||||
<div class="level">
|
<div class="level">
|
||||||
<p class="level-item">Loading <b>${this.sourceUrl}</b>...</p>
|
<p class="level-item">Loading <b>${this.sourceUrl}</b>...</p>
|
||||||
</div>` : ``}
|
</div>` : ""}
|
||||||
<div class="level">
|
<div class="level">
|
||||||
<div class="level-item has-text-centered">
|
<div class="level-item has-text-centered">
|
||||||
${this.renderContent()}
|
${this.renderContent()}
|
||||||
@@ -282,7 +285,7 @@ You can select a file to upload from the main page by clicking the \'Choose File
|
|||||||
renderContent() {
|
renderContent() {
|
||||||
switch (this.state) {
|
switch (this.state) {
|
||||||
case "googledrive":
|
case "googledrive":
|
||||||
return html`<wr-gdrive .sourceUrl=${this.sourceUrl} @load-ready=${this.onLoadReady}/>`
|
return html`<wr-gdrive .sourceUrl=${this.sourceUrl} @load-ready=${this.onLoadReady}/>`;
|
||||||
|
|
||||||
case "started":
|
case "started":
|
||||||
return html`
|
return html`
|
||||||
@@ -294,7 +297,7 @@ You can select a file to upload from the main page by clicking the \'Choose File
|
|||||||
<p class="loaded-prog">Loaded <b>${prettyBytes(this.currentSize)}</b> of <b>${prettyBytes(this.totalSize)}</b></p>` : html``}
|
<p class="loaded-prog">Loaded <b>${prettyBytes(this.currentSize)}</b> of <b>${prettyBytes(this.totalSize)}</b></p>` : html``}
|
||||||
|
|
||||||
${!this.embed ? html`
|
${!this.embed ? html`
|
||||||
<button @click="${this.onCancel}" class="button is-danger">Cancel</button>` : ``}
|
<button @click="${this.onCancel}" class="button is-danger">Cancel</button>` : ""}
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
case "errored":
|
case "errored":
|
||||||
@@ -303,7 +306,7 @@ You can select a file to upload from the main page by clicking the \'Choose File
|
|||||||
<div class="error has-text-danger">${this.error}</div>
|
<div class="error has-text-danger">${this.error}</div>
|
||||||
<div>
|
<div>
|
||||||
${this.errorAllowRetry ? html`
|
${this.errorAllowRetry ? html`
|
||||||
<a class="button is-warning" @click=${(e) => window.parent.location.reload()}>Try Again</a>` : ``}
|
<a class="button is-warning" @click=${() => window.parent.location.reload()}>Try Again</a>` : ""}
|
||||||
${this.embed ? html`` : html`
|
${this.embed ? html`` : html`
|
||||||
<a href="/" class="button is-warning">Back</a>`}
|
<a href="/" class="button is-warning">Back</a>`}
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|||||||
+15
-10
@@ -1,12 +1,15 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { LitElement, html, css, unsafeCSS } from 'lit-element';
|
import { LitElement, html, css, unsafeCSS } from "lit-element";
|
||||||
import { unsafeSVG } from 'lit-html/directives/unsafe-svg';
|
import { unsafeSVG } from "lit-html/directives/unsafe-svg";
|
||||||
import { styleMap } from 'lit-html/directives/style-map';
|
import { styleMap } from "lit-html/directives/style-map";
|
||||||
|
|
||||||
import allCssRaw from '../assets/main.scss';
|
import allCssRaw from "../assets/main.scss";
|
||||||
|
|
||||||
import rwpLogo from '../assets/logo.svg';
|
import rwpLogo from "../assets/logo.svg";
|
||||||
|
|
||||||
|
const apiPrefix = "./w/api";
|
||||||
|
const replayPrefix = "./w";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -15,8 +18,10 @@ function wrapCss(custom) {
|
|||||||
return [allCss, custom];
|
return [allCss, custom];
|
||||||
}
|
}
|
||||||
|
|
||||||
const IS_APP = window.IS_APP || window.electron && window.electron.IS_APP || window.matchMedia('(display-mode: standalone)').matches;
|
const IS_APP = window.IS_APP || window.electron && window.electron.IS_APP || window.matchMedia("(display-mode: standalone)").matches;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const VERSION = __VERSION__;
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// Buttons are expected to respond to both enter/return and spacebar.
|
// Buttons are expected to respond to both enter/return and spacebar.
|
||||||
@@ -45,7 +50,7 @@ class FaIcon extends LitElement
|
|||||||
size: { type: String },
|
size: { type: String },
|
||||||
width: { type: String },
|
width: { type: String },
|
||||||
height: { type: String }
|
height: { type: String }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
@@ -137,7 +142,7 @@ class WrModal extends LitElement
|
|||||||
return {
|
return {
|
||||||
title: { type: String },
|
title: { type: String },
|
||||||
bgClass: { type: String }
|
bgClass: { type: String }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
@@ -178,5 +183,5 @@ customElements.define("wr-anim-logo", AnimLogo);
|
|||||||
|
|
||||||
customElements.define("wr-modal", WrModal);
|
customElements.define("wr-modal", WrModal);
|
||||||
|
|
||||||
export { wrapCss, IS_APP, clickOnSpacebarPress, rwpLogo, FaIcon, AnimLogo, WrModal,
|
export { wrapCss, IS_APP, VERSION, clickOnSpacebarPress, rwpLogo, FaIcon, AnimLogo, WrModal,
|
||||||
LitElement, html, css, unsafeCSS, unsafeSVG };
|
LitElement, html, css, unsafeCSS, unsafeSVG, apiPrefix, replayPrefix };
|
||||||
|
|||||||
+27
-23
@@ -1,12 +1,12 @@
|
|||||||
import prettyBytes from 'pretty-bytes';
|
import prettyBytes from "pretty-bytes";
|
||||||
|
|
||||||
import { LitElement, html, css, unsafeCSS } from 'lit-element';
|
import { LitElement, html, css, unsafeCSS } from "lit-element";
|
||||||
|
|
||||||
import "keyword-mark-element/lib/keyword-mark.js";
|
import "keyword-mark-element/lib/keyword-mark.js";
|
||||||
|
|
||||||
import { getReplayLink } from './pageutils';
|
import { getReplayLink } from "./pageutils";
|
||||||
|
|
||||||
import { wrapCss } from './misc';
|
import { wrapCss } from "./misc";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -39,7 +39,7 @@ class PageEntry extends LitElement
|
|||||||
index: { type: Number },
|
index: { type: Number },
|
||||||
isCurrent: { type: Boolean },
|
isCurrent: { type: Boolean },
|
||||||
isSidebar: { type: Boolean },
|
isSidebar: { type: Boolean },
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
@@ -95,7 +95,7 @@ class PageEntry extends LitElement
|
|||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete {
|
.delete-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
@@ -190,12 +190,12 @@ class PageEntry extends LitElement
|
|||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input @change=${this.onSendSelToggle} type="checkbox" .checked="${this.selected}">
|
<input @change=${this.onSendSelToggle} type="checkbox" .checked="${this.selected}">
|
||||||
</label>
|
</label>
|
||||||
</div>` : ``}
|
</div>` : ""}
|
||||||
|
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
${this.index ? html`
|
${this.index ? html`
|
||||||
<div class="column col-index is-1 is-size-7">${this.index}.</div>
|
<div class="column col-index is-1 is-size-7">${this.index}.</div>
|
||||||
` : ``}
|
` : ""}
|
||||||
<div class="column col-date is-2">
|
<div class="column col-date is-2">
|
||||||
<div>${date ? date.toLocaleDateString() : ""}</div>
|
<div>${date ? date.toLocaleDateString() : ""}</div>
|
||||||
<div>${date ? date.toLocaleTimeString() : ""}</div>
|
<div>${date ? date.toLocaleTimeString() : ""}</div>
|
||||||
@@ -205,13 +205,13 @@ class PageEntry extends LitElement
|
|||||||
<figure class="media-left">
|
<figure class="media-left">
|
||||||
<p class="">
|
<p class="">
|
||||||
${this.iconValid ? html`
|
${this.iconValid ? html`
|
||||||
<img class="favicon" @error="${(e) => this.iconValid = false}" src="${this.replayPrefix}/${this.page.timestamp}id_/${p.favIconUrl}"/>` : html`
|
<img class="favicon" @error="${() => this.iconValid = false}" src="${this.replayPrefix}/${this.page.timestamp}id_/${p.favIconUrl}"/>` : html`
|
||||||
<span class="favicon"></span>`}
|
<span class="favicon"></span>`}
|
||||||
</p>
|
</p>
|
||||||
</figure>
|
</figure>
|
||||||
<div class="media-content ${this.isCurrent ? 'current' : ''}">
|
<div class="media-content ${this.isCurrent ? "current" : ""}">
|
||||||
<div role="heading" aria-level="${this.isSidebar ? "4": "3"}">
|
<div role="heading" aria-level="${this.isSidebar ? "4": "3"}">
|
||||||
<a @click="${this.onReplay}" href="${getReplayLink("pages", this.page.url, this.page.timestamp)}">
|
<a @dblclick="${this.onReload}" @click="${this.onReplay}" href="${getReplayLink("pages", this.page.url, this.page.timestamp)}">
|
||||||
<p class="is-size-6 has-text-weight-bold has-text-link text">
|
<p class="is-size-6 has-text-weight-bold has-text-link text">
|
||||||
<keyword-mark keywords="${this.query}">${p.title || p.url}</keyword-mark>
|
<keyword-mark keywords="${this.query}">${p.title || p.url}</keyword-mark>
|
||||||
</p>
|
</p>
|
||||||
@@ -226,16 +226,16 @@ class PageEntry extends LitElement
|
|||||||
${hasSize ? html`
|
${hasSize ? html`
|
||||||
<div class="media-right" style="margin-right: 2em">
|
<div class="media-right" style="margin-right: 2em">
|
||||||
${prettyBytes(p.size)}
|
${prettyBytes(p.size)}
|
||||||
</div>` : ``}
|
</div>` : ""}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${editable ? html`
|
${editable ? html`
|
||||||
${!this.deleting ? html`
|
${!this.deleting ? html`
|
||||||
<button @click="${this.onSendDeletePage}" class="delete"></button>` : html`
|
<button @click="${this.onSendDeletePage}" class="delete delete-button"></button>` : html`
|
||||||
<button class="button delete is-loading is-static"></button>
|
<button class="button is-loading delete-button is-static"></button>
|
||||||
`}` : ''}
|
`}` : ""}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +268,7 @@ class PageEntry extends LitElement
|
|||||||
|
|
||||||
if (!this.query || !this.page.text) {
|
if (!this.query || !this.page.text) {
|
||||||
this.textSnippet = null;
|
this.textSnippet = null;
|
||||||
this.requestUpdate('textSnippet', oldVal);
|
this.requestUpdate("textSnippet", oldVal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ class PageEntry extends LitElement
|
|||||||
|
|
||||||
if (inx < 0) {
|
if (inx < 0) {
|
||||||
this.textSnippet = null;
|
this.textSnippet = null;
|
||||||
this.requestUpdate('textSnippet', oldVal);
|
this.requestUpdate("textSnippet", oldVal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,25 +305,29 @@ class PageEntry extends LitElement
|
|||||||
this.textSnippet = "..." + textContent.slice(inx, lastInx) + "...";
|
this.textSnippet = "..." + textContent.slice(inx, lastInx) + "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.requestUpdate('textSnippet', oldVal);
|
this.requestUpdate("textSnippet", oldVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
onReplay(event) {
|
onReplay(event, reload = false) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
url: this.page.url,
|
url: this.page.url,
|
||||||
ts: this.page.timestamp,
|
ts: this.page.timestamp,
|
||||||
};
|
};
|
||||||
this.sendChangeEvent(data);
|
this.sendChangeEvent(data, reload);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendChangeEvent(data) {
|
onReload(event) {
|
||||||
this.dispatchEvent(new CustomEvent("coll-tab-nav", {bubbles: true, composed: true, detail: {data}}));
|
return this.onReplay(event, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSendDeletePage(event) {
|
sendChangeEvent(data, reload) {
|
||||||
|
this.dispatchEvent(new CustomEvent("coll-tab-nav", {bubbles: true, composed: true, detail: {data, reload}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
onSendDeletePage() {
|
||||||
const page = this.page;
|
const page = this.page;
|
||||||
this.dispatchEvent(new CustomEvent("delete-page", {detail: {page}}));
|
this.dispatchEvent(new CustomEvent("delete-page", {detail: {page}}));
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-35
@@ -1,18 +1,18 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { LitElement, html, css, unsafeCSS } from 'lit-element';
|
import { LitElement, html, css, unsafeCSS } from "lit-element";
|
||||||
import { wrapCss, clickOnSpacebarPress } from './misc';
|
import { wrapCss, clickOnSpacebarPress } from "./misc";
|
||||||
import ndjson from 'fetch-ndjson';
|
import ndjson from "fetch-ndjson";
|
||||||
|
|
||||||
import FlexSearch from 'flexsearch';
|
import FlexSearch from "flexsearch";
|
||||||
import prettyBytes from 'pretty-bytes';
|
import prettyBytes from "pretty-bytes";
|
||||||
|
|
||||||
import { getTS, getPageDateTS } from './pageutils';
|
import { getTS, getPageDateTS } from "./pageutils";
|
||||||
|
|
||||||
import fasSearch from '@fortawesome/fontawesome-free/svgs/solid/search.svg';
|
import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg";
|
||||||
import fasAngleDown from '@fortawesome/fontawesome-free/svgs/solid/angle-down.svg';
|
import fasAngleDown from "@fortawesome/fontawesome-free/svgs/solid/angle-down.svg";
|
||||||
|
|
||||||
import fasEdit from '@fortawesome/fontawesome-free/svgs/solid/edit.svg';
|
import fasEdit from "@fortawesome/fontawesome-free/svgs/solid/edit.svg";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -99,7 +99,7 @@ class Pages extends LitElement
|
|||||||
|
|
||||||
toDeletePages: { type: Object },
|
toDeletePages: { type: Object },
|
||||||
toDeletePage: { type: Object }
|
toDeletePage: { type: Object }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_timedUpdate() {
|
_timedUpdate() {
|
||||||
@@ -131,7 +131,7 @@ class Pages extends LitElement
|
|||||||
this.sortKey = "";
|
this.sortKey = "";
|
||||||
this.sortDesc = false;
|
this.sortDesc = false;
|
||||||
} else {
|
} else {
|
||||||
this.sortKey = "date"
|
this.sortKey = "date";
|
||||||
this.sortDesc = true;
|
this.sortDesc = true;
|
||||||
}
|
}
|
||||||
const sorter = this.renderRoot.querySelector("wr-sorter");
|
const sorter = this.renderRoot.querySelector("wr-sorter");
|
||||||
@@ -241,13 +241,13 @@ class Pages extends LitElement
|
|||||||
|
|
||||||
let lines = [];
|
let lines = [];
|
||||||
|
|
||||||
async function flush() {
|
const flush = async () => {
|
||||||
let curr = lines;
|
let curr = lines;
|
||||||
lines = [];
|
lines = [];
|
||||||
await flex.add(curr);
|
await flex.add(curr);
|
||||||
console.log("added " + count + " " + curr.length);
|
console.log("added " + count + " " + curr.length);
|
||||||
console.log(flex.info());
|
console.log(flex.info());
|
||||||
}
|
};
|
||||||
|
|
||||||
for await (const line of ndjson(resp.body.getReader())) {
|
for await (const line of ndjson(resp.body.getReader())) {
|
||||||
if (!line.text) {
|
if (!line.text) {
|
||||||
@@ -516,9 +516,9 @@ class Pages extends LitElement
|
|||||||
Pages in ${this.collInfo.title}
|
Pages in ${this.collInfo.title}
|
||||||
</div>
|
</div>
|
||||||
<div class="search-bar notification is-marginless">
|
<div class="search-bar notification is-marginless">
|
||||||
${this.isSidebar ? html `<h3 class="is-sr-only">Search and Filter Pages</h3>` : ``}
|
${this.isSidebar ? html `<h3 class="is-sr-only">Search and Filter Pages</h3>` : ""}
|
||||||
<div class="field flex-auto">
|
<div class="field flex-auto">
|
||||||
<div class="control has-icons-left ${this.loading ? 'is-loading' : ''}">
|
<div class="control has-icons-left ${this.loading ? "is-loading" : ""}">
|
||||||
<input type="search" class="input" @input="${this.onChangeQuery}" .value="${this.query}" type="text"
|
<input type="search" class="input" @input="${this.onChangeQuery}" .value="${this.query}" type="text"
|
||||||
placeholder="Search by Page URL, Title or Text">
|
placeholder="Search by Page URL, Title or Text">
|
||||||
<span class="icon is-left"><fa-icon .svg="${fasSearch}" aria-hidden="true"></fa-icon></span>
|
<span class="icon is-left"><fa-icon .svg="${fasSearch}" aria-hidden="true"></fa-icon></span>
|
||||||
@@ -531,7 +531,7 @@ class Pages extends LitElement
|
|||||||
${this.editable && this.editing ? html`
|
${this.editable && this.editing ? html`
|
||||||
<form @submit="${this.onUpdateTitle}"><input id="titleEdit" class="input" value="${this.collInfo.title}" @blur="${this.onUpdateTitle}"></form>
|
<form @submit="${this.onUpdateTitle}"><input id="titleEdit" class="input" value="${this.collInfo.title}" @blur="${this.onUpdateTitle}"></form>
|
||||||
` : html`
|
` : html`
|
||||||
<div class="index-bar-title" @dblclick="${(e) => this.editing = true}">${this.collInfo.title}</div>`}
|
<div class="index-bar-title" @dblclick="${() => this.editing = true}">${this.collInfo.title}</div>`}
|
||||||
|
|
||||||
${this.editable ? html`<fa-icon class="editIcon" .svg="${fasEdit}"></fa-icon>` : html``}
|
${this.editable ? html`<fa-icon class="editIcon" .svg="${fasEdit}"></fa-icon>` : html``}
|
||||||
|
|
||||||
@@ -540,25 +540,25 @@ class Pages extends LitElement
|
|||||||
${this.editable ? html`
|
${this.editable ? html`
|
||||||
<div class="index-bar-actions">
|
<div class="index-bar-actions">
|
||||||
${this.renderDownloadMenu()}
|
${this.renderDownloadMenu()}
|
||||||
</div>` : ``}
|
</div>` : ""}
|
||||||
|
|
||||||
${this.collInfo.lists.length ? html`
|
${this.collInfo.lists.length ? html`
|
||||||
<p id="filter-label" class="menu-label">Filter By List:</p>
|
<p id="filter-label" class="menu-label">Filter By List:</p>
|
||||||
<div class="index-bar-menu menu">
|
<div class="index-bar-menu menu">
|
||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
<li>
|
<li>
|
||||||
<a href="#list-0" data-list="0" class="${currList === 0 ? 'is-active' : ''}"
|
<a href="#list-0" data-list="0" class="${currList === 0 ? "is-active" : ""}"
|
||||||
@click=${this.onSelectList}><i>All Pages</i></a>
|
@click=${this.onSelectList}><i>All Pages</i></a>
|
||||||
</li>
|
</li>
|
||||||
${this.collInfo.lists.map(list => html`
|
${this.collInfo.lists.map(list => html`
|
||||||
<li>
|
<li>
|
||||||
<a @click=${this.onSelectList} href="#list-${list.id}"
|
<a @click=${this.onSelectList} href="#list-${list.id}"
|
||||||
data-list="${list.id}"
|
data-list="${list.id}"
|
||||||
class="${currList === list.id ? 'is-active' : ''}">${list.title}</a>
|
class="${currList === list.id ? "is-active" : ""}">${list.title}</a>
|
||||||
</li>`)}
|
</li>`)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
` : ``}
|
` : ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="column main-content">
|
<div class="column main-content">
|
||||||
<div class="is-sr-only" role="heading" aria-level="${this.isSidebar ? "3": "2"}">Page List</div>
|
<div class="is-sr-only" role="heading" aria-level="${this.isSidebar ? "3": "2"}">Page List</div>
|
||||||
@@ -571,7 +571,7 @@ class Pages extends LitElement
|
|||||||
|
|
||||||
renderDownloadMenu() {
|
renderDownloadMenu() {
|
||||||
return html`
|
return html`
|
||||||
<div class="dropdown ${this.menuActive ? 'is-active' : ''}">
|
<div class="dropdown ${this.menuActive ? "is-active" : ""}">
|
||||||
<div class="dropdown-trigger">
|
<div class="dropdown-trigger">
|
||||||
<button @click="${this.onMenu}" class="button is-small" aria-haspopup="true" aria-expanded="${this.menuActive}" aria-controls="dropdown-menu">
|
<button @click="${this.onMenu}" class="button is-small" aria-haspopup="true" aria-expanded="${this.menuActive}" aria-controls="dropdown-menu">
|
||||||
<span>Download</span>
|
<span>Download</span>
|
||||||
@@ -585,13 +585,13 @@ class Pages extends LitElement
|
|||||||
<a role="button" href="#"
|
<a role="button" href="#"
|
||||||
@click="${(e) => this.onDownload(e, "wacz", true)}"
|
@click="${(e) => this.onDownload(e, "wacz", true)}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
class="dropdown-item ${this.selectedPages.size === 0 ? 'is-disabled' : ''}">
|
class="dropdown-item ${this.selectedPages.size === 0 ? "is-disabled" : ""}">
|
||||||
Download Selected as WACZ (Web Archive Collection)
|
Download Selected as WACZ (Web Archive Collection)
|
||||||
</a>
|
</a>
|
||||||
<a role="button" href="#"
|
<a role="button" href="#"
|
||||||
@click="${(e) => this.onDownload(e, "warc", true)}"
|
@click="${(e) => this.onDownload(e, "warc", true)}"
|
||||||
@keyup="${clickOnSpacebarPress}"
|
@keyup="${clickOnSpacebarPress}"
|
||||||
class="dropdown-item ${this.selectedPages.size === 0 ? 'is-disabled' : ''}">
|
class="dropdown-item ${this.selectedPages.size === 0 ? "is-disabled" : ""}">
|
||||||
Download Selected as WARC Only
|
Download Selected as WARC Only
|
||||||
</a>
|
</a>
|
||||||
<hr class="dropdown-divider">
|
<hr class="dropdown-divider">
|
||||||
@@ -623,10 +623,10 @@ class Pages extends LitElement
|
|||||||
|
|
||||||
<div class="header columns is-hidden-mobile">
|
<div class="header columns is-hidden-mobile">
|
||||||
${this.query ? html`
|
${this.query ? html`
|
||||||
<a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="" class="column is-1 ${this.sortKey === "" ? (this.sortDesc ? "desc" : "asc") : ''}">Match</a>` : ``}
|
<a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="" class="column is-1 ${this.sortKey === "" ? (this.sortDesc ? "desc" : "asc") : ""}">Match</a>` : ""}
|
||||||
|
|
||||||
<a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="date" class="column is-2 ${this.sortKey === "date" ? (this.sortDesc ? "desc" : "asc") : ''}">Date</a>
|
<a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="date" class="column is-2 ${this.sortKey === "date" ? (this.sortDesc ? "desc" : "asc") : ""}">Date</a>
|
||||||
<a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="title" class="column is-6 pagetitle ${this.sortKey === "title" ? (this.sortDesc ? "desc" : "asc") : ''}">Page Title</a>
|
<a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="title" class="column is-6 pagetitle ${this.sortKey === "title" ? (this.sortDesc ? "desc" : "asc") : ""}">Page Title</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="is-hidden-tablet mobile-header">
|
<div class="is-hidden-tablet mobile-header">
|
||||||
@@ -638,7 +638,7 @@ class Pages extends LitElement
|
|||||||
.data="${this.filteredPages}"
|
.data="${this.filteredPages}"
|
||||||
pageResults="100"
|
pageResults="100"
|
||||||
@sort-changed="${this.onSortChanged}"
|
@sort-changed="${this.onSortChanged}"
|
||||||
class="${this.filteredPages.length ? '' : 'is-hidden'}">
|
class="${this.filteredPages.length ? "" : "is-hidden"}">
|
||||||
</wr-sorter>
|
</wr-sorter>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -650,7 +650,7 @@ class Pages extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<wr-modal bgClass="has-background-grey-lighter" @modal-closed="${(e) => this.toDeletePages = this.toDeletePage = null}" title="Confirm Delete">
|
<wr-modal bgClass="has-background-grey-lighter" @modal-closed="${() => this.toDeletePages = this.toDeletePage = null}" title="Confirm Delete">
|
||||||
${this.toDeletePage ? html`
|
${this.toDeletePage ? html`
|
||||||
<p>Are you sure you want to delete the page <b>${this.toDeletePage.title}</b>?
|
<p>Are you sure you want to delete the page <b>${this.toDeletePage.title}</b>?
|
||||||
(Size: <b>${prettyBytes(this.toDeletePage.size)}</b>)</p>` : html`
|
(Size: <b>${prettyBytes(this.toDeletePage.size)}</b>)</p>` : html`
|
||||||
@@ -659,7 +659,7 @@ class Pages extends LitElement
|
|||||||
<p>This operation can not be undone.</p>
|
<p>This operation can not be undone.</p>
|
||||||
|
|
||||||
<button @click="${this.onDeletePages}"class="button is-danger">Delete</button>
|
<button @click="${this.onDeletePages}"class="button is-danger">Delete</button>
|
||||||
<button @click="${(e) => this.toDeletePages = this.toDeletePage = null}" class="button">Cancel</button>
|
<button @click="${() => this.toDeletePages = this.toDeletePage = null}" class="button">Cancel</button>
|
||||||
</wr-modal>`;
|
</wr-modal>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,7 +691,7 @@ class Pages extends LitElement
|
|||||||
const selected = this.selectedPages.has(p.id);
|
const selected = this.selectedPages.has(p.id);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<li class="page-entry ${selected ? 'selected' : ''}">
|
<li class="page-entry ${selected ? "selected" : ""}">
|
||||||
<wr-page-entry
|
<wr-page-entry
|
||||||
.index="${this.query || this.isSidebar ? i + 1 : 0}"
|
.index="${this.query || this.isSidebar ? i + 1 : 0}"
|
||||||
.editable="${this.editable}"
|
.editable="${this.editable}"
|
||||||
@@ -704,10 +704,10 @@ class Pages extends LitElement
|
|||||||
@delete-page="${this.onDeleteConfirm}"
|
@delete-page="${this.onDeleteConfirm}"
|
||||||
replayPrefix="${this.collInfo.replayPrefix}"
|
replayPrefix="${this.collInfo.replayPrefix}"
|
||||||
query="${this.query}"
|
query="${this.query}"
|
||||||
class="${this.isSidebar ? 'sidebar' : ''}"
|
class="${this.isSidebar ? "sidebar" : ""}"
|
||||||
>
|
>
|
||||||
</wr-page-entry>
|
</wr-page-entry>
|
||||||
</li>` })}` : html`<p class="mobile-header">${this.getNoResultsMessage()}</p>`}
|
</li>`; })}` : html`<p class="mobile-header">${this.getNoResultsMessage()}</p>`}
|
||||||
</ul>
|
</ul>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -729,7 +729,7 @@ class Pages extends LitElement
|
|||||||
|
|
||||||
const body = JSON.stringify({title});
|
const body = JSON.stringify({title});
|
||||||
|
|
||||||
fetch(`${this.collInfo.apiPrefix}/metadata`, {method: 'POST', body}).then((res) => {
|
fetch(`${this.collInfo.apiPrefix}/metadata`, {method: "POST", body}).then((res) => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
this.dispatchEvent(new CustomEvent("coll-update", {detail: {title}}));
|
this.dispatchEvent(new CustomEvent("coll-update", {detail: {title}}));
|
||||||
}
|
}
|
||||||
@@ -828,9 +828,14 @@ class Pages extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const id of this.toDeletePages) {
|
for (const id of this.toDeletePages) {
|
||||||
const resp = await fetch(`${this.collInfo.apiPrefix}/page/${id}`, {method: 'DELETE'});
|
const resp = await fetch(`${this.collInfo.apiPrefix}/page/${id}`, {method: "DELETE"});
|
||||||
const json = await resp.json();
|
const json = await resp.json();
|
||||||
|
|
||||||
|
if (json.error) {
|
||||||
|
console.warn(json.error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const page = pageMap[id];
|
const page = pageMap[id];
|
||||||
|
|
||||||
if (!page) {
|
if (!page) {
|
||||||
@@ -866,7 +871,7 @@ class Pages extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.updatingSearch) {
|
if (this.updatingSearch) {
|
||||||
return "Initializing Search..."
|
return "Initializing Search...";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.loading) {
|
if (this.loading) {
|
||||||
|
|||||||
+10
-9
@@ -1,4 +1,4 @@
|
|||||||
import { register } from 'register-service-worker';
|
import { register } from "register-service-worker";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -17,13 +17,13 @@ function registerSW(name = "sw.js", scope = "./") {
|
|||||||
|
|
||||||
register(scope + name, {
|
register(scope + name, {
|
||||||
registrationOptions: { scope },
|
registrationOptions: { scope },
|
||||||
registered (reg) {
|
registered () {
|
||||||
console.log('Service worker is registered');
|
console.log("Service worker is registered");
|
||||||
resolve();
|
resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
error (error) {
|
error (error) {
|
||||||
console.error('Error during service worker registration:', error);
|
console.error("Error during service worker registration:", error);
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -36,6 +36,7 @@ let dbworker = null;
|
|||||||
|
|
||||||
function initDBWorker() {
|
function initDBWorker() {
|
||||||
if (dbworker === null) {
|
if (dbworker === null) {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
dbworker = new Worker(__SW_NAME__);
|
dbworker = new Worker(__SW_NAME__);
|
||||||
}
|
}
|
||||||
return dbworker;
|
return dbworker;
|
||||||
@@ -47,7 +48,7 @@ async function digestMessage(message, hashtype) {
|
|||||||
const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array
|
const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array
|
||||||
const hashBuffer = await crypto.subtle.digest(hashtype, msgUint8); // hash the message
|
const hashBuffer = await crypto.subtle.digest(hashtype, msgUint8); // hash the message
|
||||||
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
|
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
|
||||||
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string
|
const hashHex = hashArray.map(b => b.toString(16).padStart(2, "0")).join(""); // convert bytes to hex string
|
||||||
return hashHex;
|
return hashHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ function tsToDate(ts) {
|
|||||||
ts.substring(12, 14) + "-00:00");
|
ts.substring(12, 14) + "-00:00");
|
||||||
|
|
||||||
return new Date(datestr);
|
return new Date(datestr);
|
||||||
};
|
}
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
function getPageDateTS(page) {
|
function getPageDateTS(page) {
|
||||||
@@ -78,7 +79,7 @@ function getPageDateTS(page) {
|
|||||||
try {
|
try {
|
||||||
date = new Date(page.ts || page.date);
|
date = new Date(page.ts || page.date);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// leave date unchanged in case of error
|
||||||
}
|
}
|
||||||
|
|
||||||
const timestamp = (date && !isNaN(date)) ? getTS(date.toISOString()) : "";
|
const timestamp = (date && !isNaN(date)) ? getTS(date.toISOString()) : "";
|
||||||
@@ -88,7 +89,7 @@ function getPageDateTS(page) {
|
|||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
function getTS(iso) {
|
function getTS(iso) {
|
||||||
return iso.replace(/[-:T]/g, '').slice(0, 14);
|
return iso.replace(/[-:T]/g, "").slice(0, 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ function getReplayLink(view, url, ts) {
|
|||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
async function sourceToId(url) {
|
async function sourceToId(url) {
|
||||||
const digest = await digestMessage(url, 'SHA-256');
|
const digest = await digestMessage(url, "SHA-256");
|
||||||
const coll = "id-" + digest.slice(0, 12);
|
const coll = "id-" + digest.slice(0, 12);
|
||||||
return {url, coll};
|
return {url, coll};
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-10
@@ -1,5 +1,5 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { wrapCss, rwpLogo } from './misc';
|
import { wrapCss, rwpLogo } from "./misc";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ class Replay extends LitElement
|
|||||||
|
|
||||||
showAuth: { type: Boolean },
|
showAuth: { type: Boolean },
|
||||||
authFileHandle: { type: Object }
|
authFileHandle: { type: Object }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
@@ -57,7 +57,9 @@ class Replay extends LitElement
|
|||||||
this.refresh();
|
this.refresh();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.authFileHandle = null;
|
this.authFileHandle = null;
|
||||||
}
|
}
|
||||||
@@ -147,8 +149,8 @@ class Replay extends LitElement
|
|||||||
// google drive reauth
|
// google drive reauth
|
||||||
const headers = event.detail.headers;
|
const headers = event.detail.headers;
|
||||||
|
|
||||||
const resp = await fetch(`${this.collInfo.apiPrefix}/updateAuth`, {
|
await fetch(`${this.collInfo.apiPrefix}/updateAuth`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
body: JSON.stringify({headers})
|
body: JSON.stringify({headers})
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -200,9 +202,16 @@ class Replay extends LitElement
|
|||||||
refresh() {
|
refresh() {
|
||||||
const iframe = this.renderRoot.querySelector("iframe");
|
const iframe = this.renderRoot.querySelector("iframe");
|
||||||
|
|
||||||
if (iframe) {
|
if (!iframe) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldIframeUrl = this.iframeUrl;
|
||||||
|
// set iframe url to expected, refresh if same url
|
||||||
|
this.doSetIframeUrl();
|
||||||
|
if (oldIframeUrl === this.iframeUrl) {
|
||||||
this.waitForLoad();
|
this.waitForLoad();
|
||||||
iframe.contentWindow.location.reload();
|
iframe.contentWindow.location.href = this.iframeUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,7 +271,7 @@ class Replay extends LitElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const title = `Replay of ${this.title ? `${this.title}:` :``} ${this.url}`;
|
const title = `Replay of ${this.title ? `${this.title}:` :""} ${this.url}`;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
|
||||||
@@ -302,7 +311,7 @@ class Replay extends LitElement
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`: ``}
|
`: ""}
|
||||||
</div>
|
</div>
|
||||||
`}`;
|
`}`;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -1,8 +1,8 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { wrapCss } from './misc';
|
import { wrapCss } from "./misc";
|
||||||
|
|
||||||
import fasSortDown from '@fortawesome/fontawesome-free/svgs/solid/sort-down.svg';
|
import fasSortDown from "@fortawesome/fontawesome-free/svgs/solid/sort-down.svg";
|
||||||
import fasSortUp from '@fortawesome/fontawesome-free/svgs/solid/sort-up.svg';
|
import fasSortUp from "@fortawesome/fontawesome-free/svgs/solid/sort-up.svg";
|
||||||
|
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -16,7 +16,7 @@ class Sorter extends LitElement
|
|||||||
this.pageResults = 0;
|
this.pageResults = 0;
|
||||||
this.numResults = 0;
|
this.numResults = 0;
|
||||||
|
|
||||||
this.sortKey = null
|
this.sortKey = null;
|
||||||
this.sortDesc = null;
|
this.sortDesc = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class Sorter extends LitElement
|
|||||||
|
|
||||||
sortKey: { type: String },
|
sortKey: { type: String },
|
||||||
sortDesc: { type: Boolean },
|
sortDesc: { type: Boolean },
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
@@ -126,7 +126,7 @@ class Sorter extends LitElement
|
|||||||
`)}
|
`)}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button @click=${(e) => this.sortDesc = !this.sortDesc} class="button is-small">
|
<button @click=${() => this.sortDesc = !this.sortDesc} class="button is-small">
|
||||||
<span>Order:</span>
|
<span>Order:</span>
|
||||||
<span class="is-sr-only">${this.sortDesc ? "Ascending" : "Descending"}</span>
|
<span class="is-sr-only">${this.sortDesc ? "Ascending" : "Descending"}</span>
|
||||||
<span class="icon"><fa-icon aria-hidden="true" .svg=${this.sortDesc ? fasSortUp : fasSortDown}></span>
|
<span class="icon"><fa-icon aria-hidden="true" .svg=${this.sortDesc ? fasSortUp : fasSortDown}></span>
|
||||||
|
|||||||
+18
-16
@@ -1,12 +1,12 @@
|
|||||||
import { LitElement, html, css, unsafeCSS } from 'lit-element';
|
import { LitElement, html, css, unsafeCSS } from "lit-element";
|
||||||
import { wrapCss } from './misc';
|
import { wrapCss } from "./misc";
|
||||||
|
|
||||||
import { unsafeHTML } from 'lit-html/directives/unsafe-html';
|
import { unsafeHTML } from "lit-html/directives/unsafe-html";
|
||||||
import marked from 'marked';
|
import marked from "marked";
|
||||||
|
|
||||||
import { getTS, getReplayLink } from './pageutils';
|
import { getTS, getReplayLink } from "./pageutils";
|
||||||
|
|
||||||
import Split from 'split.js'
|
import Split from "split.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ class Story extends LitElement
|
|||||||
|
|
||||||
isSidebar: { type: Boolean },
|
isSidebar: { type: Boolean },
|
||||||
splitDirection: { type: Boolean }
|
splitDirection: { type: Boolean }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
recalcSplitter(width) {
|
recalcSplitter(width) {
|
||||||
@@ -53,11 +53,11 @@ class Story extends LitElement
|
|||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this.recalcSplitter(document.documentElement.clientWidth);
|
this.recalcSplitter(document.documentElement.clientWidth);
|
||||||
|
|
||||||
this.obs = new ResizeObserver((entries, observer) => {
|
this.obs = new ResizeObserver((entries/*, observer*/) => {
|
||||||
this.recalcSplitter(entries[0].contentRect.width);
|
this.recalcSplitter(entries[0].contentRect.width);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.obs.observe(this)
|
this.obs.observe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
@@ -87,7 +87,9 @@ class Story extends LitElement
|
|||||||
if (this.splitter) {
|
if (this.splitter) {
|
||||||
try {
|
try {
|
||||||
this.splitter.destroy();
|
this.splitter.destroy();
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
// ignore splitter destory err
|
||||||
|
}
|
||||||
this.splitter = null;
|
this.splitter = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +100,7 @@ class Story extends LitElement
|
|||||||
gutterSize: 4,
|
gutterSize: 4,
|
||||||
|
|
||||||
direction: this.splitDirection
|
direction: this.splitDirection
|
||||||
}
|
};
|
||||||
|
|
||||||
this.splitter = Split([sidebar, content], opts);
|
this.splitter = Split([sidebar, content], opts);
|
||||||
}
|
}
|
||||||
@@ -160,7 +162,7 @@ class Story extends LitElement
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
${Story.sidebarStyles(unsafeCSS(`:host(.sidebar)`))}
|
${Story.sidebarStyles(unsafeCSS(":host(.sidebar)"))}
|
||||||
|
|
||||||
.desc p {
|
.desc p {
|
||||||
margin-bottom: 1.0em;
|
margin-bottom: 1.0em;
|
||||||
@@ -257,13 +259,13 @@ class Story extends LitElement
|
|||||||
<aside class="menu">
|
<aside class="menu">
|
||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
<li>
|
<li>
|
||||||
<a href="#list-0" data-list="0" class="${currListNum === 0 ? 'is-active' : ''} menu-label is-size-4"
|
<a href="#list-0" data-list="0" class="${currListNum === 0 ? "is-active" : ""} menu-label is-size-4"
|
||||||
@click=${this.onClickScroll}>${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}"
|
||||||
data-list="${list.id}"
|
data-list="${list.id}"
|
||||||
class="${currListNum === list.id ? 'is-active' : ''}">${list.title}</a>
|
class="${currListNum === list.id ? "is-active" : ""}">${list.title}</a>
|
||||||
</li>`)}
|
</li>`)}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@@ -273,7 +275,7 @@ class Story extends LitElement
|
|||||||
<div @scroll=${this.onScroll} class="column main-content main-scroll">
|
<div @scroll=${this.onScroll} class="column main-content main-scroll">
|
||||||
<section id="list-0" class="desc">
|
<section id="list-0" class="desc">
|
||||||
<h2 class="has-text-centered title is-3">${this.collInfo.title}</h2>
|
<h2 class="has-text-centered title is-3">${this.collInfo.title}</h2>
|
||||||
${this.collInfo.desc ? unsafeHTML(marked(this.collInfo.desc)) : ''}
|
${this.collInfo.desc ? unsafeHTML(marked(this.collInfo.desc)) : ""}
|
||||||
</section>
|
</section>
|
||||||
${this.renderLists()}
|
${this.renderLists()}
|
||||||
</div>
|
</div>
|
||||||
@@ -283,7 +285,7 @@ class Story extends LitElement
|
|||||||
|
|
||||||
renderLists() {
|
renderLists() {
|
||||||
return html`
|
return html`
|
||||||
${this.collInfo.lists.map((list, i) => html`
|
${this.collInfo.lists.map((list) => html`
|
||||||
<article id="list-${list.id}">
|
<article id="list-${list.id}">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import INDEX_HTML from '../index.html';
|
import INDEX_HTML from "../index.html";
|
||||||
|
|
||||||
import { SWReplay } from '@webrecorder/wabac/src/swmain';
|
import { SWReplay } from "@webrecorder/wabac/src/swmain";
|
||||||
|
|
||||||
const staticData = new Map();
|
const staticData = new Map();
|
||||||
|
|
||||||
@@ -12,5 +12,5 @@ staticData.set(prefix + "index.html", {type: "text/html", content: INDEX_HTML});
|
|||||||
|
|
||||||
//const { SWReplay } = require('@webrecorder/wabac/src/swmain');
|
//const { SWReplay } = require('@webrecorder/wabac/src/swmain');
|
||||||
self.ipfsCustomPreload = true;
|
self.ipfsCustomPreload = true;
|
||||||
self.sw = new SWReplay(staticData);
|
self.sw = new SWReplay({staticData});
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { ReplayWebApp } from './appmain';
|
import { ReplayWebApp } from "./appmain";
|
||||||
import { Chooser } from './chooser';
|
import { Chooser } from "./chooser";
|
||||||
import { CollIndex, CollInfo } from './coll-index';
|
import { CollIndex, CollInfo } from "./coll-index";
|
||||||
import { Coll } from './coll';
|
import { Coll } from "./coll";
|
||||||
import { Story } from './story';
|
import { Story } from "./story";
|
||||||
import { GDrive } from './gdrive';
|
import { GDrive } from "./gdrive";
|
||||||
import { Loader } from './loader';
|
import { Loader } from "./loader";
|
||||||
import { Pages } from './pages';
|
import { Pages } from "./pages";
|
||||||
import { PageEntry } from './pageentry';
|
import { PageEntry } from "./pageentry";
|
||||||
import { Replay } from './replay';
|
import { Replay } from "./replay";
|
||||||
import { Sorter } from './sorter';
|
import { Sorter } from "./sorter";
|
||||||
import { URLResources } from './url-resources';
|
import { URLResources } from "./url-resources";
|
||||||
import { Embed } from './embed';
|
import { Embed } from "./embed";
|
||||||
|
|
||||||
export { ReplayWebApp, Chooser, CollIndex, CollInfo, Coll, Story, GDrive,
|
export { ReplayWebApp, Chooser, CollIndex, CollInfo, Coll, Story, GDrive,
|
||||||
Loader, Pages, PageEntry,
|
Loader, Pages, PageEntry,
|
||||||
|
|||||||
+13
-13
@@ -1,9 +1,9 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css } from "lit-element";
|
||||||
import { wrapCss, clickOnSpacebarPress } from './misc';
|
import { wrapCss, clickOnSpacebarPress } from "./misc";
|
||||||
|
|
||||||
import { getReplayLink } from './pageutils';
|
import { getReplayLink } from "./pageutils";
|
||||||
|
|
||||||
import fasSearch from '@fortawesome/fontawesome-free/svgs/solid/search.svg';
|
import fasSearch from "@fortawesome/fontawesome-free/svgs/solid/search.svg";
|
||||||
|
|
||||||
import "keyword-mark-element/lib/keyword-mark.js";
|
import "keyword-mark-element/lib/keyword-mark.js";
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ class URLResources extends LitElement
|
|||||||
loading: { type: Boolean },
|
loading: { type: Boolean },
|
||||||
sortKey: { type: String },
|
sortKey: { type: String },
|
||||||
sortDesc: { type: Boolean }
|
sortDesc: { type: Boolean }
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
@@ -318,7 +318,7 @@ class URLResources extends LitElement
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="field flex-auto">
|
<div class="field flex-auto">
|
||||||
<div class="control has-icons-left ${this.loading ? 'is-loading' : ''}">
|
<div class="control has-icons-left ${this.loading ? "is-loading" : ""}">
|
||||||
<input type="text" class="input" @input="${this.onChangeQuery}" .value="${this.query}" type="text" placeholder="Enter URL to Search">
|
<input type="text" class="input" @input="${this.onChangeQuery}" .value="${this.query}" type="text" placeholder="Enter URL to Search">
|
||||||
<span class="icon is-left"><fa-icon .svg="${fasSearch}"/></span>
|
<span class="icon is-left"><fa-icon .svg="${fasSearch}"/></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -327,9 +327,9 @@ class URLResources extends LitElement
|
|||||||
</div>
|
</div>
|
||||||
<div class="control level-right">
|
<div class="control level-right">
|
||||||
<div style="margin-left: 1em" class="control">
|
<div style="margin-left: 1em" class="control">
|
||||||
<label class="radio has-text-left"><input type="radio" name="urltype" value="contains" ?checked="${this.urlSearchType === 'contains'}" @click="${this.onClickUrlType}"> Contains</label>
|
<label class="radio has-text-left"><input type="radio" name="urltype" value="contains" ?checked="${this.urlSearchType === "contains"}" @click="${this.onClickUrlType}"> Contains</label>
|
||||||
<label class="radio has-text-left"><input type="radio" name="urltype" value="prefix" ?checked="${this.urlSearchType === 'prefix'}" @click="${this.onClickUrlType}"> Prefix</label>
|
<label class="radio has-text-left"><input type="radio" name="urltype" value="prefix" ?checked="${this.urlSearchType === "prefix"}" @click="${this.onClickUrlType}"> Prefix</label>
|
||||||
<label class="radio has-text-left"><input type="radio" name="urltype" value="exact" ?checked="${this.urlSearchType === 'exact'}" @click="${this.onClickUrlType}"> Exact</label>
|
<label class="radio has-text-left"><input type="radio" name="urltype" value="exact" ?checked="${this.urlSearchType === "exact"}" @click="${this.onClickUrlType}"> Exact</label>
|
||||||
<span id="num-results" class="num-results" is-pulled-right" aria-live="polite" aria-atomic="true">${this.filteredResults.length} Result(s)</span>
|
<span id="num-results" class="num-results" is-pulled-right" aria-live="polite" aria-atomic="true">${this.filteredResults.length} Result(s)</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -350,10 +350,10 @@ class URLResources extends LitElement
|
|||||||
<table class="all-results" aria-labelledby="results-heading num-results">
|
<table class="all-results" aria-labelledby="results-heading num-results">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="columns results-head has-text-weight-bold">
|
<tr class="columns results-head has-text-weight-bold">
|
||||||
<th scope="col" class="column col-url is-6 is-hidden-mobile"><a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="url" class="${this.sortKey === "url" ? (this.sortDesc ? "desc" : "asc") : ''}">URL</a></th>
|
<th scope="col" class="column col-url is-6 is-hidden-mobile"><a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="url" class="${this.sortKey === "url" ? (this.sortDesc ? "desc" : "asc") : ""}">URL</a></th>
|
||||||
<th scope="col" class="column col-ts is-2 is-hidden-mobile"><a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="ts" class="${this.sortKey === "ts" ? (this.sortDesc ? "desc" : "asc") : ''}">Date</a></th>
|
<th scope="col" class="column col-ts is-2 is-hidden-mobile"><a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="ts" class="${this.sortKey === "ts" ? (this.sortDesc ? "desc" : "asc") : ""}">Date</a></th>
|
||||||
<th scope="col" class="column col-mime is-3 is-hidden-mobile"><a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="mime" class="${this.sortKey === "mime" ? (this.sortDesc ? "desc" : "asc") : ''}">Mime Type</a></th>
|
<th scope="col" class="column col-mime is-3 is-hidden-mobile"><a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="mime" class="${this.sortKey === "mime" ? (this.sortDesc ? "desc" : "asc") : ""}">Mime Type</a></th>
|
||||||
<th scope="col" class="column col-status is-1 is-hidden-mobile"><a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="status" class="${this.sortKey === "status" ? (this.sortDesc ? "desc" : "asc") : ''}">Status</a></th>
|
<th scope="col" class="column col-status is-1 is-hidden-mobile"><a role="button" href="#" @click="${this.onSort}" @keyup="${clickOnSpacebarPress}" data-key="status" class="${this.sortKey === "status" ? (this.sortDesc ? "desc" : "asc") : ""}">Status</a></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
|
|||||||
+39
-36
@@ -1,7 +1,9 @@
|
|||||||
const path = require('path');
|
/*eslint-env node */
|
||||||
const webpack = require('webpack');
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const path = require("path");
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
const webpack = require("webpack");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
const CopyPlugin = require("copy-webpack-plugin");
|
||||||
|
|
||||||
// fake url used in app to serve files
|
// fake url used in app to serve files
|
||||||
// can not use custom scheme due to service worker issues
|
// can not use custom scheme due to service worker issues
|
||||||
@@ -19,15 +21,15 @@ const GDRIVE_CLIENT_ID = "160798412227-tko4c82uopud11q105b2lvbogsj77hlg.apps.goo
|
|||||||
const BANNER_TEXT = "'[name].js is part of ReplayWeb.page (https://replayweb.page) Copyright (C) 2020-2021, Webrecorder Software. Licensed under the Affero General Public License v3.'";
|
const BANNER_TEXT = "'[name].js is part of ReplayWeb.page (https://replayweb.page) Copyright (C) 2020-2021, Webrecorder Software. Licensed under the Affero General Public License v3.'";
|
||||||
|
|
||||||
// IPFS ipfs-core lib url
|
// IPFS ipfs-core lib url
|
||||||
const IPFS_CORE_URL = "https://cdn.jsdelivr.net/npm/ipfs-core@0.4.2/dist/index.min.js";
|
const IPFS_CORE_URL = "https://cdn.jsdelivr.net/npm/ipfs-core@0.5.4/dist/index.min.js";
|
||||||
|
|
||||||
|
|
||||||
const electronMainConfig = (env, argv) => {
|
const electronMainConfig = (/*env, argv*/) => {
|
||||||
return {
|
return {
|
||||||
target: 'electron-main',
|
target: "electron-main",
|
||||||
mode: 'production',
|
mode: "production",
|
||||||
entry: {
|
entry: {
|
||||||
'electron': './src/electron-main.js',
|
"electron": "./src/electron-main.js",
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
@@ -37,8 +39,8 @@ const electronMainConfig = (env, argv) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, 'dist'),
|
path: path.join(__dirname, "dist"),
|
||||||
filename: '[name].js',
|
filename: "[name].js",
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
__dirname: false,
|
__dirname: false,
|
||||||
@@ -53,8 +55,8 @@ const electronMainConfig = (env, argv) => {
|
|||||||
new webpack.BannerPlugin(BANNER_TEXT),
|
new webpack.BannerPlugin(BANNER_TEXT),
|
||||||
new CopyPlugin({
|
new CopyPlugin({
|
||||||
patterns: [
|
patterns: [
|
||||||
{ from: 'node_modules/bcrypto/build/Release/bcrypto.node', to: 'build' },
|
{ from: "node_modules/bcrypto/build/Release/bcrypto.node", to: "build" },
|
||||||
{ from: 'node_modules/leveldown/prebuilds/', to: 'prebuilds' },
|
{ from: "node_modules/leveldown/prebuilds/", to: "prebuilds" },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -62,16 +64,16 @@ const electronMainConfig = (env, argv) => {
|
|||||||
"bufferutil": "bufferutil",
|
"bufferutil": "bufferutil",
|
||||||
"utf-8-validate": "utf-8-validate",
|
"utf-8-validate": "utf-8-validate",
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const electronPreloadConfig = (env, argv) => {
|
const electronPreloadConfig = (/*env, argv*/) => {
|
||||||
return {
|
return {
|
||||||
target: 'electron-preload',
|
target: "electron-preload",
|
||||||
mode: 'production',
|
mode: "production",
|
||||||
entry: {
|
entry: {
|
||||||
'preload': './src/electron-preload.js',
|
"preload": "./src/electron-preload.js",
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.BannerPlugin(BANNER_TEXT),
|
new webpack.BannerPlugin(BANNER_TEXT),
|
||||||
@@ -82,30 +84,30 @@ const electronPreloadConfig = (env, argv) => {
|
|||||||
__IPFS_CORE_URL__: JSON.stringify("")
|
__IPFS_CORE_URL__: JSON.stringify("")
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const browserConfig = (env, argv) => {
|
const browserConfig = (/*env, argv*/) => {
|
||||||
return {
|
return {
|
||||||
target: 'web',
|
target: "web",
|
||||||
mode: 'production',
|
mode: "production",
|
||||||
entry: {
|
entry: {
|
||||||
'ui': './src/ui.js',
|
"ui": "./src/ui.js",
|
||||||
'sw': './src/sw.js'
|
"sw": "./src/sw.js"
|
||||||
},
|
},
|
||||||
|
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname),
|
path: path.join(__dirname),
|
||||||
filename: '[name].js',
|
filename: "[name].js",
|
||||||
libraryTarget: 'self',
|
libraryTarget: "self",
|
||||||
globalObject: 'self',
|
globalObject: "self",
|
||||||
publicPath: '/'
|
publicPath: "/"
|
||||||
},
|
},
|
||||||
|
|
||||||
externals: {
|
externals: {
|
||||||
electron: 'electron',
|
electron: "electron",
|
||||||
},
|
},
|
||||||
|
|
||||||
devServer: {
|
devServer: {
|
||||||
@@ -113,7 +115,7 @@ const browserConfig = (env, argv) => {
|
|||||||
port: 9990,
|
port: 9990,
|
||||||
open: false,
|
open: false,
|
||||||
contentBase: path.join(__dirname),
|
contentBase: path.join(__dirname),
|
||||||
publicPath: '/'
|
publicPath: "/"
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -122,7 +124,7 @@ const browserConfig = (env, argv) => {
|
|||||||
}),
|
}),
|
||||||
new MiniCssExtractPlugin(),
|
new MiniCssExtractPlugin(),
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
__SW_NAME__: JSON.stringify('sw.js'),
|
__SW_NAME__: JSON.stringify("sw.js"),
|
||||||
__APP_FILE_SERVE_PREFIX__ : JSON.stringify(APP_FILE_SERVE_PREFIX),
|
__APP_FILE_SERVE_PREFIX__ : JSON.stringify(APP_FILE_SERVE_PREFIX),
|
||||||
__HELPER_PROXY__ : JSON.stringify(HELPER_PROXY),
|
__HELPER_PROXY__ : JSON.stringify(HELPER_PROXY),
|
||||||
__GDRIVE_CLIENT_ID__ : JSON.stringify(GDRIVE_CLIENT_ID),
|
__GDRIVE_CLIENT_ID__ : JSON.stringify(GDRIVE_CLIENT_ID),
|
||||||
@@ -132,7 +134,8 @@ const browserConfig = (env, argv) => {
|
|||||||
new webpack.BannerPlugin(BANNER_TEXT),
|
new webpack.BannerPlugin(BANNER_TEXT),
|
||||||
new CopyPlugin({
|
new CopyPlugin({
|
||||||
patterns: [
|
patterns: [
|
||||||
{ from: 'node_modules/ipfs-core/dist/index.min.js', to: 'ipfs-core.min.js' },
|
{ from: "node_modules/ipfs-core/dist/index.min.js", to: "ipfs-core.min.js" },
|
||||||
|
{ from: "package.json", to: "_data/package.json" }
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -141,19 +144,19 @@ const browserConfig = (env, argv) => {
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.svg$/,
|
test: /\.svg$/,
|
||||||
use: ['svg-inline-loader'],
|
use: ["svg-inline-loader"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /main.scss$/,
|
test: /main.scss$/,
|
||||||
use: ['css-loader', 'sass-loader']
|
use: ["css-loader", "sass-loader"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /wombat.js|wombatWorkers.js|index.html$/i,
|
test: /wombat.js|wombatWorkers.js|index.html$/i,
|
||||||
use: ['raw-loader'],
|
use: ["raw-loader"],
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = [ browserConfig, electronMainConfig, electronPreloadConfig ];
|
module.exports = [ browserConfig, electronMainConfig, electronPreloadConfig ];
|
||||||
|
|||||||
@@ -760,12 +760,12 @@
|
|||||||
"@webassemblyjs/wast-parser" "1.9.0"
|
"@webassemblyjs/wast-parser" "1.9.0"
|
||||||
"@xtuc/long" "4.2.2"
|
"@xtuc/long" "4.2.2"
|
||||||
|
|
||||||
"@webrecorder/wabac@^2.6.9":
|
"@webrecorder/wabac@^2.7.0":
|
||||||
version "2.6.9"
|
version "2.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/@webrecorder/wabac/-/wabac-2.6.9.tgz#2e453c9b3a71f4b4e20fc79db99243ac4b25716b"
|
resolved "https://registry.yarnpkg.com/@webrecorder/wabac/-/wabac-2.7.0.tgz#d1f54d7faf99aa0333c2ad805b72602dc2b95df1"
|
||||||
integrity sha512-NovRFw02gvjTa/RlAb6zZxmkh1O39Bc8xSXVgY3/w5t7/0JTqih5PNYr1VdbtGqpwO63/Wewp2OFP4JALtcA6Q==
|
integrity sha512-AShk6WfVS3ZYvGfT1ernMAH2uHOemUs62NsiA/oVb6OGwUW0BCVCKkzomyQOLaYxcTqza5nWs73Z+8yVimYq6A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@webrecorder/wombat" "^3.1.2"
|
"@webrecorder/wombat" "^3.1.4"
|
||||||
brotli "github:foliojs/brotli.js"
|
brotli "github:foliojs/brotli.js"
|
||||||
fast-xml-parser "^3.15.1"
|
fast-xml-parser "^3.15.1"
|
||||||
format-link-header "^3.1.1"
|
format-link-header "^3.1.1"
|
||||||
@@ -779,14 +779,13 @@
|
|||||||
parse5-html-rewriting-stream "^6.0.1"
|
parse5-html-rewriting-stream "^6.0.1"
|
||||||
parse5-sax-parser "^6.0.1"
|
parse5-sax-parser "^6.0.1"
|
||||||
path-parser "^6.1.0"
|
path-parser "^6.1.0"
|
||||||
unescape-js "^1.1.4"
|
warcio "^1.4.4"
|
||||||
warcio "^1.4.2"
|
|
||||||
wbn "^0.0.3"
|
wbn "^0.0.3"
|
||||||
|
|
||||||
"@webrecorder/wombat@^3.1.2":
|
"@webrecorder/wombat@^3.1.4":
|
||||||
version "3.1.2"
|
version "3.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/@webrecorder/wombat/-/wombat-3.1.2.tgz#2f0477d8b41fdf27ff68a15da54d4e6b5ea14cad"
|
resolved "https://registry.yarnpkg.com/@webrecorder/wombat/-/wombat-3.1.4.tgz#73a1c9d67c3e7d4166819a6c7b72d675b6bd685b"
|
||||||
integrity sha512-2LxW6aD5d1n7APkw3GXNjvwNtSfsiMBEv2iSumfG5z3JA4bqy1DhZL2l/JyTj/GsU1Jr5dKVlDGCEDumrEaflw==
|
integrity sha512-zUpJZ8AMghwUK7dN4C73hKegEEhs4GSoRd6/1ww/kmxUhDrysHH1H5uCESANU/8bulkn4ZQWdN6dxXd3vJgoxg==
|
||||||
|
|
||||||
"@xtuc/ieee754@^1.2.0":
|
"@xtuc/ieee754@^1.2.0":
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
@@ -1654,10 +1653,10 @@ builtin-status-codes@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||||
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
||||||
|
|
||||||
bulma@^0.9.0:
|
bulma@^0.9.2:
|
||||||
version "0.9.0"
|
version "0.9.2"
|
||||||
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.0.tgz#948c5445a49e9d7546f0826cb3820d17178a814f"
|
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.2.tgz#340011e119c605f19b8ca886bfea595f1deaf23c"
|
||||||
integrity sha512-rV75CJkubNUroAt0qCRkjznZLoaXq/ctfMXsMvKSL84UetbSyx5REl96e8GoQ04G4Tkw0XF3STECffTOQrbzOQ==
|
integrity sha512-e14EF+3VSZ488yL/lJH0tR8mFWiEQVCMi/BQUMi2TGMBOk+zrDg4wryuwm/+dRSHJw0gMawp2tsW7X1JYUCE3A==
|
||||||
|
|
||||||
bytes@3.0.0:
|
bytes@3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
@@ -2863,10 +2862,10 @@ electron-updater@^4.3.5:
|
|||||||
lodash.isequal "^4.5.0"
|
lodash.isequal "^4.5.0"
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
|
|
||||||
electron@^11.3.0:
|
electron@^11.4.3:
|
||||||
version "11.3.0"
|
version "11.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-11.3.0.tgz#87e8528fd23ae53b0eeb3a738f1fe0a3ad27c2db"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-11.4.3.tgz#74319635417c24fd19e31cfce5a39c8792e4014b"
|
||||||
integrity sha512-MhdS0gok3wZBTscLBbYrOhLaQybCSAfkupazbK1dMP5c+84eVMxJE/QGohiWQkzs0tVFIJsAHyN19YKPbelNrQ==
|
integrity sha512-RhCWJqiYK5oIRGOheilhg/nngCgk0fPgaf00KvbxorlvFZAz8OeMT5ShCpVsMSoyYhk4XEnn4orRly5ltaFYJg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/get" "^1.0.1"
|
"@electron/get" "^1.0.1"
|
||||||
"@types/node" "^12.0.12"
|
"@types/node" "^12.0.12"
|
||||||
@@ -9118,11 +9117,6 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
|
|||||||
is-fullwidth-code-point "^3.0.0"
|
is-fullwidth-code-point "^3.0.0"
|
||||||
strip-ansi "^6.0.0"
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
string.fromcodepoint@^0.2.1:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/string.fromcodepoint/-/string.fromcodepoint-0.2.1.tgz#8d978333c0bc92538f50f383e4888f3e5619d653"
|
|
||||||
integrity sha1-jZeDM8C8klOPUPOD5IiPPlYZ1lM=
|
|
||||||
|
|
||||||
string.prototype.trimend@^1.0.0:
|
string.prototype.trimend@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
|
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
|
||||||
@@ -9565,13 +9559,6 @@ uint8arrays@^2.0.5:
|
|||||||
multibase "^3.0.0"
|
multibase "^3.0.0"
|
||||||
web-encoding "^1.0.5"
|
web-encoding "^1.0.5"
|
||||||
|
|
||||||
unescape-js@^1.1.4:
|
|
||||||
version "1.1.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/unescape-js/-/unescape-js-1.1.4.tgz#4bc6389c499cb055a98364a0b3094e1c3d5da395"
|
|
||||||
integrity sha512-42SD8NOQEhdYntEiUQdYq/1V/YHwr1HLwlHuTJB5InVVdOSbgI6xu8jK5q65yIzuFCfczzyDF/7hbGzVbyCw0g==
|
|
||||||
dependencies:
|
|
||||||
string.fromcodepoint "^0.2.1"
|
|
||||||
|
|
||||||
union-value@^1.0.0:
|
union-value@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
|
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
|
||||||
@@ -9808,10 +9795,10 @@ vm-browserify@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||||
|
|
||||||
warcio@^1.4.2:
|
warcio@^1.4.4:
|
||||||
version "1.4.2"
|
version "1.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/warcio/-/warcio-1.4.2.tgz#48ff77a61de6112de8acadf655400074e2c13df8"
|
resolved "https://registry.yarnpkg.com/warcio/-/warcio-1.4.4.tgz#5cd942c7aca0d93b237ef27f9227ef3dec5d18ff"
|
||||||
integrity sha512-trdD7EiPGFsoYuiAC+jzbYQuM/9P2ZK9q7mUc6HAMVkhTsPEluWrgq3q0q3Uv7s3pS345nIt2NU9de/PQNCfLg==
|
integrity sha512-9UyVQoxxy0nRB1HmABeHEL0QMCdyiei8DjzGQxoMuPnzUtiLvtJFuJEJwwaYBNw0L71x2cQJq0l2o2r9A620YQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@peculiar/webcrypto" "^1.1.1"
|
"@peculiar/webcrypto" "^1.1.1"
|
||||||
esm "^3.2.25"
|
esm "^3.2.25"
|
||||||
|
|||||||
Reference in New Issue
Block a user