dhtmlxTree setDragHandler

I’ve set up setDragHandler(tondrag) - function tondrag(id,newparent, idbefore)



I can drag-n-drop at the same level to a different parent (newwparent) but only if it has a child :-

1) If it has a child then parameter newparent= the new parent id.

2) but if there is no child then parameter newparent is the “parent id” of newparent!



I therefore do not know where to insert the moved node - I need to know the real parent id as I am also doing the same on a server ie reflecting the tree on the server - directory tree. How can I obtain the true parent id?



Also idbefore (see above) is in fact the id after the insert point and not as comment says in source: @eventparam: if node droped as sibling then contain id of item before whitch source node will be inserted.



1) same parent - mv P1-2 above P1-1

P1

-1

-2

can become

P1

-2

-1



2) different parent with child - move P2-2 below P1-2

P1

-1

P2

-2

-3

can become

P1

-1

-2

P2

-3



3) different parent no child - move P2-1 to P1 fails as the parent parameter contains R1 and not P1

R1

-P1

-P2

–1

–2



I think I can solve this uising

if new parent parameter = parent of target parent

var nextindex= getIndexById(idbefore);

var realparent= getItemIdByIndex(newparent,nextindex-1);

but I also need to check for null ie if target parent is last then next parent will not exist ie null



Which drag-behavior you are using?

If you need to drop item only as child of something - you can use

tree.setDragBehavior(“child”)

Now the onDrag event will provide only ID of item, on which source item was dropped, and you need not include any other parameters in calculations.

tree.setDragBehavior(“child”)
tree.attachEvent(“onDrag”,function(sid,tid){
if (this._allow_next_call) return true; //allow inner calls
this._allow_next_call = true;

if (this.getSubItems(tid)) //item has child
this.moveItem(sid,“child”,tid);
else
this.moveItem(sid,“item_sibling”,tid); //if there is no child - drop on the same level

this._allow_next_call = false;
return false; //block default drag processing
})



I’m using tree.setDragBehavior(“sibling”)

Examples to illustrate required use

1) reorder node items that are at the same level eg authors
eg move StephenKing above JaneAusten
Its useful to see the horizonal line that appears when moving -
I dont see this using tree.setDragBehavior(“child”) as I assume
you are expected to drop eg StephenKing into Horror parent folder icon

2) move a node item to another parent
eg move JaneAusten from parent Fiction to parent Classics

Also then want to do copy instead of move

Hello,
there is also complex mode tree.setDragBehavior(“complex”) It allows  to  combine  both  “sibling”  and “child”  modes.
To enable copying:
 tree.enableMercyDrag(true)

I’ve tried both tree.setDragBehavior(“complex”)
and they do not work for the specific problem I’ve already described,
take the following:-

–books
----classics
----horror
-------frankenstein

I want to move “frankenstein” as follows

–books

----classics

-------frankenstein

----horror

but this is not possible as my event handler function tondrag(id, newparent, idbefore)
does not give the target parent, it only supplies the target parents parent as follows

id=/books/horror/frankenstein
newparent=/books <<<<<<<<< I need /books/classics
idbefore=/books/horror/ <<<<<<this is the ‘parent’ after the insertion point not before

but if I have start with


–books

----classics
-------dracula

----horror

-------frankenstein


I can move as follows



–books

----classics
-------dracula

-------frankenstein

----horror


because my hander function tondrag(id, newparent, idbefore) supplies the target parent



id=/books/classics/frankenstein

newparent=/books/horror

idbefore=/books/classics/dracula


Remember I’m duplicating the tree layout and item order on my server.
So I do the move both in the tree and on the server ie once the drag-n-drop
takes place a reload from the server will leave the tree as is following
the drag-n-drop.

Sorry above should have read as below ie frankenstein moved to above dracula

"but if I have start with


–books

----classics
-------dracula

----horror

-------frankenstein


I can move as follows



–books

----classics

-------frankenstein
-------dracula
----horror

Ok I see whats wrong, the reason I see a failure is that dhtmlxTree sees
my horizontal drag line as applying to parents ie
1. if books exist then the line applies to books
2. if no books exist in a category like classics then the line applies to categories and not books

For 2 to get the same behaviour as 1 you need to drag the cursor to the category icon and then drop :frowning:

Its annoying as I only want to allow drag-n-drop at the same level as per my examples.

Take what works - we have
–classics
<-----------------drag bar-------------->
----dracula
–horror
----frankenstein  <<< selected

then visually drag-n-drop is seen with a horizontal drag bar ie
release key and frankenstein  is dropped above dracula as a book


–classics

<-----------------drag bar-------------->

–horror

----frankenstein  <<< selected


again visually drag-n-drop is seen with a horizontal drag bar but

release the key and frankenstein  is dropped above horror but
not as a book instead as a new category

–classics

–frankenstein
–horror




Question is then how do I solve this?

I need to use the horizontal bar for ordering nodes.

[A] Tell the user to only use the horizontal bar when another book exists and
if not use the category icon? Do this via a popup? Not good.
A user would expect the same behaviour.

[B] still use the bar when the category is empty ie and in my code find the new
parent (id) into which I am dropping my book/

As stated my event handler function tondrag(id, newparent, idbefore)
does not give the target parent, it only supplies the target parents parent as follows

id=/books/horror/frankenstein
newparent=/books <<<<<<<<< I need /books/classics
idbefore=/books/horror/ <<<<<<this is the ‘parent’ after the insertion point not before

whereas I need
newparent=/books/classics

and as I stated in the first posting: maybe I can use

idbefore=/books/horror/ <<<<<<this is the ‘parent’ after the insertion point

var nextindex= getIndexById(idbefore);

var realparent= getItemIdByIndex(newparent,nextindex-1);


but if target parent is last then next parent will not exist ie
idbefore=null


in which case maybe I get all the subitems for /books and the last subitem is the new parent.




Working sample was sent by email. ( the info received in onDrag event is really not suitable for desired use-case - but it can be transformed to necessary one )


tree.attachEvent(“onDrag”,function(sid,tid,bid){
if (this._allow_next_call) return true; //allow inner calls
this._allow_next_call = true;

//get previous item ID
if (!bid){
if (tree.hasChildren(tid)) //last child
bid = tree.getItemIdByIndex(tid,tree.hasChildren(tid)-1)
else
bid = tid; //has not childs - drop on parent
} else {
var ind = tree.getIndexById(bid);
if (ind) //if has previous item
bid = tree.getItemIdByIndex(tid,ind-1);
else
bid = tid; //else drop on parent
}

if (bid && tree.hasChildren(bid))
tree.moveItem(sid,“item_child”,bid); //drop if item already has childs
else
tree.moveItem(sid,“item_sibling_next”,bid);

this._allow_next_call = false;
return false; //block default drag processing
})

it only supplies the target parents parent as follows
targetID - ID of parent to the item, which is below drag-line-marker ( parent of below )
beforeID - ID of item, which is below drag-line-marker

if drag item placed after last child on level - targetID will point to the parent of above item, and beforeID will have null value.

Thanks for the quick response.

I pasted the handler into my code, renaming “tree” to my tree but
its not working as expected eg if I drag-n-drop dracula to under classics

-books
–classics
–horror
----dracula

results in

–classics

–dracula
–horror


(and same for moving from classics to horror)

Problem is classics has no children and move ‘sibling’ is used
if (bid && tree.hasChildren(bid))
  tree.moveItem(sid,“item_child”,bid); //drop if item already has childs
else
   tree.moveItem(sid,“item_sibling_next”,bid);

If  I amend and use tree.moveItem(sid,“item_child”,bid);

then it works except in the drop handler where I call
s=atree.getSubItems(tid)
Although the handler parameter tid is correct == books/classics
the call returns with s= “books/horror/dracula” and so a count of 1 not 0.


I think my real problem lies with onDrop
"Event raised after drag-and-drop processed. Event also raised while programmatic moving nodes."
tree.getSubItems(tid) is coming back with incorrect data

If dracula has moved from books/horror to books/classics
then ondrop has tid=books/classics and I’d expected
tree.getSubItems(tid)  to return with books/classics/dracula
but instead tree.getSubItems(tid) returns with books/horror/dracula
which is wrong: onDrop is meant to be after the move but I assume
books/horror/dracula is a symbolic link ie the move is incomplete at this point

On second thoughts the problem lies with me and thinking in terms of a mv dir
ie I thought because dracula moved from horror/ to classics/ in the tree then
the itemId will change to reflect that but why should it. Its up to me to
rename it : so tree.getSubItems(tid) is ok.


I thought because dracula moved from horror/ to classics/ in the tree then
>>the itemId will change to reflect that but why should it.
Yep, the IDs are preserved as is.
Technically they can be changed by using tree.changeItemId - it can be used after moveItem to set new ID, according to the scheme, used in your case

>>I think my real problem lies with onDrop
If you are using onDrag with custom logic - it better place your custom logic after calling moveItem with custom parameters , because here all necessary ids already known