diff --git a/src/pageentry.js b/src/pageentry.js
new file mode 100644
index 0000000..d61b9fb
--- /dev/null
+++ b/src/pageentry.js
@@ -0,0 +1,348 @@
+import prettyBytes from 'pretty-bytes';
+
+import { LitElement, html, css } from 'lit-element';
+
+import "keyword-mark-element/lib/keyword-mark.js";
+
+import { getTS } from './pageutils';
+
+import { wrapCss } from './misc';
+
+
+// ===========================================================================
+class PageEntry extends LitElement
+{
+ constructor() {
+ super();
+ this.query = "";
+ this.textSnippet = "";
+ this.page = null;
+ this.replayPrefix = "";
+ this.deleting = false;
+ this.editable = false;
+ this.iconValid = false;
+ this.index = 0;
+ this.isSidebar = false;
+ this.isCurrent = false;
+
+ this.timestamp = "";
+ this.date = null;
+ }
+
+ static get properties() {
+ return {
+ query: { type: String },
+ textSnippet: { type: String },
+ page: { type: Object },
+ replayPrefix: { type: String },
+ deleting: { type: Boolean },
+ selected: { type: Boolean },
+ editable: { type: Boolean },
+ iconValid: { type: Boolean },
+ index: { type: Number },
+ isSidebar: { type: Boolean },
+ isCurrent: { type: Boolean },
+ timestamp: { type: String },
+ date: { type: Object }
+ }
+ }
+
+ static get styles() {
+ return wrapCss(css`
+ :host {
+ min-height: min-content;
+ width: 100%;
+ word-break: break-all;
+ position: relative;
+ display: flex;
+ flex-direction: row;
+ background: transparent;
+ }
+
+ .check-select {
+ padding-right: 1.0em;
+ height: 100%;
+ margin: auto 0 auto 0;
+ }
+
+ .columns {
+ width: 100%;
+ }
+
+ .full {
+ flex: auto;
+ min-height: 0px;
+ }
+
+ .sidebar .column {
+ width: unset !important;
+ }
+
+ .sidebar {
+ width: 100%;
+ }
+
+ .favicon {
+ width: 24px !important;
+ height: 24px !important;
+ display: inline-block;
+ vertical-align: text-bottom;
+ }
+ img.favicon {
+ filter: drop-shadow(1px 1px 2px grey);
+ }
+
+ .media-left {
+ align-self: center;
+ }
+
+ .delete {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ }
+
+ .delete:hover {
+ background-color: rgb(241, 70, 104);
+ }
+
+ @media screen and (max-width: 768px) {
+ ${PageEntry.sidebarStyles()}
+ }
+
+ ${PageEntry.sidebarStyles(css`.sidebar `)}
+
+ .current a {
+ background-color: rgb(207, 243, 255);
+ font-style: italic;
+ display: block;
+ }
+
+ .current .curr-page {
+ font-style: italic;
+ font-size: 9px;
+ color: black;
+ }
+
+ .is-inline-date {
+ display: none;
+ }
+ `);
+ }
+
+ static sidebarStyles(prefix = css``) {
+ return css`
+ ${prefix} .col-date {
+ margin-left: calc(24px + 1rem);
+ display: none;
+ }
+ ${prefix} .col-date div {
+ display: inline;
+ }
+ ${prefix} .col-index {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ margin-top: -0.75em;
+ }
+ ${prefix} .columns {
+ display: flex;
+ flex-direction: column-reverse;
+ }
+ ${prefix} .is-inline-date {
+ display: initial !important;
+ font-style: italic;
+ }
+ `;
+ }
+
+ updated(changedProperties) {
+ if (changedProperties.has("page") || changedProperties.has("query")) {
+ this.updateSnippet();
+ this.iconValid = !!this.page.favIconUrl;
+ //this.updateFavIcon();
+ this.deleting = false;
+
+ const res = this.getDateTS();
+ this.timestamp = res.timestamp;
+ this.date = res.date;
+ }
+ }
+
+ getDateTS() {
+ let date = null;
+ let ts = this.page.ts;
+ try {
+ date = new Date(this.page.ts || this.page.date);
+ } catch (e) {
+
+ }
+
+ const timestamp = (date && !isNaN(date)) ? getTS(date.toISOString()) : "";
+ return {date, timestamp};
+ }
+
+ render() {
+ const p = this.page;
+ const date = this.date;
+
+ const hasSize = typeof(p.size) === "number";
+
+ return html`
+ ${this.editable ? html`
+
+
+
` : ``}
+
+
+
+ ${this.editable ? html`
+ ${!this.deleting ? html`
+ ` : html`
+
+ `}` : ''}
+ `;
+ }
+
+ async updateFavIcon() {
+ if (!this.page.favIconUrl) {
+ this.favIconData = null;
+ return;
+ }
+
+ const resp = await fetch(`${this.replayPrefix}/${this.timestamp}id_/${this.page.favIconUrl}`);
+
+ if (resp.status != 200) {
+ this.favIconData = null;
+ return;
+ }
+
+ const payload = await resp.arrayBuffer();
+ const mime = resp.headers.get("content-type");
+
+ try {
+ this.favIconData = `data:${mime};base64,${btoa(String.fromCharCode.apply(null, payload))}`;
+ } catch (e) {
+ console.log(e);
+ this.favIconData = null;
+ }
+ }
+
+ updateSnippet() {
+ const oldVal = this.textSnippet;
+
+ if (!this.query || !this.page.text) {
+ this.textSnippet = null;
+ this.requestUpdate('textSnippet', oldVal);
+ return;
+ }
+
+ let textContent = this.page.text;
+ let query = this.query;
+
+ let inx = textContent.indexOf(this.query);
+
+ if (inx < 0) {
+ let textLower = textContent.toLowerCase();
+ let queryLower = query.toLowerCase();
+
+ inx = textLower.indexOf(queryLower);
+
+ if (inx < 0) {
+ this.textSnippet = null;
+ this.requestUpdate('textSnippet', oldVal);
+ return;
+ }
+
+ textContent = textLower;
+ query = queryLower;
+ }
+
+ //let lastInx = textContent.lastIndexOf(query);
+ let lastInx = inx;
+
+ inx = Math.max(inx - 100, 0);
+ lastInx = Math.min(lastInx + 200, textContent.length);
+
+ if (inx === 0 && lastInx === textContent.length) {
+ this.textSnippet = textContent;
+ } else {
+ this.textSnippet = "..." + textContent.slice(inx, lastInx) + "...";
+ }
+
+ this.requestUpdate('textSnippet', oldVal);
+ }
+
+ onReplay(event) {
+ event.preventDefault();
+
+ const data = {
+ url: this.page.url,
+ ts: this.timestamp,
+ view: "replay"
+ };
+ this.sendChangeEvent(data);
+ return false;
+ }
+
+ sendChangeEvent(data) {
+ this.dispatchEvent(new CustomEvent("coll-tab-nav", {bubbles: true, composed: true, detail: {data}}));
+ }
+
+ onSendDeletePage(event) {
+ const page = this.page.id;
+ this.deleting = true;
+ this.dispatchEvent(new CustomEvent("delete-page", {detail: {page}}));
+ }
+
+ onSendSelToggle(event) {
+ const page = this.page.id;
+ const selected = event.currentTarget.checked;
+ this.dispatchEvent(new CustomEvent("sel-page", {detail: {page, selected}}));
+ }
+}
+
+customElements.define("wr-page-entry", PageEntry);
+
+export { PageEntry };
diff --git a/src/pages.js b/src/pages.js
index b8db9ad..4fa89b1 100644
--- a/src/pages.js
+++ b/src/pages.js
@@ -4,10 +4,7 @@ import { LitElement, html, css } from 'lit-element';
import { wrapCss } from './misc';
import ndjson from 'fetch-ndjson';
-import prettyBytes from 'pretty-bytes';
-
import FlexSearch from 'flexsearch';
-import "keyword-mark-element/lib/keyword-mark.js";
import { getTS } from './pageutils';
@@ -824,340 +821,8 @@ class Pages extends LitElement
}
}
-// ===========================================================================
-class PageEntry extends LitElement
-{
- constructor() {
- super();
- this.query = "";
- this.textSnippet = "";
- this.page = null;
- this.replayPrefix = "";
- this.deleting = false;
- this.editable = false;
- this.iconValid = false;
- this.index = 0;
- this.isSidebar = false;
- this.isCurrent = false;
- this.timestamp = "";
- this.date = null;
- }
-
- static get properties() {
- return {
- query: { type: String },
- textSnippet: { type: String },
- page: { type: Object },
- replayPrefix: { type: String },
- deleting: { type: Boolean },
- selected: { type: Boolean },
- editable: { type: Boolean },
- iconValid: { type: Boolean },
- index: { type: Number },
- isSidebar: { type: Boolean },
- isCurrent: { type: Boolean },
- timestamp: { type: String },
- date: { type: Object }
- }
- }
-
- static get styles() {
- return wrapCss(css`
- :host {
- min-height: min-content;
- width: 100%;
- word-break: break-all;
- position: relative;
- display: flex;
- flex-direction: row;
- background: transparent;
- }
-
- .check-select {
- padding-right: 1.0em;
- height: 100%;
- margin: auto 0 auto 0;
- }
-
- .columns {
- width: 100%;
- }
-
- .full {
- flex: auto;
- min-height: 0px;
- }
-
- .sidebar .column {
- width: unset !important;
- }
-
- .sidebar {
- width: 100%;
- }
-
- .favicon {
- width: 24px !important;
- height: 24px !important;
- display: inline-block;
- vertical-align: text-bottom;
- }
- img.favicon {
- filter: drop-shadow(1px 1px 2px grey);
- }
-
- .media-left {
- align-self: center;
- }
-
- .delete {
- position: absolute;
- top: 8px;
- right: 8px;
- }
-
- .delete:hover {
- background-color: rgb(241, 70, 104);
- }
-
- @media screen and (max-width: 768px) {
- ${PageEntry.sidebarStyles()}
- }
-
- ${PageEntry.sidebarStyles(css`.sidebar `)}
-
- .current a {
- background-color: rgb(207, 243, 255);
- font-style: italic;
- display: block;
- }
-
- .current .curr-page {
- font-style: italic;
- font-size: 9px;
- color: black;
- }
-
- .is-inline-date {
- display: none;
- }
- `);
- }
-
- static sidebarStyles(prefix = css``) {
- return css`
- ${prefix} .col-date {
- margin-left: calc(24px + 1rem);
- display: none;
- }
- ${prefix} .col-date div {
- display: inline;
- }
- ${prefix} .col-index {
- position: absolute;
- top: 0px;
- left: 0px;
- margin-top: -0.75em;
- }
- ${prefix} .columns {
- display: flex;
- flex-direction: column-reverse;
- }
- ${prefix} .is-inline-date {
- display: initial !important;
- font-style: italic;
- }
- `;
- }
-
- updated(changedProperties) {
- if (changedProperties.has("page") || changedProperties.has("query")) {
- this.updateSnippet();
- this.iconValid = !!this.page.favIconUrl;
- //this.updateFavIcon();
- this.deleting = false;
-
- const res = this.getDateTS();
- this.timestamp = res.timestamp;
- this.date = res.date;
- }
- }
-
- getDateTS() {
- let date = null;
- let ts = this.page.ts;
- try {
- date = new Date(this.page.ts || this.page.date);
- } catch (e) {
-
- }
-
- const timestamp = (date && !isNaN(date)) ? getTS(date.toISOString()) : "";
- return {date, timestamp};
- }
-
- render() {
- const p = this.page;
- const date = this.date;
-
- const hasSize = typeof(p.size) === "number";
-
- return html`
- ${this.editable ? html`
-
-
-
` : ``}
-
-
-
- ${this.editable ? html`
- ${!this.deleting ? html`
- ` : html`
-
- `}` : ''}
- `;
- }
-
- async updateFavIcon() {
- if (!this.page.favIconUrl) {
- this.favIconData = null;
- return;
- }
-
- const resp = await fetch(`${this.replayPrefix}/${this.timestamp}id_/${this.page.favIconUrl}`);
-
- if (resp.status != 200) {
- this.favIconData = null;
- return;
- }
-
- const payload = await resp.arrayBuffer();
- const mime = resp.headers.get("content-type");
-
- try {
- this.favIconData = `data:${mime};base64,${btoa(String.fromCharCode.apply(null, payload))}`;
- } catch (e) {
- console.log(e);
- this.favIconData = null;
- }
- }
-
- updateSnippet() {
- const oldVal = this.textSnippet;
-
- if (!this.query || !this.page.text) {
- this.textSnippet = null;
- this.requestUpdate('textSnippet', oldVal);
- return;
- }
-
- let textContent = this.page.text;
- let query = this.query;
-
- let inx = textContent.indexOf(this.query);
-
- if (inx < 0) {
- let textLower = textContent.toLowerCase();
- let queryLower = query.toLowerCase();
-
- inx = textLower.indexOf(queryLower);
-
- if (inx < 0) {
- this.textSnippet = null;
- this.requestUpdate('textSnippet', oldVal);
- return;
- }
-
- textContent = textLower;
- query = queryLower;
- }
-
- let lastInx = textContent.lastIndexOf(query);
-
- inx = Math.max(inx - 100, 0);
- lastInx = Math.min(lastInx + 200, textContent.length);
-
- if (inx === 0 && lastInx === textContent.length) {
- this.textSnippet = textContent;
- } else {
- this.textSnippet = "..." + textContent.slice(inx, lastInx) + "...";
- }
-
- this.requestUpdate('textSnippet', oldVal);
- }
-
- onReplay(event) {
- event.preventDefault();
-
- const data = {
- url: this.page.url,
- ts: this.timestamp,
- view: "replay"
- };
- this.sendChangeEvent(data);
- return false;
- }
-
- sendChangeEvent(data) {
- this.dispatchEvent(new CustomEvent("coll-tab-nav", {bubbles: true, composed: true, detail: {data}}));
- }
-
- onSendDeletePage(event) {
- const page = this.page.id;
- this.deleting = true;
- this.dispatchEvent(new CustomEvent("delete-page", {detail: {page}}));
- }
-
- onSendSelToggle(event) {
- const page = this.page.id;
- const selected = event.currentTarget.checked;
- this.dispatchEvent(new CustomEvent("sel-page", {detail: {page, selected}}));
- }
-}
customElements.define("wr-page-view", Pages);
-customElements.define("wr-page-entry", PageEntry);
-export { Pages, PageEntry };
+export { Pages };
diff --git a/src/ui.js b/src/ui.js
index 49aad53..8e8dd45 100644
--- a/src/ui.js
+++ b/src/ui.js
@@ -6,6 +6,7 @@ import { Story } from './story';
import { GDrive } from './gdrive';
import { Loader } from './loader';
import { Pages } from './pages';
+import { PageEntry } from './pageentry';
import { Replay } from './replay';
import { Sorter } from './sorter';
import { URLResources } from './url-resources';