mbraak / jqTree

Tree widget for jQuery
https://mbraak.github.io/jqTree/
Apache License 2.0
1.02k stars 177 forks source link

Drag & Drop multiple nodes #794

Closed TomDeFord closed 6 months ago

TomDeFord commented 6 months ago

Once again, thanks for the effort you've put into this project.

Using addToSelection, removeFromSelection, etc. I can happily multi-select nodes in jqTree. However when dragging only the node selected at the start of the drag gets moved.

Is it possible to do this currently? Or would it be possible to add a PR to move all nodes returned from 'getSelectedNodes' after the drag is released. I appreciate that this may require an enable/disable flag as it is a change to its current behaviour.

I'm using version 1.8.1 of jqTree.

Many thanks.

TomDeFord commented 6 months ago

So 10 seconds after I post this the solution seems obvious: adding something like the following to the tree.move event seems to do the job:

if (selectedNodes.length > 1)
    selectedNodes.forEach(node => { if (node != movedNode) $tree.tree('moveNode', node, targetNode, position); });
TomDeFord commented 6 months ago

So a hopefully more useful question; how can I sort the array from 'getSelectedNodes' based on a top to bottom position in the tree?

When I drop the nodes I want them to remain in the same visual order that they appear, even if that is from multiple separate parents. Currently the order is based on the sequence in which they were clicked and hence added to the getSelectedNodes array.

mbraak commented 6 months ago

What I can think of:

// Create a set of the selected nodes
// assuming $tree is the jquery tree element.
const selectedNodesSet =  new Set($tree.tree(getSelectedNodes'));

const sortedSelectedNodes = [];

// get the root node
const tree = $tree.tree('getTree');

// Iterate over all the nodes in sorted order
// This uses the iterate function, which is not documented yet.
tree.iterate((node) => {
  // If the node is selected, then add it to sortedSelectedNodes 
  if (selectedNodesSet .has(node)) {
    sortedSelectedNodes.push(node);
  }

  // Return true so iterate continues.
  return true;
});

// Now sortedSelectedNodes should contain the selected nodes in sorted order.

I think this should work, but I haven't tested it.

TomDeFord commented 6 months ago

Thanks that works a treat, the iterate function makes all the difference. My old solution builds a path for each selected node based on its depth and its parent's depths and sorted by that, works but a bit convoluted. Thanks again.