Moveing of objects

This commit is contained in:
Magnus Åhall 2025-07-05 09:57:20 +02:00
parent cfd5bfd719
commit 25bbc0c748
7 changed files with 167 additions and 16 deletions

View file

@ -18,6 +18,8 @@ export class App {
'NODE_CREATE_DIALOG',
'NODE_DELETE',
'NODE_EDIT_NAME',
'NODE_MOVE',
'NODE_REMOVED',
'NODE_SELECTED',
'TREE_RELOAD_NODE',
'TYPES_LIST_FETCHED',
@ -41,8 +43,9 @@ export class App {
for (const n of document.querySelectorAll('#nodes .node.selected'))
n.classList.remove('selected')
for (const n of document.querySelectorAll(`#nodes .node[data-node-id="${event.detail}"]`))
n.classList?.add('selected')
if (event.detail !== null)
for (const n of document.querySelectorAll(`#nodes .node[data-node-id="${event.detail}"]`))
n.classList?.add('selected')
this.edit(event.detail)
break
@ -53,6 +56,20 @@ export class App {
this.nodeDelete(this.currentNode.ID)
break
case 'NODE_MOVE':
const nodes = this.tree.markedNodes()
if (!confirm(`Are you sure you want to move ${nodes.length} nodes here?`))
return
this.nodesMove(nodes, this.currentNode.ID)
break
case 'NODE_REMOVED':
// Event dispatched when a tree node is removed after an update.
if (this.currentNode.ID !== event.detail)
return
mbus.dispatch('NODE_SELECTED', null)
break
case 'EDITOR_NODE_SAVE':
this.nodeUpdate()
break
@ -79,12 +96,12 @@ export class App {
break
case 'TREE_RELOAD_NODE':
this.tree.updateNode(event.detail.parentNodeID)
this.tree.updateNode(parseInt(event.detail.parentNodeID))
.then(() => {
if (event.detail.callback)
event.detail.callback()
.catch(err => showError(err))
})
.catch(err => showError(err))
break
default:
@ -93,16 +110,20 @@ export class App {
}
}// }}}
keyHandler(event) {// {{{
let handled = true
if (!event.shiftKey || !event.altKey)
return
let handled = true
switch (event.key.toUpperCase()) {
case 'D':
mbus.dispatch('NODE_DELETE')
break
case 'M':
mbus.dispatch('NODE_MOVE')
break
case 'N':
if (!event.shiftKey || !event.altKey)
return
mbus.dispatch('NODE_CREATE_DIALOG')
break
@ -146,6 +167,12 @@ export class App {
}// }}}
edit(nodeID) {// {{{
if (nodeID === null) {
document.getElementById('editor-node').style.display = 'none'
this.currentNode = null
return
}
fetch(`/nodes/${nodeID}`)
.then(data => data.json())
.then(json => {
@ -240,6 +267,29 @@ export class App {
})
.catch(err => showError(err))
}// }}}
nodesMove(nodes, newParentID) {// {{{
const req = {
NewParentID: parseInt(newParentID),
NodeIDs: nodes.map(n => n.ID),
}
fetch(`/nodes/move`, {
method: 'POST',
body: JSON.stringify(req),
})
.then(data => data.json())
.then(json => {
if (!json.OK) {
showError(json.Error)
return
}
const newParentElement = this.tree.treeNodes.get(newParentID).children
for (const n of nodes)
newParentElement.append(this.tree.treeNodes.get(n.ID).element)
})
.catch(err => showError(err))
}// }}}
}
class NodeCreateDialog {
@ -306,10 +356,7 @@ class NodeCreateDialog {
}
mbus.dispatch('TREE_RELOAD_NODE', {
parentNodeID: this.parentNodeID,
callback: () => {
console.log('hum foo')
mbus.dispatch('NODE_SELECTED', json.NodeID)
},
callback: () => mbus.dispatch('NODE_SELECTED', json.NodeID)
})
this.dialog.close()
})
@ -374,6 +421,21 @@ export class Tree {
mbus.subscribe(e, event => this.eventHandler(event))
// click on the empty tree list to unmark all nodes.
const nodesEl = document.getElementById('nodes')
nodesEl.addEventListener('click', event => {
// To prevent accidentally removing all node marks,
// shift is required to be unpressed, since it is required to
// be pressed when marking nodes.
if (event.shiftKey)
return
const markedElements = document.querySelectorAll('#nodes .node.marked')
for (const e of markedElements)
e.classList.remove('marked')
})
// Fetch the top node to start
this.fetchNodes(0)
.then(node => {
const top = document.getElementById('nodes')
@ -426,6 +488,17 @@ export class Tree {
// Children are sorted according to type and name.
this.sortChildren(node.Children)
// Deleted or moved children
for (const c of thisTreeNode.children.children) {
const nodeID = parseInt(c.dataset.nodeId)
const nodeStillExist = node.Children.some(n => n.ID === nodeID)
if (!nodeStillExist) {
c.remove()
mbus.dispatch('NODE_REMOVED', nodeID)
}
}
// Update or add children
for (const n of node.Children) {
if (this.treeNodes.has(n.ID)) {
@ -439,10 +512,11 @@ export class Tree {
thisTreeNode.children.appendChild(treenode.render())
}
}
resolve()
})
.catch(err => reject(err))
.catch(err => { showError(err); reject(err) })
})
}// }}}
sortChildren(children) {// {{{
@ -456,6 +530,15 @@ export class Tree {
return 0
})
}// }}}
markedNodes() {// {{{
const markedElements = document.querySelectorAll('#nodes .node.marked')
const marked = []
for (const n of markedElements) {
const nodeID = n.getAttribute('data-node-id')
marked.push(this.treeNodes.get(parseInt(nodeID)).node)
}
return marked
}// }}}
}
export class TreeNode {
@ -483,7 +566,13 @@ export class TreeNode {
this.children = div.querySelector('.children')
this.expandImg = div.querySelector('.expand-status img')
div.querySelector('.name').addEventListener('click', () => mbus.dispatch('NODE_SELECTED', this.node.ID))
div.querySelector('.name').addEventListener('click', event => {
if (!event.shiftKey)
mbus.dispatch('NODE_SELECTED', this.node.ID)
else
this.element.classList.toggle('marked')
event.stopPropagation()
})
// data.NumChildren is set regardless of having fetched the children or not.
this.expandStatus = div.querySelector('.expand-status img')