JSFiddle - React, Tailwind, and code Playground

by ThiefMaster

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/redmond/jquery-ui.css">
<div id="sortspace">
    <div id="cat1" class="sortblock">
        <table>
            <thead>
                <tr>
                    <th>dummy caption</th>
                </tr>
            </thead>
            <tbody>
                <tr data-id="1"><td><span class="sort-handle">X</span>dummy 1.1</td></tr>
                <tr data-id="2"><td><span class="sort-handle">X</span>dummy 1.2</td></tr>
                <tr data-id="3"><td><span class="sort-handle">X</span>dummy 1.3</td></tr>
                <tr data-id="x"><td><span class="sort-handle">X</span>dummy X</td></tr>
            </tbody>
        </table>
    </div>
    
    <div id="cat2" class="sortblock">
        <table>
            <thead>
                <tr>
                    <th>dummy caption</th>
                </tr>
            </thead>
            <tbody>
                <tr data-id="4"><td><span class="sort-handle">X</span>dummy 2.1</td></tr>
                <tr data-id="5"><td><span class="sort-handle">X</span>dummy 2.2</td></tr>
                <tr data-id="6"><td><span class="sort-handle">X</span>dummy 2.3</td></tr>
                <tr data-id="x"><td><span class="sort-handle">X</span>dummy X</td></tr>
            </tbody>
        </table>
    </div>
</div>

<button id="save">Save</button>

<div id="debug">
    
</div>

CSS

#debug { margin: 2em 1em 1em 1em; border-top: 1px solid #000; }
#sortspace > div {
    margin: 1em;
    border: 1px solid #000;
}
table { width: 100%; }

.sort-handle { cursor: move; margin-right: 0.5em; font-weight: bold; }
.placeholder { height: 1.5em; background: #fc0; }
.drop-target { border: 1px dashed #fa0 !important; background: #fff7cf; }

JavaScript

function dbg(txt, overwrite) {
    if(overwrite) {
        $('#debug').empty();
    }
    $('#debug').append($('<pre/>').text(txt));
}

function canBeDropped(elem, item) {
    var currentRow = $(item);
    var ret = true;
    $('tr', elem).not(currentRow).each(function() {
        // We check all rows of the target element for one with the same ID.
        // In indido this would check the email address, name, id or whatever.
        // I'd suggest to store this information in data(), too, as it's the easiest
        // way to access it here.
        if($(this).data('id') == currentRow.data('id')) {
            ret = false; // set return value for outer function
            return false; // cancel the loop
        }
    });    
    return ret;
}

$('.sortblock tbody').sortable({
    connectWith: '.sortblock tbody', // interconnect all sortable tables
    placeholder: 'placeholder', // set a class for the placeholder row
    handle: '.sort-handle', // require the user to use the sorting handle to move items
    start: function(e, ui) { // triggered when sorting starts (i.e. when the user stargs dragging)
        // so we have a valid placeholder row
        ui.placeholder.html('<td></td>');
        // mark all valid drop areas as targets
        $('.sortblock').each(function() {
            if(canBeDropped($('tbody', this), ui.item)) {
                $(this).addClass('drop-target'); 
            }
            else {
                $(this).addClass('no-drop-target');
            }
        });
    },
    stop: function(e, ui) { // triggered when sorting finished (cancelled or successfully sorted)
        //remove drop target highlighting
        $('.sortblock').removeClass('drop-target no-drop-target');
    },
    receive: function(e, ui) { // triggered when an element is being dropped
        // check if we are a child of a drop target
        if(!$(this).closest('.drop-target').length) {
            $(ui.sender).sortable('cancel');
            alert('You cannot...