REDIPS.drag documentation – Appendix A

Here is list of keywords (mostly class names) used in REDIPS.drag library. Id of drag container(s) or table cell class names should be named properly to achieve needed functionality like cloning DIV elements, adding trash cell, mark cells, adding row handler or mark table as “nolayout”. This post is appendix to the REDIPS.drag documentation post.

Keywords
  1. redips-drag
  2. redips-clone
  3. redips-mark
  4. redips-only
  5. redips-single
  6. redips-trash
  7. redips-rowhandler / row
  8. redips-nolayout
  9. redips-noautoscroll
  10. redips-nodrag

Before going to keywords details, make sure that HTML file has DOCTYPE definition at the top. This will switch browser to the strict mode needed for drag and drop functionality – otherwise REDIPS.drag library will not work properly.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

1. redips-drag
drag is one of the most important keywords. It is used as default name for drag container and for marking DIV elements as drag-n-drop elements. During initialization, REDIPS.drag searches inside the drag container for every DIV element with redips-drag class name and assigns onmousedown event handler. First, here is example of how to create drag container:

<div id="redips-drag">
    <!-- table1 -->
    <table>
     ...
    </table>
    <!-- table2 -->
    <table>
     ...
    </table>
</div>

Any table within drag container will become drag-n-drop layout. The most common problems and questions I received in using REDIPS.drag library are related to drag container size. If width and height CSS properties of drag container are not properly set and inner table comes out of drag container borders then dragged DIV element will not “see” exceeded cells. Good rule is to make drag container visible in customization process of REDIPS.drag library to avoid mentioned problem:

#redips-drag {
    border: 1px solid lime;
}

Next main role of redips-drag keyword is to mark DIV elements as drag elements. Every DIV element inside drag container will be able to drag and drop if drag is in class names list.

<!-- simple DIV drag element -->
<div class="redips-drag">Drag1</div>

<!-- DIV element contains two class names -->
<div class="redips-drag green">Drag2</div>

And finally, it’s possible to have more drag containers. Elements from first drag container can’t be dropped to second drag container and vice versa.

<!-- first drag container -->
<div id="my-drag1">
    <table>
     ...
    </table>
</div>

<!-- second drag container -->
<div id="my-drag2">
    <table>
     ...
    </table>
</div>

Initialization of separated drag containers is slightly different because REDIPS.drag should know names of drag containers. Here is code snippet from example08:

// reference to the REDIPS.drag library
var rd = REDIPS.drag;
// DIV container initialization
rd.init('my-drag1');
rd.init('my-drag2');

2. redips-clone
If DIV element contains redips-clone class name then in a moment of dragging a new DIV element will be cloned. Original DIV element will stay in table cell. Here is how to define clone type of DIV element.

<!-- clone DIV element -->
<div class="redips-drag redips-clone">One of Many</div>

Cloning can be further customized with climit1_X and climit2_X class names (X is integer). If needed, number of cloned DIV elements can be limited with adding climit class name. climit1 means that last DIV element will be moveable while in case of climit2 last object will stay in cell as immovable object.

<!-- allow 4 cloned elements -->
<div class="redips-drag redips-clone climit1_4">Clone type1</div>

<!-- allow 3 cloned elements and left original element as immovable in cell -->
<div class="redips-drag redips-clone climit2_3">Clone type1</div>

3. redips-mark
By default, if table cell is marked with redips-mark class name then this table cell will be closed (forbidden) for any DIV element. Simply said, DIV element will not be able to drop to this cell. Here is example of how to mark table cells as closed:

<tr>
    <td class="redips-mark">You</td>
    <td class="redips-mark">can</td>
    <td class="redips-mark">not</td>
    <td class="redips-mark">drop</td>
    <td class="redips-mark">here</td>
</tr>

It is possible to define exceptions for closed cells. For example, table cell can be forbidden for every DIV element except DIV elements with defined “id”.

// allow DIV element with id="g1" to enter to the marked cell with class="green"
rd.mark.exception.g1 = 'green';

Or it’s possible to define exception for all DIV elements with class name “green” to enter to TD defined with class name “green_cell”.

// allow DIV containing class name "green" to enter to the
// marked cell with class="redips-mark green_cell"
rd.mark.exception.green = 'green_cell';

To avoid class name collisions on existing page, redips-mark class name can be renamed with the following property:

// rename "mark" class name to "my_mark"
REDIPS.drag.mark.cname = 'my_mark';

If REDIPS.drag.mark.action is set to “allow”, then dropping will be possible only to the marked table cell. This means that default behaviour is inverted.

// reference to the REDIPS.drag library
var rd = REDIPS.drag;
// allow dropping only to the marked table cells
rd.mark.action = 'allow';

4. redips-only
Table cells marked with redips-only class name can accept only defined DIV elements. Here is example of how to define table cells marked with redips-only class name.

<th class="redips-only last"></th>

Without any additional rule, redips-only table cells will be closed for any DIV element. With the following JS lines, table cells will accept only DIV elements with id=”a” and id=”b”.

// reference to the REDIPS.drag
var rd = REDIPS.drag;
// define table cells with class="redips-only last" to accept only
// DIV elements with id="a" and id="b"
rd.only.div.a = 'last';
rd.only.div.b = 'last';

It’s also possible to set rule for DIV elements with defined class name to enter to “redips-only” table cell. Here is example how:

// only DIV elements with class="redips-drag orange" can be dropped
// to TD with class="redips-only last"
rd.only.divClass.orange = 'last';

Above rules also mean that DIV elements with id=”a” and id=”b” or with class=”redips-drag orange” will not be able to drop to any other table cell. That behaviour defines REDIPS.drag.only.other property with default value set to “deny”. If defined DIV elements are allowed to enter to other table cells then set the following property:

// allow DIV element tied with "only" rule to enter to other table cells
rd.only.other = 'allow';

5. redips-single
Table cell marked with class name redips-single will accept only one DIV element.

<!-- accept only one DIV element to the dark table cell -->
<td class="redips-single dark" title="Single content cell"></td>

6. redips-trash
Table cell marked with class name redips-trash will behave as trash can.

<td class="redips-trash" title="Trash">Trash</td>

It is possible to rename default class name (to avoid class name collisions):

REDIPS.drag.trash_cname = 'redips-bin';

Now trash cell will be defined as follows:

<td class="redips-bin" title="Trash">Trash</td>

7. redips-rowhandler / redips-row
To define row handler it is needed to add redips-row class name to the DIV element and set redips-rowhandler class name to table cell.

<tr>
    <td class="redips-rowhandler"><div class="redips-drag redips-row"></div></td>
    <td></td>
    <td></td>
    <td></td>
</tr>

Table cells marked with class name redips-rowhandler will be closed (or forbidden) for other DIV elements. In other words, DIV elements won’t have access to the “row handler” table cell.

8. redips-nolayout
If table contains redips-nolayout in class name list then it will be treated as ordinary table and other DIV elements will not be able to enter to such table. This option can be handy if you want to put table inside DIV element and drag as any other content.

<table class="redips-nolayout">
 ...
</table>

9. redips-noautoscroll
If class name of scrollable DIV container contains redips-noautoscroll class name then autoscroll option will be disabled.

<!-- drag container -->
<div id="redips-drag">
    <!-- scrollable div container -->
    <div id="sdc" class="redips-noautoscroll">
        <table>
         ...
        </table>
    </div>
</div>

To make DIV container scrollable, it is needed to set overflow to “auto” and position property to something else then default “static”:

/* make sdc DIV container scrollable */
#sdc {
    overflow: auto;
    position: relative;
}

Here is snippet from www.howtocreate.co.uk: Element position with scrolling offsets with explanation why is needed to set CSS position property (to something else then default “static”). If CSS position of scrollable DIV container is not set, then dragged DIV element will not have correct position below mouse pointer.

… make sure that every element with an overflow of anything other than “visible” also has a position style set to something other than the default “static”. This way, they will all appear in the offsetParent chain, and can be easily subtracted in the same loop that adds the offsetLeft and offsetTop.

10. redips-nodrag
If HTML element has “redips-nodrag” class, then dragging will not be able. It can be useful when DIV element contains inner HTML like in example11.

<td class="redips-nodrag">
 ...
</td>

63 thoughts on “REDIPS.drag documentation – Appendix A”

  1. Hi dbunic,
    I tested this using redips-drag-source.js file and found that it keeps alternating between 2 lines for Layout. First is in getScrollPosition():

    getScrollPosition = function () {
        // define local scroll position variables
        var scrollX, scrollY;
        // Netscape compliant
        if (typeof(window.pageYOffset) === 'number') {
            scrollX = window.pageXOffset;
            scrollY = window.pageYOffset;
        }
        ...
        ...
    

    … and Recalculate Style events:

    getStyle = function (el, style_name) {
        var val; // value of requested object and property
        if (el && el.currentStyle) {
            val = el.currentStyle[style_name];
        }
        else if (el && window.getComputedStyle) {
            val = document.defaultView.getComputedStyle(el, null)[style_name];  
        }
        return val;
    };
    

    Any idea how I can reduce the time spent on these two calls?
    Thanks

  2. @Mentalic – During initialization – enableDrag(), for each DIV element is called boxOffset() and getStyle() method. boxOffset calls getScrollPosition() and that causes the first part of the problem. Please see changes made on github:

    https://github.com/dbunic/REDIPS_drag/commit/705b739ac0fdc5011d207a125f0f726d2075d375

    Actually, page scroll offset is now set in calculateCells() and this method is called on window scroll event. Hope this modification will reduce call number of getScrollPosition(). You can download all 5.0.7 version code from github.

    Second part is related to getStyle(). It is called twice in enableDrag() for every DIV element. If your page doesn’t containt scrollable DIV container then you can completely comment out “else if (enable_flag === ‘init’) {” part. This check is not necessary and can be removed from code.

  3. Thanks a lot dbunic….I will try that out and let you know how it works.

    As an aside, I had another question. Is it possible to trap a drag and drop outside the intended container?
    For e.g., let’s say I have 2 baskets with colored balls, where each colored ball is a drag element. I can drag and drop these balls between the 2 baskets. If I drag and drop one outside of these 2 boxes, I want a popup to show up to allow me to take further actions. Is it possible to trap a drop outside these 2 containers?

    Thanks again for your prompt help !

  4. @Mentalic – You can write JS code inside moved() event handler. This handler will be fired in the moment when DIV element is moved from its current position. Or you can define TD outside baskets (like space between left and right basket) and when user drops DIV element to this cell, custom JS code in dropped() event handler can show popup with question. This can be similar to “Trash” cell with modified action …

  5. @dbunic. Thank you. Will try that out.

    btw…there is some improvement by using v 5.0.7. I will try the other change as well and see if it improves further.

    Thanks again.

  6. Hi dbunic,

    I am facing another issue with ‘click’ events. I have a click event registered on each draggable div that shows a popup when that div element is clicked. When I drag this div onto another container, I have a confirm dialog that asks if the users wants to move this element. On yes, the div is dropped into the new container and no popup shows up. On cancel, drag is cancelled, but then the onclick on the div fires and the popup shows up.

    How is the onclick suppressed when the user says ‘yes’ to dropping into the new container? I tried stopPropagation on window.event, but that does not seem to work.

    Any thoughts?

    Thanks

  7. @Mentalic – Events in REDIPS.drag library are actually hooks in dragging process. When you say that “click event” is registered I’m not sure if additional event is attached to your DIV element or you write JS code inside rd.event.clicked(). It would be better to use original REDIPS.event hooks instead of attaching event listeners to the DIV elements.

    Next, for showing a popup (with question drop or not), you can use rd.event.droppedBefore(). If user click to “Yes” then DIV element will be dropped to the destination cell (code inside this event handler just needs to nicely finish – nothing to call). In case of “No”, just return boolean false from droppedBefore() event handler and DIV element will be returned to the source cell.

    This code will return all dropped DIV elements to the source position:

    rd.event.droppedBefore = function (targetCell) {
        return false;
    };
    
  8. Hi dbunic,
    Nice piece of code.
    I was so excited to see this as I am trying to create a dynamic form creator with the ability to drag and drop elements into a table. I tried to use the merge split functionality together with the drag and drop and I got an error after merging cells together and trying to drag and element that was inside one of the cells which I merged.
    I am going to have to unfortunately abandon this until this is resolved. The error happened on line 1908: in firebug this is the error I got: “TypeError: cell_current is undefined”.
    Please let me know if I am doing something wrong or it is a bug which can be fixed.
    Regards,
    Nate

  9. @Nate – REDIPS.drag and REDIPS.table are designed to work together. Please see example 24: Table editor with the following features: merge/split cells horizontally, add/delete table row, drag and drop DIV elements …

    Merging table cells with DIV elements inside, should work without a problem (or you found a bug). If you can prepare stand alone example (zip and email) or online example (with jsfiddle), I will gladly peek to the source code and try to help.

  10. I have tried to add more lines to the school example but when save is pressed, the DIVs move up by 2 rows.
    Could you help?

  11. @Kev – If your question is still relevant (sorry for delay), adding TRs to the table should work without any problem. I tried to add the following lines to the index.php of example03:

    <?php timetable('17:00', 10) ?>
    <?php timetable('18:00', 11) ?>
    

    … and last two rows appeared (ready for accepting new DIV elements). It was possible to drop there DIV elements and to save current positions.

  12. I’ve got 3 table on my page.

    T1 and T2 are the source tables and T3 is my destination table.

    I need to allow user to drag from both the sources to the final table. All well and good till here. I was able to implement till this part.

    What i need is if they want to remove it, I want them to drag back to their original tables instead of mixing it. So T1 contents don’t get mixed with T2 contents.

    How can i achieve this? Using “only”?

    Cheers

  13. If you want to control how DIV elements can be dragged back, you will have to know origin of DIV element. Let’s assume that DIV origin is defined as additional class name (this is ID of source table) and in the moment of dropping, small JS code in event handler can allow or return dropped element. Here is JS code that can be used for such task:

    rd.event.droppedBefore = function (targetCell) {
        var div = rd.obj, // define id of DIV element
            tt;           // target table
        // define reference to target table
        tt = rd.findParent('TABLE', targetCell);
        // rule based on target table and dropped DIV element
        // eg. if DIV element doesn't contain class name
        // as id of it's origin table then return false
        // (and return DIV element to its start position)
        if (div.className.indexOf(tt.id) === -1) {
            return false;
        }
    };
    

    Hope this code snippet will give you idea how to create rule based on your request.

  14. I’m using exceptions. Can I apply one id to go in all cells despite existing exceptions ie.

    // allow DIV element with id="g1" to enter to the marked cell with class="green"
    rd.mark.exception.g1 = 'green';
    rd.mark.exception.r1 = 'red';
    rd.mark.exception.b1 = 'green', 'red'; //This wont work.
    
  15. @Ishkhan – The best way to cancel DIV dropping is to use droppedBefore() event handler. If boolean “false” is returned from this method then element dropping will be canceled (DIV will be returned to the start position). Here is small JS snippet with example:

    rd.event.droppedBefore = function (targetCell) {
        // ...
        // some JS logic to define returned value
        var flag = ...
        // return true / false
        return flag;
    };
    

    @Partick – All exceptions should be defined before user starts to drag DIV element. REDIPS.drag lib doesn’t have option to universally define one DIV element to be able entering all cells despite marking. The solution might be to dynamically add exception like it is for cloned elements in example07. Please see script2.js for some more details and here is JS snippet:

    rd.event.cloned = function () {
        // set id of cloned element
        var clonedId = rd.obj.id;
        // if id of cloned element begins with "e" then make exception
        // (allow DIV element to access cells with class name "mark")
        if (clonedId.substr(0, 1) === 'e') {
            rd.mark.exception[clonedId] = 'mark';
        }
    };
    
  16. @Pat Harding – No problem and if you’ll have further questions, please be free to ask. The only limiting factor is my free time. You never know how the next day will look like … ;)

  17. I have been looking through the shifting options and can’t quite find what I want. I would like cells that have something in them to be shifted up if there is an empty cell above them. If the standard options don’t have something like this, how can I get access to the cell just above the one I am interested in (from a beforeDropped or dropped event), find out if it’s empty, and shift up until I run into the top or a non-empty cell?

  18. Hi Darko,
    just a quick question about “single”, is this supposed to limit the number of DIV elements to only one per TD that it’s applied to? I’m trying to stop clones of DIVs being added accidentally to the original (like example 27) But even with the example I can sometimes add clones of DIVs to the TD with single applied to it.

    Any suggestions? Thanks, and great job with this overall!

Leave a Comment