Content of HTML table cells can be dragged to another cell or another table. It isn’t difficult to define onMouseMove handler and change top / left element styles to move the object. In case with tables, you will have to determine somehow target cell. Attaching onMouseOver handler on TD elements will not work, because browser doesn’t fire events to the elements below the dragged object.
Anyway, after taking care of the current scroll position and calculating TD positions, REDIPS.drag should work in recent major browsers like Google Chrome, Firefox, Safari, Internet Explorer, Opera and mobile devices as well. Click on image below, will open live demo where you can drag green, blue or orange bordered DIV elements, change properties (radio button and check-boxes) and click on “Save” button.
Download latest version redips2.tar.gz

REDIPS.drag example01
In this example “Save” button will scan table content, create query string and send to PHP page. Demo shows how to collect content and accept parameters on the server side. More about accepting parameters you can read at Reading multiple parameters in PHP. “Clone” elements (orange in this demo) will be duplicated first because of “redips-clone” keyword contained in class name. If you drop object on cell named “Trash”, object will be deleted from the table (with or without confirmation). Library has built in autoscroll and option to forbid landing to non empty cells or cells named with class “redips-mark”. Table can contain rowspan / colspan TDs and different background color for every cell.
Here are minimal steps to enable content dragging in table:
- put <script type=”text/javascript” src=”redips-drag-min.js”></script> to the head section
- initialize REDIPS.drag library: <body onload=”REDIPS.drag.init()”>
- place table(s) inside <div id=”redips-drag”> to enable content dragging
- place <div class=”redips-drag”>Hello World</div> to the table cell
Other features of REDIPS.drag library:
- methods and data structure are defined in namespace (easier integration with other JS frameworks)
- all JavaScript code is checked with ESLint
- REDIPS.drag documentation generated with JsDoc Toolkit
- drag and drop table rows
- movable DIV element can contain other HTML code (images, forms, tables …)
- forbidding or allowing TDs marked with class name “redips-mark”
- option to define exceptions and allow dropping certain DIV elements to the marked cell
- option to define single content cell on the table declared with “multiple” drop option
- cloning
- for unlimited cloning add “redips-clone” class name to the DIV object
<div class=”redips-drag redips-clone”>Hello World</div> - to limit cloning and transform last object to the ordinary movable object add ‘climit1_X’ class name
<div class=”redips-drag redips-clone climit1_4″>Hello World</div> - to limit cloning and transform last object to immovable object add ‘climit2_X’ class name
<div class=”redips-drag redips-clone climit2_4″>Hello World</div> - where X is integer and defines number of cloned elements (in previous examples, each climit will allow only 4 cloned elements)
- for unlimited cloning add “redips-clone” class name to the DIV object
- unlimited nested tables support
- dropping objects only to empty cells
- switch cell content
- switching cell content continuously
- overwrite TD content with dropped element
- shift table content
- table cell with “redips-trash” class name becomes trashcan
- enabled handlers to place custom code on events: changed, clicked, cloned, clonedDropped, clonedEnd1, clonedEnd2, dblClicked, deleted, dropped, droppedBefore, finish, moved, notCloned, notMoved, shiftOverflow, relocateBefore, relocateAfter, relocateEnd, rowChanged, rowClicked, rowCloned, rowDeleted, rowDropped, rowDroppedBefore, rowDroppedSource, rowMoved, rowNotCloned, rowNotMoved, rowUndeleted, switched and undeleted
- deleting cloned DIV if the cloned DIV is dragged outside of any table
- enabling / disabling dragging
- animation (move element/row to the destination cell/row)
- added support for touch devices (touchstart, touchmove, touchend)
How REDIPS.drag works?
Script will search for DIV elements (with class name “redips-drag”) inside tables closed in <div id=”redips-drag”> and attach onMouseDown event handler. When user clicks with left mouse button on DIV element, onMouseMove and onMouseUp handlers will be attached to the document level.
While dragging DIV element, script changes its “left” and “top” styles. This is function of the onMouseMove handler. When user releases left mouse button, onMouseUp event handler will unlink onMouseMove and onMouseUp event handlers. This way, browser will listen and process mousemove events only when DIV element is dragged.
As I mentioned, onMouseDown is defined on the elements you want to drag. Elements beneath the dragged object will not be able to catch onMouseOver event. Why? Because you are dragging object and that object only can catch the onMouseOver event.
So, to detect destination table cells, script calculates all cell coordinates (with scroll page offset) and store them to the array. Array is searched inside onMouseMove handler and after left mouse button is released, DIV will drop to the current (highlighted) table cell.
In redips2.tar.gz package you will find many examples including example of how to save/recall table using PHP and MySQL. Package also contains and redips-drag-min.js – a compressed version of REDIPS.drag library (compressed with Google Closure Compiler).
Happy dragging and dropping!
Great JavaScript tool. Thanks for this.
Darko,
what a great piece of code! Thanks a lot for your work. I am struggeling with the following:
Basically I need more than just 2 tables to drag and drop. Besides the tables are very large and I want to toggle their visibility. The tables I do not need I want to sort of collapse (display:block vs display:none). Unfortunately when I make one of the tables reappear their is a sort of offset. Any idea about that?
Thanks in advance for sharing your thoughts.
Michael
Found a bug where if I have div tags within the div with class=drag and I try to switch table cells there is an error. The error occurs when you try to drag a cell into another cell that has nested div tags. The fix was not too hard – it seems to work without breaking anything else.
Modified the code in drag.js starting at line 357:
else if (REDIPS.drag.drop_option === ‘switch’) {
// remove dragged element from DOM (source cell) – node still exists in memory
obj.parentNode.removeChild(obj);
// move object from the destination to the source cell
target_elements = target_cell.getElementsByTagName(‘DIV’);
target_elements_length = target_elements.length;
for (i = 0; i < target_elements_length; i++) {
// source_cell is defined in onmouseup
if (target_elements[0] != null) { //fixes issue with nested DIVS
source_cell.appendChild(target_elements[0]); // '0', not 'i' because NodeList objects in the DOM are live
}
}
Added the if statement to make sure the target_elements object is not null. Please let me know if anyone sees a better way to handling this.
Thanks so much dbunic for this script – great job!
What a fantastic library, thanks very much for this. I’ve just been playing around with your example 6, and wondered whether it was possible to define an ‘only’ class for all clones of a div. With your example at the if I made div a infinitely cloneable I would have to code
rd.only.div.ac0 = ‘last’;
rd.only.div.ac1 = ‘last’;
rd.only.div.ac2 = ‘last’;
rd.only.div.ac4 = ‘last’;
… forever in order to get the functionality I want. Is there a way to get around this? Many thanks.
I have the same issue.
I’ve tried defining a variable that should extract all id’s that start with a specific keyword but with no success :(
Here is my code:
var gk = $(“div[id^=’gk_’]”);
rd.only.div.gk = ‘last’;
I was hoping that all the divs that had the ids like gk_1, gk_2 etc. would be defined as ‘last’.
@chai – I haven’t any experience with combining “freeze header” and my drag-n-drop library. I know that you posted question more than a month ago, but can you specify what was the problem? If “freeze header” lib fixes div position and emulates table header with DIV elements, then there shouldn’t be a problem. Anyway, it would be easier to help if you can show the problematic example.
@Pete – If I understood well, you want to allow only different content in table cells of right table. Unfortunately, lib has the following possibilities: forbid dropping to the cell, control only certain content to the cell, allow single / multiple content and overwrite content. Currently there is no option to forbid dropping the same content to the table cell. But, you can place custom JS code in myhandler_dropped handler to test if content already exists in target table cell.
And you asked about placing table cell content horizontally. Lib simply adds DIV element to the table cell so you can modify CSS to achieve placing DIV elements side by side instead of vertical positioning.
@SP – Additional action like adding table rows and columns can be done inside myhandler_dropped handler. You only have to place JS code which will be executed after content dropping. Please see example of how to add table rows / columns dynamically on my post: Adding table rows & columns in JavaScript
Save button in this demo only shows prepared query string. Please try to find save() function In JS code of example1 and you will see how to call save_content() function from the drag-n-drop library. Instead of “window.open” you can specify “window.location.href” to point browser to your page.
If you want to place tables side by side, please use DIVs and CSS like in example3. Drag-n-drop library uses tables to define dropping positions.
@Bill – Yes, it’s possible to make objects infinitely clone-able. Please find the 1025 line in drag.js:
// remove clone from the class name of the new object
obj_new.className = obj_new.className.replace(‘clone’, ”);
If you comment this line, cloned object will stay clone-able.
Drag-n-drop library now has new drop option: “overwrite”. If you specify “overwrite”:
REDIPS.drag.drop_option = ‘overwrite’;
… old content will be overwritten with the dropped content.
@Sandy – Drag-n-drop lib is table cell oriented, so spanning across more rows or columns are not possible. But after DIV element is dropped to the table cell, you can clone element to the other table cells like in example3 (if checkbox in upper left corner is checked). Please try.
Hi, thanks for putting this online its fantastic. I have just been playing around with example 1. I am new to all this and wondered if there was a way to set it so ‘switch content’ is not turned on as a button but programmed to be permanently the case.
It’s this bit below I would like to just happen without the user having to click a button but I am a little stuck!!
Thank you
Jonathan
@Michael – I suppose you should run REDIPS.drag.init(); after table is shown. Initialization will scan table cell positions and offset should fit properly.
@Doony – Your code correction is applied and my lib is better than before. Thank you very much!
@hgbreton & Sorin Haidau – Example7 is modified and now every cloned element of element A or B can be placed to the last row no matter how many elements will be cloned. I used myhandler_cloned() event handler … Here is the code:
// after element is cloned define dropping for last row – only for clones of element A or element B
rd.myhandler_cloned = function () {
// define variables
var cloned_id = rd.obj.id; // cloned id
// if cloned if begins with a or b define dropping only for last row
if (cloned_id.substr(0, 1) === ‘a’ || cloned_id.substr(0, 1) === ‘b’) {
rd.only.div[cloned_id] = ‘last’;
}
}
This two line can be ignored – just leave them out.
rd.only.div.ac0 = ‘last’;
rd.only.div.bc0 = ‘last’;
@Jonathan – If you want the “switch” mode behavior, just define drop option after initialization. Here is how:
// initialization
REDIPS.drag.init();
// switch mode
REDIPS.drag.drop_option = ‘switch’;
Hi, excellent tool, but I have a bit of a problem. In example 5 with the scrolling DIV containers if you set the right DIV to float: left; then drap/drop stops working. My requirements are 3 tables, the left and right need to be scrollable and the centre table fixed size. If I use floats to position the tables then drag/drop doesn’t work. Any ideas? You help is much appreciated.
Hi there,
Is it also possible to drag and drop a row between two rows? For example:
http://developer.yahoo.com/yui/examples/datatable/dt_ddrows_clean.html
How can that be applied in the www_redips_net/index.html example index page?
Thanks for the great work!
Rolf
HI,
Is there any one can enhance the Lib to have the re-order functionality between rows and also columns as well, i wonder if someone can do that. Any feedback ?
Regards
Tamer
@MattI – The problem was due to drag DIV. Drag DIV should encapsulate scrollable and fixed DIV containers. Anyway, examples are modified and you will find two examples with scrollable DIV containers. Cheers!
@Rolf – Sorry, but drag.js library is table cell oriented. Dragging table rows are not supported yet …
@Tamer – Currently, re-order functionality is out of the scope of drag.js lib. I will try to enhance lib with simple row/column shifting in the upcoming period … Patience please ;)
Dear All,
I am trying to use the drag and drop feature in my one site. I am using this in the scrollable div but I am facing a really surprising problem. It gives me error of tables[table_source] undefined when I try to drag and drop content of one table into another but when I move the scroller of any of my div then it starts working but without moving scrolling it is not working. Please help me out.
Any help will be really appreciated. Thanks to you people in advance.
@Gautam – It will be much easier to resolve the problem if you can send me a link to see problematic example. Thanks for using my Drag and Drop library.
Dear Dbunic,
Thanks a lot for your quick response. This is the demo URL which will tell you what exactly I want to do with this drag and drop functioanlity.
http://tsprojects.net/demo/dragdrop/#
When you will open the URL then you will get a link drag and drop. When you will click that link then it will open a page in lightbox. When you will try to drag and drop anything then it will show error but when you just move a slider of the overlay div or the window then it will start working perfectly fine. Please guide me what is the problem here.
“tables[table_source] is undefined” this is the error which I am getting.
Hope I am clear enough to describe about my problem. Any help will really be appreciated.
Thanks again
Gautam
@Gautam – Very nice page. Just one question. Did you include somewhere in your code initialization of REDIPS.drag library? I tried to find the code like:
window.onload = function () {
// initialization
REDIPS.drag.init();
}
but without luck (or I have to search harder) :)
Anyway, If you have some other initialization routine, just place REDIPS.drag.init(); line inside …
Hi there,
Actually the initialization code is written in the light box page. When you click on the drag and drop link then a page open in the light box and all code is written in that light box. I guess that I am facing problem because I am using this drag and drop feature in light box. But the trick is that how I should Initialize the drag and drop in light box.
If you want to see the code where initialization has been done then you need to see the view source of the page which opens in lightbox.
Thanks in advance
OK, I found it. Instead of initialization in 33.html please try to modify open_model() function in projects.js to look like this:
function open_model( uri ){
$().jOverlay({
url:uri,
imgLoading : ‘http://focusproject.com/img/ajax-loader.gif’,
bgClickToClose : false,
closeOnEsc:false,
autoHide : false,
success: function(){REDIPS.drag.init();}
});
}
Actually I just added success handler to start initialization after 33.html is loaded. You will also have to delete:
$(document).ready(function () {
// initialization
REDIPS.drag.init();
});
from 33.html
I assume that this may be the problem … Please try and let me know if it helps – if not I will search further.
Cheers!
Hi dbunic,
Just wondering whether you could help me out on this. I need to be able to change the css for a div when I drop it. In order to do this I have used your myhandler_dropped and added the code to change the className when a particular div is dropped. Unfortunately when I subsequently try to move the div it is not visible while I am dragging it. Is there some way around this problem? Many thanks in advance.