Implemented a notification system for fetched children

This commit is contained in:
Magnus Åhall 2025-02-09 13:49:37 +01:00
parent bb6279c55a
commit 26fe670965
2 changed files with 62 additions and 14 deletions

View file

@ -385,9 +385,7 @@ export class Node {
if (this._children_fetched) if (this._children_fetched)
return this.Children return this.Children
this.Children = await nodeStore.getTreeNodes(this.UUID, this.Level + 1) this.Children = await nodeStore.getTreeNodes(this.UUID, this.Level + 1)
this._children_fetched = true this._children_fetched = true
// Children are sorted to allow for storing siblings befare and after. // Children are sorted to allow for storing siblings befare and after.
@ -403,6 +401,9 @@ export class Node {
this.Children[i]._parent = this this.Children[i]._parent = this
} }
// Notify the tree that all children are fetched and ready to process.
_notes2.current.tree.fetchChildrenOn(this.UUID)
return this.Children return this.Children
}//}}} }//}}}
hasChildren() {//{{{ hasChildren() {//{{{

View file

@ -81,6 +81,11 @@ class Tree extends Component {
this.expandedNodes = {} // keyed on UUID this.expandedNodes = {} // keyed on UUID
this.treeDiv = createRef() 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.props.app.tree = this
this.populateFirstLevel() this.populateFirstLevel()
@ -110,6 +115,20 @@ class Tree extends Component {
this.setSelected(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) {//{{{ populateFirstLevel(callback = null) {//{{{
nodeStore.get(ROOT_NODE) nodeStore.get(ROOT_NODE)
.then(node => node.fetchChildren()) .then(node => node.fetchChildren())
@ -142,7 +161,7 @@ class Tree extends Component {
this.treeNodeComponents[node.UUID]?.current.forceUpdate() this.treeNodeComponents[node.UUID]?.current.forceUpdate()
if (!dontExpand) if (!dontExpand)
this.setNodeExpanded(node.UUID, true) this.setNodeExpanded(node, true)
}//}}} }//}}}
isSelected(node) {//{{{ isSelected(node) {//{{{
return this.selectedNode?.UUID === node.UUID return this.selectedNode?.UUID === node.UUID
@ -152,7 +171,7 @@ class Tree extends Component {
const ancestry = await nodeStore.getNodeAncestry(node, []) const ancestry = await nodeStore.getNodeAncestry(node, [])
for (const i in ancestry) { for (const i in ancestry) {
await nodeStore.node(ancestry[i].UUID).fetchChildren() await nodeStore.node(ancestry[i].UUID).fetchChildren()
this.setNodeExpanded(ancestry[i].UUID, true) this.setNodeExpanded(ancestry[i], true)
} }
// Already a top node, no need to expand anything. // Already a top node, no need to expand anything.
@ -160,17 +179,29 @@ class Tree extends Component {
return return
// Start the chain of by expanding the top node. // Start the chain of by expanding the top node.
this.setNodeExpanded(ancestry[ancestry.length - 1].UUID, true) this.setNodeExpanded(ancestry[ancestry.length - 1], true)
}//}}} }//}}}
getNodeExpanded(UUID) {//{{{ getNodeExpanded(UUID) {//{{{
if (this.expandedNodes[UUID] === undefined) if (this.expandedNodes[UUID] === undefined)
this.expandedNodes[UUID] = signal(false) this.expandedNodes[UUID] = signal(false)
return this.expandedNodes[UUID].value return this.expandedNodes[UUID].value
}//}}} }//}}}
setNodeExpanded(UUID, value) {//{{{ async setNodeExpanded(node, value) {//{{{
// Creating a default value if it doesn't exist already. return new Promise((resolve, reject) => {
this.getNodeExpanded(UUID) const work = uuid=>{
this.expandedNodes[UUID].value = value // 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) {//{{{ getParentWithNextSibling(node) {//{{{
let currNode = node let currNode = node
@ -187,17 +218,33 @@ class Tree extends Component {
return currNode 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) {//{{{ async keyHandler(event) {//{{{
let handled = true let handled = true
const n = this.selectedNode const n = this.selectedNode
const Space = ' ' const Space = ' '
switch (event.key) { switch (event.key) {
// Space is toggling expansion. // Space and enter is toggling expansion.
// Holding shift down does it recursively.
case Space: case Space:
case 'Enter': case 'Enter':
const expanded = this.getNodeExpanded(n.UUID) const expanded = this.getNodeExpanded(n.UUID)
this.setNodeExpanded(n.UUID, !expanded) if (event.shiftKey) {
this.recursiveExpand(n, !expanded)
} else {
this.setNodeExpanded(n, !expanded)
}
break break
case 'g': case 'g':
@ -246,7 +293,7 @@ class Tree extends Component {
const expanded = this.getNodeExpanded(n.UUID) const expanded = this.getNodeExpanded(n.UUID)
if (expanded && n.hasChildren()) { if (expanded && n.hasChildren()) {
this.setNodeExpanded(n.UUID, false) this.setNodeExpanded(n, false)
return return
} }
@ -273,7 +320,7 @@ class Tree extends Component {
const expanded = this.getNodeExpanded(n.UUID) const expanded = this.getNodeExpanded(n.UUID)
if (!expanded && n.hasChildren()) { if (!expanded && n.hasChildren()) {
this.setNodeExpanded(n.UUID, true) this.setNodeExpanded(n, true)
return return
} }
@ -405,7 +452,7 @@ class TreeNode extends Component {
return html` return html`
<div class="node"> <div class="node">
<div class="expand-toggle" onclick=${() => { tree.setNodeExpanded(node.UUID, !tree.getNodeExpanded(node.UUID)) }}>${expandImg}</div> <div class="expand-toggle" onclick=${() => { tree.setNodeExpanded(node, !tree.getNodeExpanded(node.UUID)) }}>${expandImg}</div>
<div class="name ${selected}" onclick=${() => window._notes2.current.goToNode(node.UUID)}>${node.get('Name')}</div> <div class="name ${selected}" onclick=${() => window._notes2.current.goToNode(node.UUID)}>${node.get('Name')}</div>
<div class="children ${node.Children.length > 0 && tree.getNodeExpanded(node.UUID) ? 'expanded' : 'collapsed'}">${children}</div> <div class="children ${node.Children.length > 0 && tree.getNodeExpanded(node.UUID) ? 'expanded' : 'collapsed'}">${children}</div>
</div>` </div>`