diff --git a/static/js/notes2.mjs b/static/js/notes2.mjs
index 50286af..ddaf891 100644
--- a/static/js/notes2.mjs
+++ b/static/js/notes2.mjs
@@ -86,404 +86,6 @@ export class Notes2 extends Component {
}//}}}
}
-class Tree extends Component {
- constructor(props) {//{{{
- super(props)
- console.log('new tree')
- this.treeNodeComponents = {}
- this.treeTrunk = []
- this.selectedNode = null
- this.expandedNodes = {} // keyed on UUID
- this.treeDiv = createRef()
-
- // childrenFetchedCallbacks is keyed on a UUID and each
- // item is an array with callbacks called when a UUID has
- // had all children fetched.
- this.childrenFetchedCallbacks = {}
-
- this.props.app.tree = this
-
- this.populateFirstLevel()
- }//}}}
- render({ app }) {//{{{
- const renderedTreeTrunk = this.treeTrunk.map(node => {
- this.treeNodeComponents[node.UUID] = createRef()
- return html`<${TreeNode} key=${`treenode_${node.UUID}`} tree=${this} node=${node} ref=${this.treeNodeComponents[node.UUID]} selected=${node.UUID === app.state.startNode?.UUID} />`
- })
-
- return html`
-
-
_notes2.current.goToNode(ROOT_NODE)}>

-
-

_mbus.dispatch('op-search')} />
-

_sync.run()} />
-
- ${renderedTreeTrunk}
-
`
- }//}}}
- componentDidMount() {//{{{
- //this.treeDiv.current.addEventListener('keydown', event => this.keyHandler(event))
-
- // This will show and select the treenode that is selected in the node UI.
- const node = _notes2.current?.nodeUI.current?.node.value
- if (node === null)
- return
- _notes2.current.tree.expandToTrunk(node)
- this.setSelected(node)
- }//}}}
-
- fetchChildrenNotify(uuid, fn) {//{{{
- if (this.childrenFetchedCallbacks[uuid] === undefined)
- this.childrenFetchedCallbacks[uuid] = [fn]
- else
- this.childrenFetchedCallbacks[uuid].push(fn)
- }//}}}
- fetchChildrenOn(uuid) {//{{{
- if (this.childrenFetchedCallbacks[uuid] === undefined)
- return
- for (const fn of this.childrenFetchedCallbacks[uuid])
- fn(uuid)
- delete this.childrenFetchedCallbacks[uuid]
- }//}}}
-
- populateFirstLevel(callback = null) {//{{{
- nodeStore.get(ROOT_NODE)
- .then(node => node.fetchChildren())
- .then(children => {
- this.treeNodeComponents = {}
- this.treeTrunk = []
- for (const node of children) {
- // The root node isn't supposed to be shown in the tree.
- if (node.UUID === ROOT_NODE)
- continue
- if (node.ParentUUID === ROOT_NODE)
- this.treeTrunk.push(node)
- }
- this.forceUpdate()
- if (callback)
- callback()
-
- })
- .catch(e => { console.log(e); console.log(e.type, e.error); alert(e.error) })
- }//}}}
- setSelected(node, dontExpand) {//{{{
- // The previously selected node, if any, needs to be rerendered
- // to not retain its 'selected' class.
- const prevUUID = this.selectedNode?.UUID
- this.selectedNode = node
- if (prevUUID)
- this.treeNodeComponents[prevUUID]?.current.forceUpdate()
-
- // And now the newly selected node is rerendered.
- this.treeNodeComponents[node.UUID]?.current.forceUpdate()
-
- if (!dontExpand)
- this.setNodeExpanded(node, true)
- }//}}}
- isSelected(node) {//{{{
- return this.selectedNode?.UUID === node.UUID
- }//}}}
- async expandToTrunk(node) {//{{{
- // Get all ancestors from a certain node up to the highest grandparent.
- const ancestry = await nodeStore.getNodeAncestry(node, [])
- for (const i in ancestry) {
- await nodeStore.node(ancestry[i].UUID).fetchChildren()
- this.setNodeExpanded(ancestry[i], true)
- }
-
- // Already a top node, no need to expand anything.
- if (ancestry.length === 0)
- return
-
- // Start the chain of by expanding the top node.
- this.setNodeExpanded(ancestry[ancestry.length - 1], true)
- }//}}}
- getNodeExpanded(UUID) {//{{{
- if (this.expandedNodes[UUID] === undefined)
- this.expandedNodes[UUID] = signal(false)
- return this.expandedNodes[UUID].value
- }//}}}
- async setNodeExpanded(node, value) {//{{{
- return new Promise((resolve, reject) => {
- const work = uuid => {
- // Creating a default value if it doesn't exist already.
- this.getNodeExpanded(uuid)
- this.expandedNodes[uuid].value = value
- resolve()
- }
-
- if (node.hasFetchedChildren()) {
- work(node.UUID)
- return
- } else {
- this.fetchChildrenNotify(node.UUID, uuid => work(uuid))
- }
- })
- }//}}}
- getParentWithNextSibling(node) {//{{{
- let currNode = node
- while (currNode !== null && currNode.UUID !== ROOT_NODE && currNode.getSiblingAfter() === null) {
- currNode = currNode.getParent()
- }
- return currNode?.getSiblingAfter()
- }//}}}
- getLastExpandedNode(node) {//{{{
- let currNode = node
- while (this.getNodeExpanded(currNode.UUID) && currNode.hasChildren()) {
- currNode = currNode.Children[currNode.Children.length - 1]
- }
- return currNode
- }//}}}
-
- async recursiveExpand(node, state) {//{{{
- if (state)
- await this.setNodeExpanded(node, true)
-
- for (const child of node.Children)
- await this.recursiveExpand(child, state)
-
- if (!state)
- await this.setNodeExpanded(node, false)
- }//}}}
-
- async keyHandler(event) {//{{{
- let handled = true
- const n = this.selectedNode
- const Space = ' '
-
- // This handler would otherwise react to stuff like Ctrl+L.
- if (event.ctrlKey || event.altKey)
- return
-
- switch (event.key) {
- // Space and enter is toggling expansion.
- // Holding shift down does it recursively.
- case Space:
- case 'Enter':
- const expanded = this.getNodeExpanded(n.UUID)
- if (event.shiftKey) {
- this.recursiveExpand(n, !expanded)
- } else {
- this.setNodeExpanded(n, !expanded)
- }
- break
-
- case 'g':
- case 'Home':
- this.navigateTop()
- break
-
- case 'G':
- case 'End':
- this.navigateBottom()
- break
-
- case 'j':
- case 'ArrowDown':
- await this.navigateDown(this.selectedNode)
- break
-
- case 'k':
- case 'ArrowUp':
- await this.navigateUp(this.selectedNode)
- break
-
- case 'h':
- case 'ArrowLeft':
- await this.navigateLeft(this.selectedNode)
- break
-
- case 'l':
- case 'ArrowRight':
- await this.navigateRight(this.selectedNode)
- break
-
- default:
- // nonsole.log(event.key)
- handled = false
- }
-
- if (handled) {
- event.preventDefault()
- event.stopPropagation()
- }
- }//}}}
- async navigateLeft(n) {//{{{
- if (n === null)
- return
-
- const expanded = this.getNodeExpanded(n.UUID)
- if (expanded && n.hasChildren()) {
- this.setNodeExpanded(n, false)
- return
- }
-
- if (n.isFirstSibling() && n.getParent().UUID !== ROOT_NODE) {
- await _notes2.current.goToNode(n.getParent()?.UUID, true, true)
- return
- }
-
- const siblingBefore = n.getSiblingBefore()
- const siblingExpanded = this.getNodeExpanded(siblingBefore?.UUID)
- if (siblingBefore !== null && siblingExpanded && siblingBefore.hasChildren()) {
- const siblingAbove = this.getLastExpandedNode(siblingBefore)
- await _notes2.current.goToNode(siblingAbove?.UUID, true, true)
- return
- }
-
- await _notes2.current.goToNode(n.getSiblingBefore()?.UUID, true, true)
- }//}}}
- async navigateRight(n) {//{{{
- if (n === null)
- return
-
- const siblingAfter = n.getSiblingAfter()
- const expanded = this.getNodeExpanded(n.UUID)
-
- if (!expanded && n.hasChildren()) {
- this.setNodeExpanded(n, true)
- return
- }
-
- if (expanded && n.hasChildren()) {
- await _notes2.current.goToNode(n.Children[0]?.UUID, true, true)
- return
- }
-
- if (n.isLastSibling()) {
- const nextNode = this.getParentWithNextSibling(n)
- await _notes2.current.goToNode(nextNode?.UUID, true, true)
- return
- }
-
- await _notes2.current.goToNode(n.getSiblingAfter()?.UUID, true, true)
- }//}}}
- async navigateUp(n) {//{{{
- if (n === null)
- return
-
- let parent = null
- const siblingBefore = n.getSiblingBefore()
- let siblingExpanded = false
- if (siblingBefore !== null)
- siblingExpanded = this.getNodeExpanded(siblingBefore.UUID)
-
- if (n.isFirstSibling()) {
- parent = n.getParent()
- if (parent?.UUID === ROOT_NODE)
- return
- await _notes2.current.goToNode(parent?.UUID, true, true)
- return
- }
-
- if (siblingBefore !== null && siblingExpanded && siblingBefore.hasChildren()) {
- await _notes2.current.goToNode(siblingBefore.Children[siblingBefore.Children.length - 1]?.UUID, true, true)
- return
- }
-
- if (siblingBefore) {
- await _notes2.current.goToNode(siblingBefore.UUID, true, true)
- return
- }
- }//}}}
- async navigateDown(n) {//{{{
- if (n === null)
- return
-
- const nodeExpanded = this.getNodeExpanded(n.UUID)
-
- // Last node, not expanded, so it matters not whether it has children or not.
- // Traverse upward to nearest parent with next sibling.
- if (!nodeExpanded && n.isLastSibling()) {
- const wantedNode = this.getParentWithNextSibling(n)
- await _notes2.current.goToNode(wantedNode?.UUID, true, true)
- return
- }
-
- if (nodeExpanded && n.isLastSibling() && !n.hasChildren()) {
- const wantedNode = this.getParentWithNextSibling(n)
- await _notes2.current.goToNode(wantedNode?.UUID, true, true)
- return
- }
-
- // Node not expanded. Go to this node's next sibling.
- // GoToNode will abort if given null.
- if (!nodeExpanded || !n.hasChildren()) {
- await _notes2.current.goToNode(n.getSiblingAfter()?.UUID, true, true)
- return
- }
-
- // Node is expanded.
- // Children will be visually beneath this node, if any.
- if (nodeExpanded && n.hasChildren()) {
- await _notes2.current.goToNode(n.Children[0].UUID, true, true)
- return
- }
- }//}}}
- async navigateTop() {//{{{
- const root = await nodeStore.get(ROOT_NODE)
- if (root.Children.length === 0)
- return
- await _notes2.current.goToNode(root.Children[0]?.UUID, true, true)
- }//}}}
- async navigateBottom() {//{{{
- const root = await nodeStore.get(ROOT_NODE)
- if (root.Children.length === 0)
- return
-
- const toplevel = root.Children[root.Children.length - 1]
- const toplevelExpanded = this.getNodeExpanded(toplevel?.UUID)
-
- if (toplevelExpanded) {
- const lastnode = this.getLastExpandedNode(toplevel)
- await _notes2.current.goToNode(lastnode?.UUID, true, true)
- } else
- await _notes2.current.goToNode(root.Children[root.Children.length - 1]?.UUID, true, true)
- }//}}}
-}
-
-class TreeNode extends Component {
- constructor(props) {//{{{
- super(props)
- this.children_populated = signal(false)
- if (this.props.node.Level === 0 || this.props.tree.getNodeExpanded(this.props.node.UUID))
- this.fetchChildren()
- }//}}}
- render({ tree, node, parent }) {//{{{
- // Fetch the next level of children if the parent tree node is expanded and our children thus will be visible.
- const selected = tree.isSelected(node) ? 'selected' : ''
-
- if (!this.children_populated.value && tree.getNodeExpanded(parent?.props.node.UUID))
- this.fetchChildren()
-
- const children = node.Children.map(node => {
- tree.treeNodeComponents[node.UUID] = createRef()
- return html`<${TreeNode} key=${`treenode_${node.UUID}`} tree=${tree} node=${node} parent=${this} ref=${tree.treeNodeComponents[node.UUID]} selected=${node.UUID === tree.props.app.startNode?.UUID} />`
- })
-
- let expandImg = ''
- if (node.Children.length === 0)
- expandImg = html`
`
- else {
- if (tree.getNodeExpanded(node.UUID))
- expandImg = html`
`
- else
- expandImg = html`
`
- }
-
- return html`
-
-
{ tree.setNodeExpanded(node, !tree.getNodeExpanded(node.UUID)) }}>${expandImg}
-
window._notes2.current.goToNode(node.UUID)}>${node.get('Name')}
-
${children}
-
`
- }//}}}
- async fetchChildren() {//{{{
- await this.props.node.fetchChildren()
- this.children_populated.value = true
- }//}}}
-}
-
class Op {
constructor(id) {
this.id = id