-
-
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.
focusOnClick: false, // Focus, although draggable cancels mousedown event (#270)
// 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: {
autoExpandMS: 400,
draggable: { // modify default jQuery draggable options
zIndex: 1000,
scroll: false,
revert: "invalid"
},
preventVoidMoves: true, // Prevent dropping nodes 'before self', etc.
preventRecursiveMoves: true, // Prevent dropping nodes on own descendants
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);
}
}
});
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
});
}
By default, jQuery Draggable options for auto scrolling are enabled for the tree:
scroll: true,
scrollSpeed: 7,
scrollSensitivity: 10,
Scrolling also requires that the Fancytree container has 'position: relative'. Starting with v2.1 this is added to common CSS:
ul.fancytree-container {
position: relative;
}
While this may be handy when nodes should be dragged inside one large tree,
scrolling may be undesirable when nodes are dragged to outside targets.
In order to prevent scrolling inside the tree container, this can be turned
off for draggable and container:
$("#tree").fancytree({
...
dnd: {
...
draggable: { // modify default jQuery draggable options
scroll: false
},
and custom CSS
ul.fancytree-container {
position: inherit;
}
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);
}
});
Fancytree uses tthe standard jQuery UI draggable plugin to implement drag'n'drop. `draggable`` however prevents mouse clicks from setting the focus (so you can drag an object without activating it).
In combination with keyboard navigation, this can prevent setting the focus
to the tree container, so that keyboard input is not delivered to the tree.
Use the dnd.focusOnClick: true
option in this case:
$("#tree").fancytree({
dnd: {
focusOnClick: false, // Focus, although draggable cancels mousedown event (#270)
...
}
[...]
});
Documentation Home - Project Page - Copyright (c) 2008-2022, Martin Wendt (https://wwWendt.de)