JavaScript drag and drop plus content shift

Demo is based on REDIPS.drag JavaScript library with enabled shift drop mode. After element is dropped to the cell, other elements will be shifted to make room. Animation is optional and can be turned off. The presented demo (with three tables – normal, colspan / rowspan and marked cells) can be a good start point for various sorting Web applications.


REDIPS.drag example21

Boolean public property animation.shift defines whether shift animation will be turned off or on. Default is off and table content will be shifted instantly. If animation is turned on, then dragging will not be possible while animation lasts. This was needed to prevent possible collisions between animation and dragging.

Drag and drop DIV element inside the same table will actually sort table content. Table content will be shifted to left or to the right side. If new element is dropped to the table, then table content will be shifted to the right. Repeating will result with accumulation of DIV elements in the bottom last table cell. Here is JavaScript code needed for shift table content:

var redipsInit,
    setTable,
    shiftMode,
    overflow,
    shiftAnimation,
    shiftAfter,
    toggleConfirm,
    counter = 0;

// redips initialization
redipsInit = function () {
    // reference to the REDIPS.drag library
    var rd = REDIPS.drag;
    // initialization
    rd.init();
    // set mode option to "shift"
    rd.dropMode = 'shift';
    // set animation loop pause
    rd.animation.pause = 20;
    // enable shift.animation
    rd.shift.animation = true;
    // set TD for overflow elements (initially)
    rd.shift.overflow = document.getElementById('overflow');
    // add counter to cloned element name
    // (after cloned DIV element is dropped to the table)
    rd.event.clonedDropped = function () {
        // increase counter
        counter++;
        // append to the DIV element name
        rd.obj.innerHTML += counter;
    };
};

// set current table
setTable = function (e) {
    var value = e.options[e.selectedIndex].value,
        tables = document.getElementById('drag').getElementsByTagName('table'),
        i;
    // loop goes through all fetched tables within drag container
    for (i = 0; i < tables.length; i++) {
        // skip mini table
        if (tables[i].id === 'mini') {
            continue;
        }
        // show selected table
        else if (tables[i].id === value) {
            tables[i].style.display = '';
        }
        // hide all other tables
        else {
            tables[i].style.display = 'none';
        }
    }
};

// set shift mode
shiftMode = function (radio) {
    REDIPS.drag.shift.mode = radio.value;
};

// set overflow
overflow = function (radio) {
    if (radio.value === 'user') {
        REDIPS.drag.shift.overflow = document.getElementById('overflow');
    }
    else {
        REDIPS.drag.shift.overflow = radio.value;
    }
};

// enable / disable animation
shiftAnimation = function (chk) {
    REDIPS.drag.shift.animation = chk.checked;
};

// enable / disable shift after element is deleted
shiftAfter = function (chk) {
    REDIPS.drag.shift.after = chk.value;
};

// toggles trash_ask parameter defined at the top
toggleConfirm = function (chk) {
    if (chk.checked === true) {
        REDIPS.drag.trash.question = 'Are you sure you want to delete DIV element?';
    }
    else {
        REDIPS.drag.trash.question = null;
    }
};

// add onload event listener
if (window.addEventListener) {
    window.addEventListener('load', redipsInit, false);
}
else if (window.attachEvent) {
    window.attachEvent('onload', redipsInit);
}

Label of cloned elements is increased on every element cloning. Please see how event.clonedDropped event handler was used. REDIPS.drag has many event handlers hooked in different stages to simplify needed customization.

39 thoughts on “JavaScript drag and drop plus content shift”

  1. @Ramprasad – Checkbox definition is simple:

    <input type="checkbox" name="box1" value="R"/>
    <input type="checkbox" name="box2" value="W"/>
    

    Checkboxes should be closed within HTML form. After user clicks on form submit, browser will send values box1=R&box2=W if both checkboxes are checked. In case of unchecked checkbox, browser will not send anything. So, on the server side you should accept form parameters box1 and box2. Here is example in PHP:

    $box1 = $_REQUEST['box1'];
    $box1 = $_REQUEST['box2'];
    

    Now parameters are accepted and can be stored to the database. Hope this tips will be helpful.

  2. Hi,

    First, please excuse me if I make writing mistakes. I’m French and my English level is not very good.

    Next, your library is pretty cool, I have been using it for 2 days and I discoverd a lot of things.

    BUT, I have a little question : How can I do to sort my photos, using your “shift” option without leaving empty cells.

    For example, in this page, if you move the “J” down, you will have an empty cell between “I” and “K”.

    How can I do this ?

    Thanks a lot for your help.

    Yohan.

  3. Everything was working fine then I tried to call Perform action using ICallbackEventHandler interface that really called it but color was not changing, after that I removed that interface and again switched to __doPostBack but then I’m facing an error that my DIVs become disabled when I drag a single DIV and again enabled on page refresh …

    Can you help me please?

  4. @Yohan – REDIPS.drag is upgraded to version 4.7.4. If shift_after public property is set to always then content will be shifted in your case as well.

    REDIPS.drag.shift_after = 'always';
    
    // if REDIPS.drag is defined as rd
    
    rd.shift_after = 'always';
    

    New feature is shown in this example also. Just check “always” radio button and try to move “J” element to empty table cell.

    @Waqas – Described problems are related to messed events handlers attached to the DIV elements. During REDIPS.drag initialiazation, lib will search for all DIV elements inside drag container and attach onClick event handler (this is a bit simplified description). In the moment when user clicks on DIV element, onMove event handler will be activated on BODY. This way dragged DIV element can be moved accross whole page. When mouse button is released, DIV element will be replaced from source to the current table cell and onMove event handler will be removed. In short, this is described process of how REDIPS.drag works. If you are familiar with Web inspector you can test if event listener exists and try to discover the source of collision. Hope this lines will help you in debugging …

  5. Am loving the script, am using example 13 as base of what we are doing. Am having difficulty in finding out how to align objects so that they align horizontally instead of vertically, so that they wrap onto next line when table cell fills up.

    Could someone explain where I can find the settings for this?

    Thanks

  6. @Stephen – Just try to set float:left style. Here is example of DIV CSS styles to place dropped elements horizontally (side by side):

    .drag {
        text-align: center;
        width: 80px;
        height: 30px;
        float: left;
    }
    

    You will need to have wide enough table cells for horizontal alignment. Hope this will solve your problem …

  7. First of all, this library is awesome and you are the man.

    Quick Question though. I have been working on one thing for a few days that I can’t figure out.

    If I have Horizontal2 turned on, how can I make it so that all DIVs shifts Left so that no spaces are left? (Similar to Yohans example except I want DIVs to stay in their designated rows)

    I know that may be a problem if there are multiple DIVs in the last row, but my table has enough columns where that shouldn’t be an issue…Or maybe the top/bottom DIV moves left.

    Again, all DIVs shift left until there are no open TDs in each row.

    Is there a relatively simple way to do this?

  8. @Thomas – horizontal2 mode treats rows separately. If content should be shifted in whole table then try with horizontal1 mode. The similar modes are vertical1 and vertical2 (content is shifted verticaly).

    Next, DIV elements are shifted cell by cell. But you can create custom shifting with shift_cells(td1, td2) method. td1 and td2 are source and target table cells.

  9. Thanks Darko,

    Sorry for wording the problem poorly. I just meant if horizontal2 is turned on, and I was to take DIv B and place it in say (row 4, column 4) , C,D,E,F in row 0 would shift to the left to fill in the gap, and B would shift in row 4 to the left until it came to another DIV, or R. No Gaps would ever be left in rows.

    I got it working using shift_cells and a loop that starts at the final column of each row, and works its way to the left shifting any cells that have an empty cell to “the left.” If there is a shift, it jumps back to the right most column and starts again.

    The only problem I am having is that the animation is awkward from the looping, so I am turning it off during the loop. Sometimes the contents of the cell can shift multiple spaces to the left. Maybe I can fix it with move_object and/or relocate.

    Also what event can I use that will start my loop AFTER all of your standard animated shifts happen?

    Thanks again

  10. @Thomas – Thanks for detailed info. Lib is updated with new event handler. So, in REDIPS.drag version 4.7.6, you have myhandler_relocated() event handler. This event handler is triggered after animation is finished in shift mode (actually, myhandler_relocated() event handler is called from relocate() method). If animation is turned off, then new event handler will not be called.

    Hope this will help. If you will still need assistance, I will gladly help.

  11. Thanks again for your help Darko.
    The problem was I thought that shift_cells(td1,td2) only shifted adjacent cells, rather then the range of cells. Looping through adjacent cells caused the animation to get a little whacky.

    For anyone else interested, here is a simple starting point so that “gaps” in your rows close themselves, and everything shifts left in its row while horizontal2 is on.

    leftShift = function (rd) {
        var lastCol = 5;
        var mainTable = document.getElementById("mainTable");
        rd.enable_table(false, mainTable);
    
        var pos = rd.get_position();
        var startRow = pos[4];
        var startCol = pos[5];
        var finishRow = pos[1];
        var finishCol = pos[2];
        var leftTd;
        var rightTd;
        var trList;
        var tdList;
    
        if (startRow != finishRow) {
            trList = mainTable.getElementsByTagName('tr');
            tdList = trList[startRow].getElementsByTagName('td');
    
            rightTd = tdList[lastCol];
            leftTd = tdList[startCol];
    
            rd.shift_cells(leftTd, rightTd);
        }
        rd.enable_table(true, mainTable);
    };
    
  12. @Thomas – Thank you very much for posting a solution. Your JS code will surely be helpful for others. Cheers!

  13. Hello Mr.dbunic,
    Thank you for your great ideas.
    How may we save the position of the above Table2 example?

    I would like to save the position to database.
    Can it be done? with your example above?
    If too much work, you may charge if you need.

    Once more, Thank you sir.

  14. @emerson – Inside REDIPS.drag event handlers you can reference “td” property. Here is list from documentation:

    td.source – reference to source table cell (set in onmousedown)
    td.previous – reference to previous table cell (set in onmousemove and autoscroll)
    td.current – reference to current table cell (set in onmousemove and autoscroll)
    td.target – reference to target table cell (target table cell is set in a moment of dropping element to the table cell)

    From this info it’s possible to get DIV position and prepare data for saving to database.

  15. hi ! i am working of drag and drop using jquery , but here my client requirements is that if shifted the first div to upper then the old div is become empty and the empty div is not able to drag. also at the time of drop if the div containing some value then not any other div content drop in this div

    pls suggest me option to solve problem

  16. I wonder how could I integrate many example in 1 example ,in addition for that I want to add event when i drop item into table .
    thanks in advance.

  17. Hi,
    In drag & drop operation, my source is a tree node where are the target is a text box. Is it possible to drag & drop a tree node into a text box component? Please advise if there is a way to go

Leave a Comment