Using Dnd feature in tree, you can experience what happens if you drag a parent node and drop it on any of its child nodes:
the parent node and the child node suddenly disappears from the view!
here is what happens in dijit/tests/tree/test_Tree_DnD.html:
treePic.jpg
The explanation simply is we just created an isolated subtree:
"Fruits" node was referencing "Citrus" node, but when "Fruits" was dropped to "Citrus", there was no more node referencing "Citrus". So tree updated itself showing neither "Fruits" neither "Citrus", because there wasn't a path to "Citrus" and "Fruits".
I think allowing or disallowing users to drop a node to one of its child could be a feature in Tree Widget.
My actual solution to avoid users dropping a node to its child is (this code works with multiple nodes drag and drop, and with any relationship degree):
var actualDraggedNodes = [];
/*
*
*/
function checkPaternity(source, draggedNodes, newParentNode)
{
// parents is newParentNode to Root path described as a list of nodes
var parents = [];
parents.push(newParentNode);
var parentNode = newParentNode;
while (parentNode != source.tree.rootNode)
{
parentNode = parentNode.getParent();
parents.push(parentNode);
}
// for each parent check if at least one is dropped to its child
for(var i=0; i<parents.length; i++)
{
var position = draggedNodes.indexOf(parents[i]);
if (position >= 0)
{
return false;
}
}
return true;
};
/*
*
*/
function dndAccept(source,nodes)
{
// save dragged nodes to global var
actualDraggedNodes = nodes;
if (source.tree.id=="folderT"){
return true;
}
return false;
};
/*
*
*/
function itemTreeCheckItemAcceptance(node,source)
{
var draggedNodes = [];
// get nodes from global var array
for(var i=0; i<actualDraggedNodes.length; i++)
{
var draggedNode = dijit.getEnclosingWidget(actualDraggedNodes[i]);
draggedNodes.push(draggedNode);
}
return checkPaternity(source, draggedNodes, dijit.getEnclosingWidget(node));
};
</script>
...
<div dojoType="dijit.Tree" id="myTree" jsId="myTree"
model="myTreeModel"
dndController="dijit._tree.dndSource" checkAcceptance="dndAccept"
checkItemAcceptance="itemTreeCheckItemAcceptance"
onDndDrop="dndDrop"
root="{ name: 'World' }">
Hope it can help! :)

looks good
Might be able to consider this a manifestation of the bug that Tree doesn't support items w/multiple parents... not sure. Although supporting cycles is weirder than supporting a DAG. Probably best to just prohibit it like you did.
BTW instead of
// get nodes from global var array
for(var i=0; i<actualDraggedNodes.length; i++)
{
var draggedNode = dijit.getEnclosingWidget(actualDraggedNodes[i]);
draggedNodes.push(draggedNode);
}
You should be able to do something like
Also, concerning:
for(var i=0; i<parents.length; i++)
{
var position = draggedNodes.indexOf(parents[i]);
if (position >= 0)
{
return false;
}
}
return true;
Probably you didn't try this on IE, the myArray.indexOf() doesn't work there. That's why dojo has an indexOf() function. You could use it and reduce the code w/something like:
It might also make sense to be using hashes rather than arrays... if you have a structure like
Then to check if myHash contains zaz you just do if(myHash["zaz"]);
=========
Bill Keese
Project Lead (aka BDFL) of Dijit