Using the dragged node as the avatar
by Yoav Rubin

When doing drag and drop, the avatar is the element that is displayed on the screen that represents the dragged element. Usually it is either a duplicate of the dragged element or something that mimics it (in cases the dragged element is a heavy dom element such as a well populated table). While this happens, the dragged element remains in its original place.

This behavior has some usability drawbacks. The first is that the user does not see the element that is dragged actually moved on the screen (and thus may not know if the right element is being dragged). The second is that the user does not see how the area from which the element was dragged from would look after the completion of the drag and drop operation.
Nevertheless, this is the approach that Dojo uses.

Here I’ll show you how to go under Dojo.dnd’s radar and use the real dragged node as the avatar, while leaving a marker back where the element was dragged from.

This approach has the usability benefits that the real data (the dragged node) is presented at the place where the user is focusing, while at the place where the user has only peripheral focus, only a marker (or an avatar) remains.

We’ll start in the creator function, when its hint parameter equals to avatar, we’ll do the following:

// first we'll get the dragged element from the dnd managervar draggedNode = dojo.dnd.manager().nodes[0];// we'll wrap the dragged element with a divvar dv = document.createElement("div"); // we'll keep some info regarding the whereabouts of the dragged node:// its next sibling and parent, for easy restoration later, assumption: there is an id for// the next sibling, if not you'll need to allocate onedraggedNode.nxtId = draggedNode.nextSibling.id;draggedNode.theParent = draggedNode.parentNode;// we'll need this flag later on to allow only the returing to the initial position not to be called// more then oncedraggedNode.needToReturn = true;// disconnecting the dragged node from the parentdraggedNode.parentNode.removeChild(draggedNode);// connecting the dragged node to its wrapperdv.appendChild(draggedNode);// creating a marker on the place from which the dragged node was taken from// change the contents of this function to create any kind of marker, which may as well be// a simplified display of the actual dragged nodevar marker= function makeMarker(){  document.createElement("div");  marker.innerHTML = "The element was dragged from here";}();draggedNode.theParent.insertBefore(marker,dojo.byId(draggedNode.nxtId));draggedNode.theMarker = marker;// the data and type were handled before in the creator functionreturn {node: dv, data: data, type: "your dnd type"};

The next thing that needs to be done is to return the dragged element back to its original place before Dojo’s dnd system would notice it, and the system notices it on two occasions - when dropping and when canceling the dnd operation, therefore we’ll need to override Dojo’s Source object in these exact functions, but first lets define this function:

// this function is the one that is responsible for returning the dragged node to the right place, and// during that process remove the markerreturnDraggedItemToPosition: function(draggedNode){// taking the dragged node out of the avatar, inserting it back to its original place and// allowing the dnd mechanism to do it job as if nothing happened  if(draggedNode.needToReturn == true){    draggedNode.theMarker.parentNode.removeChild(draggedNode.marker);    draggedNode.parentNode.removeChild(draggedNode); // disconnecting from the avatar    draggedNode.theParent.insertBefore(draggedNode,dojo.byId(draggedNode.nxtId)); // re-inserting    // marking the returning of the node as complete,    // as this function will be revisited later at the end of the dnd process    draggedNode.needToReturn = false;  }}

Now we’ll override the onDrop and onDndCancel functions

// assuming that our implementation is called MyNS.MySourceonDrop: function(source, nodes, copy){  this.returnDraggedItemToPosition(nodes[0]);  MyNS.MySource.superclass.onDrop.apply(this,arguments);},onDndCancel: function(){  var manager = dojo.dnd.manager();  this.returnDraggedItemToPosition(manager.nodes[0]);  MyNS.MySource.superclass.onDndCancel.apply(this,arguments);}

And at this point, all that is left is to go and DnD things around

Tags: ,

This entry was posted on Monday, July 6th, 2009 at 7:15 pm and is filed under Dojo Cookies. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

2 Responses to “Using the dragged node as the avatar”

  1. Marton Kenyeres Says:

    Yummy cookie :)

    Is there a reason why the former nextSibling should be stored and looked up later via the id as opposed to storing a direct reference to the node?

  2. Yoav Rubin Says:

    Thanks :-)

    I didn’t investigate much into it, but there were scenarios when the direct reference didn’t work, so there was a need to keep it in another way

Leave a Reply

You must be logged in to post a comment.