-
-
Notifications
You must be signed in to change notification settings - Fork 604
ExtDnd
About Fancytree drag-and-drop extension.
- Status: beta
- example
Add Drag-and-Drop support:
- Drag nodes inside one tree, i.e. re-order.
- Drag nodes between trees.
- Drop standard jQuery UI draggables on tree nodes.
- Drop tree nodes on standard jQuery UI droppables.
In addition to jQuery, jQuery UI, and Fancytree, include jquery.fancytree.dnd.js
:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js" type="text/javascript"></script>
<link href="skin-win8/ui.fancytree.css" rel="stylesheet" type="text/css">
<script src="js/jquery.fancytree.js" type="text/javascript"></script>
<script src="js/jquery.fancytree.dnd.js" type="text/javascript"></script>
Enable dnd
extension and pass options:
$("#tree").fancytree({
extensions: ["dnd"],
dnd: {
// Available options with their default:
autoExpandMS: 1000, // Expand nodes after n milliseconds of hovering.
draggable: null, // Additional options passed to jQuery draggable
droppable: null, // Additional options passed to jQuery droppable
preventRecursiveMoves: true, // Prevent dropping nodes on own descendants
preventVoidMoves: true, // Prevent dropping nodes 'before self', etc.
// Events that make tree nodes draggable
dragStart: null, // Callback(sourceNode, data), return true, to enable dnd
dragStop: null, // Callback(sourceNode, data)
// Events that make tree nodes accept draggables
dragEnter: null, // Callback(targetNode, data)
dragOver: null, // Callback(targetNode, data)
dragDrop: null, // Callback(targetNode, data)
dragLeave: null // Callback(targetNode, data)
},
[...]
});
All API function are passed a data
object:
{
node: ...,
tree: ...,
options: ...,
originalEvent: ...,
otherNode: ...,
ui: ...,
hitMode: ...,
draggable: ...,
}
$("#tree").fancytree({
extensions: ["dnd"],
// .. other options...
dnd: {
preventVoidMoves: true, // Prevent dropping nodes 'before self', etc.
preventRecursiveMoves: true, // Prevent dropping nodes on own descendants
autoExpandMS: 400,
dragStart: function(node, data) {
// This function MUST be defined to enable dragging for the tree.
// Return false to cancel dragging of node.
// if( data.originalEvent.shiftKey ) ...
return true;
},
dragEnter: function(node, data) {
/* data.otherNode may be null for non-fancytree droppables.
* Return false to disallow dropping on node. In this case
* dragOver and dragLeave are not called.
* Return 'over', 'before, or 'after' to force a hitMode.
* Return ['before', 'after'] to restrict available hitModes.
* Any other return value will calc the hitMode from the cursor position.
*/
// Prevent dropping a parent below another parent (only sort
// nodes under the same parent):
// if(node.parent !== data.otherNode.parent){
// return false;
// }
// Don't allow dropping *over* a node (would create a child). Just
// allow changing the order:
// return ["before", "after"];
// Accept everything:
return true;
},
dragOver: function(node, data) {
},
dragLeave: function(node, data) {
},
dragStop: function(node, data) {
},
dragDrop: function(node, data) {
// This function MUST be defined to enable dropping of items on the tree.
// hitMode is 'before', 'after', or 'over'.
// We could for example move the source to the new target:
data.otherNode.moveTo(node, data.hitMode);
}
draggable: {
zIndex: 1000,
scroll: false
}
}
});
When a node is copied from a the same tree, we should generate a new key, or let the tree generate one.
dragDrop: function(node, data) {
newNode = data.otherNode.copyTo(node, data.hitMode, function(n){
n.title = "Copy of " + n.title;
n.key = null; // make sure, a new key is generated
});
}
The Fancytree dnd extension enables the standard jQuery Draggable options for auto scrolling:
scroll: true,
scrollSpeed: 7,
scrollSensitivity: 10,
but depending on the the surrounding markup, it may also be necessary to add some CSS to give the Fancytree container 'position: relative':
#tree .fancytree-container {
position: relative;
}
Dropping a node onto a lazy folder may not work as expected: The item that is
dragged will appear in that folder but it stops the node from performing the
ajax request.
This is 'works as designed': lazy folders only generate an ajax reques, if
the children
property is null or undefined in order to prevent lazy-loading a
second time.
We could however expand the node before adding the dropped node:
dragDrop: function(node, data) {
node.setExpanded(true).always(function(){
// Wait until expand finished, then add the additional child
data.otherNode.moveTo(node, data.hitMode);
});
}
(Another pattern could be: issue an ajax request to notify the server about the new node. Then reload the branch.)
<p class="draggable">
Draggable.
</p>
Connect the draggable to the tree:
$(".draggable").draggable({
revert: true, //"invalid",
cursorAt: { top: -5, left: -5 },
connectToFancytree: true, // let Fancytree accept drag events
});
and handle drop events:
$("#tree").fancytree({
extensions: ["dnd"],
...
dnd: {
...
dragEnter: function(node, data) {
return true;
},
dragDrop: function(node, data) {
if( !data.otherNode ){
// It's a non-tree draggable
alert("dropped " + $(data.draggable.element).text());
return;
}
data.otherNode.moveTo(node, data.hitMode);
}
}
});
Assuming we have a stabdard droppable
<p class="droppable">
Droppable.
</p>
and the tree has the dnd extension enabled:
$("#tree").fancytree({
extensions: ["dnd"],
...
dnd: {
...
dragStart: function(node, data) {
return true;
},
...
}
});
Nodes can be dropped to the standard droppables, and we can access the original source node like so::
$(".droppable").droppable({
drop: function(event, ui){
var sourceNode = $(ui.helper).data("ftSourceNode");
alert("Dropped source node " + sourceNode);
}
});
Documentation Home - Project Page - Copyright (c) 2008-2022, Martin Wendt (https://wwWendt.de)