Tree keyboard navigation
This commit is contained in:
parent
82f09dcb1d
commit
d5ffd4fb0a
1 changed files with 101 additions and 55 deletions
|
@ -185,74 +185,27 @@ class Tree extends Component {
|
||||||
|
|
||||||
async keyHandler(event) {//{{{
|
async keyHandler(event) {//{{{
|
||||||
let handled = true
|
let handled = true
|
||||||
let nodeExpanded = false
|
|
||||||
let siblingBefore = null
|
|
||||||
let siblingExpanded = false
|
|
||||||
let parent = null
|
|
||||||
const n = this.selectedNode
|
const n = this.selectedNode
|
||||||
|
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'j':
|
case 'j':
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
nodeExpanded = this.getNodeExpanded(n.UUID)
|
await this.navigateDown(this.selectedNode)
|
||||||
|
|
||||||
// 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.getParentNodeWithNextSibling(n)
|
|
||||||
if (wantedNode?.UUID === ROOT_NODE)
|
|
||||||
break
|
|
||||||
await _notes2.current.goToNode(wantedNode?.UUID, true, true)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodeExpanded && n.isLastSibling() && !n.hasChildren()) {
|
|
||||||
const wantedNode = this.getParentNodeWithNextSibling(n)
|
|
||||||
await _notes2.current.goToNode(wantedNode?.UUID, true, true)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// 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)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'k':
|
case 'k':
|
||||||
case 'ArrowUp':
|
case 'ArrowUp':
|
||||||
siblingBefore = n.getSiblingBefore()
|
await this.navigateUp(this.selectedNode)
|
||||||
if (siblingBefore !== null)
|
|
||||||
siblingExpanded = this.getNodeExpanded(siblingBefore.UUID)
|
|
||||||
|
|
||||||
if (n.isFirstSibling()) {
|
|
||||||
parent = n.getParent()
|
|
||||||
if (parent?.UUID === ROOT_NODE)
|
|
||||||
break
|
|
||||||
await _notes2.current.goToNode(parent?.UUID, true, true)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (siblingBefore !== null && siblingExpanded && siblingBefore.hasChildren()) {
|
|
||||||
await _notes2.current.goToNode(siblingBefore.Children[siblingBefore.Children.length - 1]?.UUID, true, true)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (siblingBefore) {
|
|
||||||
await _notes2.current.goToNode(siblingBefore.UUID, true, true)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'ArrowLeft':
|
case 'ArrowLeft':
|
||||||
|
await this.navigateLeft(this.selectedNode)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
case 'ArrowRight':
|
||||||
|
await this.navigateRight(this.selectedNode)
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -264,6 +217,99 @@ class Tree extends Component {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
}
|
}
|
||||||
}//}}}
|
}//}}}
|
||||||
|
async navigateLeft(n) {//{{{
|
||||||
|
const expanded = this.getNodeExpanded(n.UUID)
|
||||||
|
if (expanded && n.hasChildren()) {
|
||||||
|
this.setNodeExpanded(n.UUID, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isFirstSibling() && n.getParent().UUID !== ROOT_NODE) {
|
||||||
|
await _notes2.current.goToNode(n.getParent()?.UUID, true, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await _notes2.current.goToNode(n.getSiblingBefore()?.UUID, true, true)
|
||||||
|
}//}}}
|
||||||
|
async navigateRight(n) {//{{{
|
||||||
|
const siblingAfter = n.getSiblingAfter()
|
||||||
|
const expanded = this.getNodeExpanded(n.UUID)
|
||||||
|
|
||||||
|
if (!expanded && n.hasChildren()) {
|
||||||
|
this.setNodeExpanded(n.UUID, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expanded && n.hasChildren()) {
|
||||||
|
await _notes2.current.goToNode(n.Children[0]?.UUID, true, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isLastSibling()) {
|
||||||
|
const nextNode = this.getParentNodeWithNextSibling(n)
|
||||||
|
await _notes2.current.goToNode(nextNode?.UUID, true, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await _notes2.current.goToNode(n.getSiblingAfter()?.UUID, true, true)
|
||||||
|
}//}}}
|
||||||
|
async navigateUp(n) {//{{{
|
||||||
|
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) {//{{{
|
||||||
|
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.getParentNodeWithNextSibling(n)
|
||||||
|
if (wantedNode?.UUID === ROOT_NODE)
|
||||||
|
return
|
||||||
|
await _notes2.current.goToNode(wantedNode?.UUID, true, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeExpanded && n.isLastSibling() && !n.hasChildren()) {
|
||||||
|
const wantedNode = this.getParentNodeWithNextSibling(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
|
||||||
|
}
|
||||||
|
}//}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TreeNode extends Component {
|
class TreeNode extends Component {
|
||||||
|
|
Loading…
Add table
Reference in a new issue