import { CustomHTMLElement } from './lib/custom_html_element.mjs' import { Node } from './page_node.mjs' import { MarkedPosition } from './marked_position.mjs' export class N2PageHistory extends CustomHTMLElement { static PAGESIZE = 15 static {// {{{ this.tmpl = document.createElement('template') this.tmpl.innerHTML = `
Back to node

Actions
History
History on server:
History on client:
<
>
Document
` }// }}} constructor() {// {{{ super() this.selectedNode = null this.setAttribute('tabindex', '-1') this.addEventListener('keydown', event => this.keyHandler(event)) // Connect back icon and text to give the user a way back to the node. this.elBackImage.addEventListener('click', () => _mbus.dispatch('SHOW_PAGE', { page: 'node' })) this.elBackText.addEventListener('click', () => _mbus.dispatch('SHOW_PAGE', { page: 'node' })) this.elPrev.addEventListener('click', () => this.prevPage()) this.elNext.addEventListener('click', () => this.nextPage()) this.elDownloadHistory.addEventListener('click', async () => { await this.downloadHistory() await this.useNode(this.node) this.render(true) }) _mbus.subscribe('NODE_UI_OPEN', async (event) => { await this.useNode(event.detail.data) this.render() }) _mbus.subscribe('HISTORY_NODE_SELECTED', (event) => { this.selectedNode = event.detail.data.historyNode // Any selected history node is rendered with markdown. const marked = new MarkedPosition() this.elNodeMarkdown.innerHTML = marked.parse(this.selectedNode?.node.content()) }) }// }}} async render(keepFetchHistoryProgress) {// {{{ this.elNodeName.innerText = this.node.get('Name') this.elPage.innerText = `${this.page} / ${this.pages}` this.elStatsOnClient.innerText = `${this.nodesTotal}` this.elStatsOnServer.innerText = `${this.historyOnServerTotal}` if (this.nodesTotal <= N2PageHistory.PAGESIZE) this.elPagination.style.display = 'none' else this.elPagination.style.display = '' let nodes = await nodeStore.nodesHistory.retrievePage(this.node.UUID, N2PageHistory.PAGESIZE, this.page) let i = 0 let divs = nodes.map(n => { i++ const index = 1 + this.nodesTotal - (N2PageHistory.PAGESIZE * (this.page - 1) + i) const div = new N2PageHistoryNode(n, index) div.render() return div }) this.elNodes.replaceChildren(...divs) if (!keepFetchHistoryProgress) this.elFetchHistoryProgress.innerText = '' // Select the first node. if (!this.selectedNode) { this.elNodes.firstElementChild?.select() } }// }}} async useNode(node) {// {{{ this.node = node this.page = 1 this.nodesTotal = await nodeStore.nodesHistory.count(this.node.UUID) this.historyOnServerTotal = await this.getServerTotal() this.pages = Math.ceil(this.nodesTotal / N2PageHistory.PAGESIZE) }// }}} keyHandler(event) {// {{{ let handled = true switch (event.key) { case 'ArrowLeft': this.prevPage() break case 'ArrowRight': this.nextPage() break case 'ArrowUp': const prevNode = this.selectedNode?.previousElementSibling if (prevNode) prevNode.select() break case 'ArrowDown': const nextNode = this.selectedNode?.nextElementSibling if (nextNode) nextNode.select() break default: handled = false } if (handled) { event.stopPropagation() event.preventDefault() } }// }}} prevPage() {// {{{ if (this.page == 1) return // Selecting a node on another page is wrong. this.selectedNode = null this.page-- this.render() }// }}} nextPage() {// {{{ if (this.page >= this.pages) return // Selecting a node on another page is wrong. this.selectedNode = null this.page++ this.render() }// }}} async getServerTotal() {// {{{ const res = await fetch(`/node/history/count/${this.node.UUID}`, { headers: { "Authorization": 'Bearer ' + localStorage.getItem('token'), } }) const json = await res.json() if (!json.OK) { alert(json.Error) return } return json.Count }// }}} async downloadHistory() {// {{{ try { const nodes = [] let offset = 0 let hasMore = true while (hasMore) { const history = await this.downloadHistoryPage(offset) hasMore = history.HasMore for (const nodeData of history.Nodes) { nodes.push(new Node(nodeData)) } offset = nodes.length this.elFetchHistoryProgress.innerText = `${nodes.length} fetched.` } let num = 0 for (const node of nodes) { const ok = await nodeStore.nodesHistory.hasNode(node.UUID, node.get('Updated')) if (ok) num++ await nodeStore.nodesHistory.add(node) } this.elFetchHistoryProgress.innerText = `${nodes.length} fetched - all history fetched.` } catch (e) { console.error(e) alert(e) } }// }}} async downloadHistoryPage(offset) {// {{{ const res = await fetch(`/node/history/retrieve/${this.node.UUID}/${offset}`, { headers: { "Authorization": 'Bearer ' + localStorage.getItem('token'), } }) const json = await res.json() if (!json.OK) { alert(json.Error) return } return json }// }}} } customElements.define('n2-pagehistory', N2PageHistory) class N2PageHistoryNode extends CustomHTMLElement { static {// {{{ this.tmpl = document.createElement('template') this.tmpl.innerHTML = `
` }// }}} constructor(node, index) {// {{{ super() this.node = node this.index = index this.style.display = 'contents' this.selected = false this.addEventListener('click', () => this.select()) // Another history node has been selected. _mbus.subscribe('HISTORY_NODE_SELECTED', (event) => { if (this.node.get('Updated') == event.detail.data.historyNode.node.get('Updated')) return this.selected = false this.render() }) }// }}} select() {// {{{ this.selected = true // Other nodes are told to unselect and rerender. _mbus.dispatch('HISTORY_NODE_SELECTED', { historyNode: this }) this.render() }// }}} render() {// {{{ const date = this.node.get('Updated').slice(0, 10) const time = this.node.get('Updated').slice(11, 19) if (this.selected) this.classList.add('selected') else this.classList.remove('selected') this.elIndex.innerText = this.index this.elDate.innerText = date this.elTime.innerText = time this.elSize.innerText = this.node.get('Content').length this.elName.innerText = this.node.get('Name') }// }}} formatSize(s) {// {{{ let div = 1 let unit = 'B' if (s >= 1048576) { div = 1048576 unit = 'MB' } else if (s >= 1024) { div = 1024 unit = 'kB' } return new Intl.NumberFormat(undefined, { maximumFractionDigits: 0 }).format(Math.round(s / div)) + ' ' + unit }// }}} } customElements.define('n2-pagehistorynode', N2PageHistoryNode)