import { h, Component, createRef } from 'preact' import { signal } from 'preact/signals' import htm from 'htm' import { Node, NodeUI } from 'node' import { ROOT_NODE } from 'node_store' import { TreeNative } from 'tree' const html = htm.bind(h) export class Notes2 extends Component { constructor() {//{{{ super() this.nodeUI = createRef() this.reloadTree = signal(0) this.state = { startNode: null, } this.op = signal('') this.treeNative = new TreeNative() window._sync = new Sync() window._sync.run() new OpSearch() this.getStartNode() }//}}} render(_props, { startNode }) {//{{{ console.log('notes2 render') const treeKey = `tree-${this.reloadTree}` console.log('treeKey', treeKey) if (startNode === null) return /* let op = null switch(this.op.value) { case 'search': op = html`<${OpSearch} />` break } */ return html` <${Tree} app=${this} key=${treeKey} startNode=${startNode} /> <${NodeUI} app=${this} ref=${this.nodeUI} startNode=${startNode} /> ` }//}}} getStartNode() {//{{{ let nodeUUID = ROOT_NODE // Is a UUID provided on the URI as an anchor? const parts = document.URL.split('#') if (parts[1]?.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) nodeUUID = parts[1] nodeStore.get(nodeUUID).then(node => { this.setState({ startNode: node }) }) }//}}} async goToNode(nodeUUID, dontPush, dontExpand) {//{{{ if (nodeUUID === null || nodeUUID === undefined) return // Don't switch notes until saved. if (this.nodeUI.current.nodeModified.value) { if (!confirm("Changes not saved. Do you want to discard changes?")) return } if (!dontPush) history.pushState({ nodeUUID }, '', `/#${nodeUUID}`) // New node is fetched in order to retrieve content and files. // Such data is unnecessary to transfer for tree/navigational purposes. const node = nodeStore.node(nodeUUID) const ancestors = await nodeStore.getNodeAncestry(node) this.nodeUI.current.setNode(node) this.nodeUI.current.setCrumbs(ancestors) this.tree.setSelected(node, dontExpand) this.treeNative.setSelected(node, dontExpand) }//}}} logout() {//{{{ localStorage.removeItem('session.UUID') location.href = '/' }//}}} } class Op { constructor(id) { this.id = id _mbus.subscribe(this.id, p => this.render(p)) } render(html) { const op = document.getElementById('op') const t = document.createElement('template') t.innerHTML = `${html}` op.replaceChildren(t.content) document.getElementById(this.id).showModal() } get(selector) { return document.querySelector(`#${this.id} ${selector}`) } bind(selector, event, fn) { this.get(selector).addEventListener(event, evt => fn(evt)) } } function tmpl(html) { const el = document.createElement('template') el.innerHTML = html return el.content.children } class OpSearch extends Op { constructor() { super('op-search') } render() { super.render(`
Search
Results
`) this.bind('input[type="text"]', 'keydown', evt => this.search(evt)) } search(event) { if (event.key !== 'Enter') return const searchFor = document.querySelector('#op-search input').value nodeStore.search(searchFor, ROOT_NODE) .then(res => this.displayResults(res)) } displayResults(results) { const rs = [] for (const r of results) { const ancestors = r.ancestry.reverse().map(a => { const div = tmpl(`
${a.data.Name}
`) div[0].addEventListener('click', () => _notes2.current.goToNode(a.UUID)) return div[0] }) const div = tmpl(`
${r.name}
`) div[0].addEventListener('click', () => _notes2.current.goToNode(r.uuid)) rs.push(...div) const ancDev = tmpl('
') ancDev[0].append(...ancestors) rs.push(ancDev[0]) } this.get('.results').replaceChildren(...rs) } } // vim: foldmethod=marker