import { h, Component, createRef } from 'preact'
import htm from 'htm'
import { signal } from 'preact/signals'
const html = htm.bind(h)
export class NodeUI extends Component {
constructor() {//{{{
super()
this.menu = signal(false)
this.tree = signal(null)
this.node = signal(null)
this.nodeContent = createRef()
window.addEventListener('popstate', evt=>{
if(evt.state && evt.state.hasOwnProperty('nodeID'))
this.goToNode(evt.state.nodeID, true)
else
this.goToNode(0, true)
})
}//}}}
render() {//{{{
if(this.node.value === null)
return
let node = this.node.value
let tree = this.tree.value
let treeHTML = html`Tree`
if(tree !== null)
treeHTML = this.renderTree(tree)
let crumbs = [
html`
${crumbs}
${children.length > 0 ? html`
${children}
` : html``}
${node.ID > 0 ? html`
${node.Name}
<${NodeContent} key=${node.ID} content=${node.Content} ref=${this.nodeContent} />
` : html``}
`
/*
this.retrieveTree()} style="color: #000">
Start
${treeHTML}
*/
}//}}}
componentDidMount() {//{{{
let urlParams = new URLSearchParams(window.location.search)
let nodeID = urlParams.get('node')
let root = new Node(this.props.app, nodeID ? parseInt(nodeID) : 0)
root.retrieve(node=>{
this.node.value = node
})
}//}}}
showMenu() {//{{{
this.menu.value = true
}//}}}
goToNode(nodeID, dontPush) {//{{{
if(this.props.app.nodeModified.value) {
if(!confirm("Changes not saved. Do you want to discard changes?"))
return
}
if(!dontPush)
history.pushState({ nodeID }, '', `/?node=${nodeID}`)
let node = new Node(this.props.app, nodeID)
node.retrieve(node=>{
this.props.app.nodeModified.value = false
this.node.value = node
})
}//}}}
createNode() {//{{{
let name = prompt("Name")
if(!name)
return
this.props.app.request('/node/create', {
Name: name.trim(),
ParentID: this.node.value.ID,
})
.then(res=>{
this.goToNode(res.Node.ID)
})
.catch(this.props.app.responseError)
}//}}}
saveNode() {//{{{
let content = this.nodeContent.current.contentDiv.current.value
content = content
.replaceAll("\r", "")
.replaceAll("
", "")
this.props.app.request('/node/update', {
NodeID: this.node.value.ID,
Content: content,
})
.then(res=>{
this.props.app.nodeModified.value = false
})
.catch(this.props.app.responseError)
}//}}}
renameNode() {//{{{
let name = prompt("New name")
if(!name)
return
this.props.app.request('/node/rename', {
Name: name.trim(),
NodeID: this.node.value.ID,
})
.then(_=>{
this.goToNode(this.node.value.ID)
this.menu.value = false
})
.catch(this.props.app.responseError)
}//}}}
deleteNode() {//{{{
if(!confirm("Do you want to delete this note and all sub-notes?"))
return
this.props.app.request('/node/delete', {
NodeID: this.node.value.ID,
})
.then(_=>{
this.goToNode(this.node.value.ParentID)
this.menu.value = false
})
.catch(this.props.app.responseError)
}//}}}
retrieveTree() {//{{{
this.props.app.request('/node/tree', { StartNodeID: this.node.value.ID })
.then(res=>{
this.tree.value = res.Nodes
})
.catch(this.props.app.responseError)
}//}}}
renderTree(tree) {//{{{
return tree.map(node=>html`
${node.Name}
`)
}//}}}
}
class NodeContent extends Component {
constructor(props) {//{{{
super(props)
this.contentDiv = createRef()
this.state = {
modified: false,
//content: props.content,
}
}//}}}
render({ content }) {//{{{
return html`
`
}//}}}
componentDidMount() {//{{{
this.resize()
}//}}}
componentDidUpdate() {//{{{
this.resize()
}//}}}
contentChanged() {//{{{
window._app.current.nodeModified.value = true
this.resize()
}//}}}
resize() {//{{{
let textarea = this.contentDiv.current;
textarea.style.height = "auto";
textarea.style.height = textarea.scrollHeight + 16 + "px";
}//}}}
}
class Node {
constructor(app, nodeID) {//{{{
this.app = app
this.ID = nodeID
this.ParentID = 0
this.UserID = 0
this.Name = ''
this.Content = ''
this.Children = []
this.Crumbs = []
}//}}}
retrieve(callback) {//{{{
this.app.request('/node/retrieve', { ID: this.ID })
.then(res=>{
this.ParentID = res.Node.ParentID
this.UserID = res.Node.UserID
this.Name = res.Node.Name
this.Content = res.Node.Content
this.Children = res.Node.Children
this.Crumbs = res.Node.Crumbs
callback(this)
})
.catch(this.app.responseError)
}//}}}
}
// vim: foldmethod=marker