Compare commits
3 commits
83abc3f456
...
697576cb34
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
697576cb34 | ||
|
|
4976a6ebe0 | ||
|
|
b3e5d79403 |
7 changed files with 83 additions and 91 deletions
|
|
@ -92,7 +92,7 @@ button {
|
|||
border-right: none;
|
||||
}
|
||||
|
||||
n2-tree {
|
||||
n2-sidebar {
|
||||
display: none;
|
||||
|
||||
}
|
||||
|
|
@ -164,7 +164,7 @@ button {
|
|||
|
||||
border-right: 1px solid var(--line-color);
|
||||
|
||||
n2-tree {
|
||||
n2-sidebar {
|
||||
.el-treenodes {
|
||||
margin: 24px 32px 32px 32px;
|
||||
}
|
||||
|
|
@ -508,7 +508,7 @@ dialog.op {
|
|||
}
|
||||
|
||||
#tree {
|
||||
n2-tree {
|
||||
n2-sidebar {
|
||||
.el-treenodes {
|
||||
height: calc(100vh - 64px - 64px);
|
||||
margin: 0px;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
import { ROOT_NODE } from 'node_store'
|
||||
import { CustomHTMLElement } from './lib/custom_html_element.mjs'
|
||||
import { N2Tree } from 'tree'
|
||||
import { N2Sidebar } from 'sidebar'
|
||||
import { Node } from 'node'
|
||||
|
||||
export class App {
|
||||
constructor() {// {{{
|
||||
this.currentNode = null
|
||||
this.tree = new N2Tree()
|
||||
this.sidebar = new N2Sidebar()
|
||||
this.crumbs = new N2Crumbs()
|
||||
this.crumbsElement = document.getElementById('crumbs')
|
||||
this.nodeUI = document.getElementById('note')
|
||||
this.showNodeEventSequence = new ShowNodeEventSequence() // discard all GO_TO_NODE events
|
||||
|
||||
this.sidebar.render().then(sidebar => {
|
||||
document.getElementById('tree').append(sidebar)
|
||||
document.getElementById('tree-nodes')?.focus()
|
||||
})
|
||||
|
||||
_mbus.subscribe('TREE_TRUNK_FETCHED', async () => {
|
||||
// Subscribing to the start node existing after the tree trunk is
|
||||
|
|
@ -18,11 +23,8 @@ export class App {
|
|||
// root node itself, and the root node should be selected in the tree
|
||||
// after it is rendered when the site is shown without UUID in the URL.
|
||||
const startNode = await this.getStartNode()
|
||||
_mbus.subscribe(`NODE_COMPONENT_EXIST_${startNode.UUID}`, () => {
|
||||
this.goToNode(startNode.UUID, false, false)
|
||||
})
|
||||
|
||||
document.getElementById('tree').append(await this.tree.render())
|
||||
document.getElementById('tree').append(await this.sidebar.render())
|
||||
document.getElementById('tree-nodes')?.focus()
|
||||
|
||||
if (startNode.UUID == ROOT_NODE)
|
||||
|
|
@ -85,7 +87,7 @@ export class App {
|
|||
if (document.activeElement.id === 'tree-nodes') {
|
||||
this.nodeUI.takeFocus()
|
||||
} else {
|
||||
this.tree.focus()
|
||||
this.sidebar.focus()
|
||||
}
|
||||
break
|
||||
|
||||
|
|
@ -184,17 +186,38 @@ export class App {
|
|||
node.reset() // any modifications are discarded.
|
||||
|
||||
this.currentNode = node
|
||||
this.tree.setSelected(node, dontExpand)
|
||||
this.sidebar.setSelected(node, dontExpand)
|
||||
|
||||
const ancestors = await nodeStore.getNodeAncestry(node)
|
||||
_mbus.dispatch('CRUMBS_SET', ancestors, () => this.crumbsElement.replaceChildren(this.crumbs.render()))
|
||||
_mbus.dispatch('NODE_UI_OPEN', node)
|
||||
_mbus.dispatch('NODE_UNMODIFIED')
|
||||
_mbus.dispatch('TREE_EXPANSION', { expand: false, when: 'narrow' })
|
||||
|
||||
// Scrolls node into view.
|
||||
this.tree.makeVisible(node)
|
||||
// makeVisible normally expands all ancestor nodes to make the whole chain visible.
|
||||
// This is a bad idea when quickly navigating the tree, since the arrow navigation
|
||||
// has collapsed nodes which the event calling goToNode can come to undo, if the
|
||||
// event processing lags behind.
|
||||
await this.sidebar.makeVisible(node, ancestors, dontExpand)
|
||||
|
||||
_mbus.dispatch('CRUMBS_SET', ancestors, () => this.crumbsElement.replaceChildren(this.crumbs.render()))
|
||||
_mbus.dispatch('NODE_UI_OPEN', { node, eventSequence: this.showNodeEventSequence.next() })
|
||||
_mbus.dispatch('TREE_EXPANSION', { expand: false, when: 'narrow' })
|
||||
_mbus.dispatch('NODE_UNMODIFIED')
|
||||
}//}}}
|
||||
pageIsVisible(page) {// {{{
|
||||
let classList = document.querySelector('#main-page').classList
|
||||
return classList.contains(page)
|
||||
}// }}}
|
||||
}
|
||||
|
||||
class ShowNodeEventSequence {
|
||||
constructor() {
|
||||
this.seq = 0
|
||||
}
|
||||
next() {
|
||||
return ++this.seq
|
||||
}
|
||||
current() {
|
||||
return this.seq
|
||||
}
|
||||
}
|
||||
|
||||
class N2Crumbs extends CustomHTMLElement {
|
||||
|
|
|
|||
|
|
@ -199,9 +199,7 @@ export class NodeStore {
|
|||
}
|
||||
|
||||
Promise.all(hasChildrenPromises)
|
||||
.then(() => {
|
||||
resolve(nodes)
|
||||
})
|
||||
.then(() => resolve(nodes))
|
||||
}
|
||||
req.onerror = (event) => reject(event.target.error)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -80,8 +80,11 @@ export class N2PageHistory extends CustomHTMLElement {
|
|||
|
||||
})
|
||||
|
||||
_mbus.subscribe('NODE_UI_OPEN', async (event) => {
|
||||
await this.useNode(event.detail.data)
|
||||
_mbus.subscribe('SHOW_PAGE', async (event) => {
|
||||
if(event.detail.data.page != 'history')
|
||||
return
|
||||
|
||||
await this.useNode(_app.nodeUI.node)
|
||||
this.render()
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ export class N2PageNodeUI extends CustomHTMLElement {
|
|||
this.marked = new MarkedPosition()
|
||||
|
||||
_mbus.subscribe('NODE_UI_OPEN', event => {
|
||||
this.node = event.detail.data
|
||||
console.log(event.detail.data.eventSequence, _app.showNodeEventSequence.current())
|
||||
this.node = event.detail.data.node
|
||||
this.showMarkdown(true)
|
||||
this.render()
|
||||
})
|
||||
|
|
@ -376,10 +377,6 @@ export class Node {
|
|||
this.Children[i]._parent = this
|
||||
}
|
||||
|
||||
// Notify the tree that all children are fetched and ready to process.
|
||||
//_notes2.current.tree.fetchChildrenOn(this.UUID)
|
||||
_mbus.dispatch(`NODE_CHILDREN_FETCHED_${this.UUID}`)
|
||||
|
||||
return this.Children
|
||||
}//}}}
|
||||
setHasChildren(v) {// {{{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { ROOT_NODE } from 'node_store'
|
||||
import { CustomHTMLElement } from './lib/custom_html_element.mjs'
|
||||
import { Color, Solver } from './lib/css_colorize.mjs'
|
||||
import { Node } from './page_node.mjs'
|
||||
|
||||
// TreeExpandedHandler is responsible for collapsing or expanding
|
||||
// the node tree, wide view or narrow "mobile" view.
|
||||
|
|
@ -59,12 +58,12 @@ class TreeExpansionHandler {// {{{
|
|||
}
|
||||
}// }}}
|
||||
|
||||
export class N2Tree extends CustomHTMLElement {
|
||||
export class N2Sidebar extends CustomHTMLElement {
|
||||
static {// {{{
|
||||
this.tmpl = document.createElement('template')
|
||||
this.tmpl.innerHTML = `
|
||||
<style>
|
||||
n2-tree {
|
||||
n2-sidebar {
|
||||
#logo {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr min-content;
|
||||
|
|
@ -145,24 +144,21 @@ export class N2Tree extends CustomHTMLElement {
|
|||
treenode.render(true)
|
||||
})
|
||||
|
||||
this.populateFirstLevel()
|
||||
|
||||
/* XXX - set color */
|
||||
let color = new Color(0x80, 0x00, 0x33)
|
||||
let solver = new Solver(color)
|
||||
let result = solver.solve()
|
||||
// console.log(result.filter)
|
||||
console.log(result.filter)
|
||||
}// }}}
|
||||
async render() {// {{{
|
||||
if (this.rendered)
|
||||
alert('Tree should only be rendered once.')
|
||||
|
||||
|
||||
this.expandedNodes[ROOT_NODE] = true
|
||||
const startnode = await nodeStore.get(ROOT_NODE)
|
||||
const starttreenode = new N2TreeNode(this, startnode, null)
|
||||
this.treeNodeComponents[startnode.UUID] = starttreenode
|
||||
this.elTreenodes.appendChild(starttreenode.render())
|
||||
this.elTreenodes.appendChild(await starttreenode.render())
|
||||
|
||||
this.rendered = true
|
||||
return this
|
||||
|
|
@ -174,27 +170,6 @@ export class N2Tree extends CustomHTMLElement {
|
|||
this.elTreenodes.replaceChildren()
|
||||
this.populateFirstLevel()
|
||||
}// }}}
|
||||
populateFirstLevel() {//{{{
|
||||
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)
|
||||
}
|
||||
_mbus.dispatch('TREE_TRUNK_FETCHED')
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
console.log(e.type, e.error)
|
||||
alert(e.error)
|
||||
})
|
||||
}//}}}
|
||||
getNodeExpanded(UUID) {//{{{
|
||||
if (this.expandedNodes[UUID] === undefined)
|
||||
this.expandedNodes[UUID] = false
|
||||
|
|
@ -249,6 +224,8 @@ export class N2Tree extends CustomHTMLElement {
|
|||
// Holding shift down does it recursively.
|
||||
case Space:
|
||||
case 'Enter':
|
||||
if (n.UUID === ROOT_NODE)
|
||||
return
|
||||
const expanded = this.getNodeExpanded(n.UUID)
|
||||
if (event.shiftKey) {
|
||||
this.recursiveExpand(n, !expanded)
|
||||
|
|
@ -302,7 +279,7 @@ export class N2Tree extends CustomHTMLElement {
|
|||
return
|
||||
|
||||
const expanded = this.getNodeExpanded(n.UUID)
|
||||
if (expanded && n.hasChildren()) {
|
||||
if (expanded && n.hasChildren() && n.UUID !== ROOT_NODE) {
|
||||
this.setNodeExpanded(n, false)
|
||||
return
|
||||
}
|
||||
|
|
@ -452,26 +429,27 @@ export class N2Tree extends CustomHTMLElement {
|
|||
if (!state)
|
||||
await this.setNodeExpanded(node, false)
|
||||
}//}}}
|
||||
async makeVisible(node) {// {{{
|
||||
async makeVisible(node, providedAncestors, dontExpand) {// {{{
|
||||
const treenode = this.treeNodeComponents[node.UUID]
|
||||
|
||||
const ancestors = await nodeStore.getNodeAncestry(node)
|
||||
for (const ancestor of ancestors.reverse()) {
|
||||
this.setNodeExpanded(ancestor, true)
|
||||
if (!dontExpand) {
|
||||
const ancestors = providedAncestors || await nodeStore.getNodeAncestry(node)
|
||||
for (const ancestor of ancestors.reverse()) {
|
||||
this.setNodeExpanded(ancestor, true)
|
||||
}
|
||||
}
|
||||
|
||||
// The ROOT_NODE for example hasn't got a treenode.
|
||||
treenode?.scrollIntoView({ block: 'nearest' })
|
||||
}// }}}
|
||||
}
|
||||
customElements.define('n2-tree', N2Tree)
|
||||
customElements.define('n2-sidebar', N2Sidebar)
|
||||
|
||||
export class N2TreeNode extends CustomHTMLElement {
|
||||
static {// {{{
|
||||
this.tmpl = document.createElement('template')
|
||||
this.tmpl.innerHTML = `
|
||||
<style>
|
||||
n2-tree:focus-within {
|
||||
n2-sidebar:focus-within {
|
||||
.el-name {
|
||||
&.selected {
|
||||
span {
|
||||
|
|
@ -503,55 +481,48 @@ export class N2TreeNode extends CustomHTMLElement {
|
|||
`
|
||||
}// }}}
|
||||
|
||||
constructor(tree, node, parent) {//{{{
|
||||
constructor(sidebar, node, parent) {//{{{
|
||||
super()
|
||||
this.classList.add('node')
|
||||
|
||||
this.tree = tree
|
||||
this.sidebar = sidebar
|
||||
this.node = node
|
||||
this.parent = parent
|
||||
|
||||
this.children_populated = false
|
||||
this.rendered = false
|
||||
|
||||
this.elExpandToggle.addEventListener('click', () => this.tree.setNodeExpanded(this.node, !this.tree.getNodeExpanded(this.node.UUID)))
|
||||
this.elExpandToggle.addEventListener('click', () => this.sidebar.setNodeExpanded(this.node, !this.sidebar.getNodeExpanded(this.node.UUID)))
|
||||
this.elName.addEventListener('click', () => _mbus.dispatch('TREE_NODE_SELECTED', this.node))
|
||||
|
||||
_mbus.subscribe(`NODE_CHILDREN_FETCHED_${node.UUID}`, () => {
|
||||
this.render(true)
|
||||
})
|
||||
|
||||
_mbus.subscribe(`NODE_EXPAND_${node.UUID}`, _state => {
|
||||
this.render(true)
|
||||
})
|
||||
|
||||
if (this.node.Level === 0 || this.tree.getNodeExpanded(this.node.UUID))
|
||||
this.fetchChildren()
|
||||
}// }}}
|
||||
async fetchChildren() {//{{{
|
||||
async fetchChildren(force_fetch) {//{{{
|
||||
if (this.children_populated && !force_fetch)
|
||||
return
|
||||
|
||||
await this.node.fetchChildren()
|
||||
this.children_populated = true
|
||||
}//}}}
|
||||
render(force_update) {//{{{
|
||||
async render(force_update, force_refetch_children) {//{{{
|
||||
if (this.rendered && force_update !== true)
|
||||
return this
|
||||
|
||||
// Fetch the next level of children if the parent tree node is expanded and our children thus will be visible.
|
||||
const expanded = this.node.hasChildren() && this.tree.getNodeExpanded(this.node.UUID)
|
||||
if (this.sidebar.getNodeExpanded(this.node.UUID))
|
||||
await this.fetchChildren()
|
||||
|
||||
if (!this.children_populated && this.tree.getNodeExpanded(this.parent?.node.UUID)) {
|
||||
this.node.fetchChildren().then(() => this.children_populated = true)
|
||||
}
|
||||
|
||||
// Update the name and selected status
|
||||
// Update the name and selected status.
|
||||
this.elName.querySelector('span').innerText = this.node.get('Name')
|
||||
|
||||
if (this.tree.isSelected(this.node))
|
||||
if (this.sidebar.isSelected(this.node))
|
||||
this.elName.classList.add('selected')
|
||||
else
|
||||
this.elName.classList.remove('selected')
|
||||
|
||||
// Update expansion state
|
||||
const expanded = this.node.hasChildren() && this.sidebar.getNodeExpanded(this.node.UUID)
|
||||
if (expanded) {
|
||||
this.elChildren.classList.add('expanded')
|
||||
this.elChildren.classList.remove('collapsed')
|
||||
|
|
@ -565,27 +536,27 @@ export class N2TreeNode extends CustomHTMLElement {
|
|||
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/icon_home.svg`)
|
||||
else if (!this.node.hasChildren())
|
||||
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/leaf.svg`)
|
||||
else if (this.tree.getNodeExpanded(this.node.UUID))
|
||||
else if (this.sidebar.getNodeExpanded(this.node.UUID))
|
||||
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/expanded.svg`)
|
||||
else
|
||||
this.setImgSrc(this.elExpand, `/images/${window._VERSION}/collapsed.svg`)
|
||||
|
||||
// Should children be rendered?
|
||||
this.elChildren.innerHTML = ''
|
||||
let children = []
|
||||
if (expanded)
|
||||
children = this.node.Children.map(node => {
|
||||
let treenode = this.tree.treeNodeComponents[node.UUID]
|
||||
let treenode = this.sidebar.treeNodeComponents[node.UUID]
|
||||
if (treenode === undefined) {
|
||||
treenode = new N2TreeNode(this.tree, node, this)
|
||||
this.tree.treeNodeComponents[node.UUID] = treenode
|
||||
_mbus.dispatch(`NODE_COMPONENT_EXIST_${node.UUID}`)
|
||||
treenode = new N2TreeNode(this.sidebar, node, this)
|
||||
this.sidebar.treeNodeComponents[node.UUID] = treenode
|
||||
}
|
||||
return treenode
|
||||
})
|
||||
|
||||
const renderedChildren = []
|
||||
for (const c of children)
|
||||
this.elChildren.appendChild(c.render())
|
||||
renderedChildren.push(await c.render())
|
||||
this.elChildren.replaceChildren(...renderedChildren)
|
||||
|
||||
this.rendered = true
|
||||
return this
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
"crypto": "/js/{{ .VERSION }}/crypto.mjs",
|
||||
"node_store": "/js/{{ .VERSION }}/node_store.mjs",
|
||||
"node": "/js/{{ .VERSION }}/page_node.mjs",
|
||||
"tree": "/js/{{ .VERSION }}/tree.mjs"
|
||||
"sidebar": "/js/{{ .VERSION }}/sidebar.mjs"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue