The TableDnD jQuery plugin allows the user to reorder rows within a table, for example if they represent an ordered list (tasks by priority for example). Individual rows can be marked as non-draggable and/or non-droppable (so other rows can’t be dropped onto them). Rows can have as many cells as necessary and the cells can contain form elements.
This is a great plugin at all, but needs some attention in case of usability. The default behavior of the plugin is passing over the drag-n-drop “ghosting” effect. (You can see an example here: http://www.gimiti.com/kltan/demo/jTree/)
It is difficult to make the ghosting work with this plugin but I found a very simple solution to do it. I used a small amount of CSS a Javascript code to reach a better usability behavior when a user drag-n-drop a table row.
The main concept was to mimic the ghosting effect in my project.
I used the following CSS lines.
/* This declarations makes a draghandle icon (a small crosshair) visible in the first cell of a table row */
td.dragHandle {padding-left:17px;}
td.showDragHandle {padding-left:17px; background:url(arrow_all_thin.png) no-repeat center center; cursor: move;}
/* The followings will format the entire table row when a user is dragging it */
tr.myDragClass td {background-color: #fff; padding-left:2px;} /* change the background color all of the table cells in the row to white */
tr.myDragClass td a {color: #aaa;} /* change the text color to grey, or just lighter - note: I'm using links in the TDs */
tr.myDragClass td img, tr.myDragClass td .taskDelete, tr.myDragClass td.napok div {display:none;} /* Do not display any of the images and other informations in the cells. Just show the most important information for dragging and dropping. Other information, icons, etc may confuse the user. */
tr.myDragClass td span, tr.myDragClass td span span {padding:0;} /* Pull the information closer to the drag icon */
After that formatting I played with the plugin itself. I set up it on the following way.
var oldSibling;
$("#todoList").tableDnD({
onDragClass: "myDragClass",
onDragStart: function(table, cell) {
// Saving the row under the dragged one
oldSibling=$(cell).parents("tr").next();
//Set the CSS class immediately to show the "ghosting" like effect when the user clicks on the row
$(cell).parents("tr").addClass("myDragClass");
},
onDrop: function(table, row) {
var aHtml=$("a", row).html();
var f=$.getUrlVar('f');
if(confirm("\nAre you sure to move \""+aHtml+"\" task?")) {
// Here comes the AJAX call
$("#cover").show();
$("#ajaxMessage").show();
document.getElementById("cover").style.width="100%";
document.getElementById("cover").style.height=docHeight()+"px";
$("#bigCal").load("setTask.php?f="+f+"&orig="+row.title+"&"+$.tableDnD.serializeT(), function(){
$("#cover").hide();
$("#ajaxMessage").fadeOut(200);
});
}
else {
//If the user Cancel the moving we have to take back the row to the original place
$(row).insertBefore(oldSibling);
}
},
dragHandle: "dragHandle"
});
As you can see I made the drag-n-drop cancel functionality also.
TODO: Handle the oldSibling if the moved row was the last row in the table.
Do you have any thoughts or question?
