JSFiddle - React, Tailwind, and code Playground

by theodorejb

HTML

<a href="#" id="drag" draggable="true">Drag me</a>

<div id="drop" dropzone="copy">
    Text node in parent
    <p>
        Text node in child
        <p>Text node in grandchild</p>
    </p>
    Text node in parent
</div>

CSS

body {
    padding: 5px;
    font-family: Arial, sans-serif;
}
#drag {
    display: inline-block;
    text-decoration: none;
    border: 1px solid gray;
    color: #111;
    background-color: #dfdfdf;
    padding: 8px 14px;
}
#drop {
    margin-top: 10px;
    background-color: #e3e3e3;
    padding: 8px;
}
#drop.over {
    background-color: #d1d1d1;
}
#drop.dragging {
    padding: 18px;
    border: 1px dashed gray;
}
#drop p {
    margin: 10px 0;
}

JavaScript

/*
 * While it isn't possible to prevent the dragleave event from
 * firing on parent elements when dragging over their children
 * in IE 8-10, it is possible to ignore it. To do this, add 
 * dragenter and dragleave event listeners to each child node 
 * which will add or remove an 'ignore-drag-leave' class from 
 * their parent. This works because the dragenter event on 
 * child nodes is fired before the dragleave event on the parent.
 *
 * This technique is tested and working in Chrome, Firefox, and
 * IE8+. If you don't need to support versions of IE prior to
 * IE11, use this simpler solution: http://jsfiddle.net/theodorejb/4ZGvv/.
 */

var drag = document.getElementById('drag');
var drop = document.getElementById('drop');

addEvent(drag, 'dragstart', startDrag);
addEvent(drag, 'dragend', endDrag);

addEvent(drop, 'dragenter', handleDragEnter);
addEvent(drop, 'dragleave', handleDragLeave);
addEvent(drop, 'dragover', handleDragOver);
addEvent(drop, 'drop', handleDrop);

if (drop.hasChildNodes) {
    var children = drop.childNodes;
    for (var i = 0; i < children.length; i++) {
        var node = children[i];
        addEvent(node, 'dragenter', handleChildDragEnter);
        addEvent(node, 'dragleave', handleChildDragLeave);
        console.log('Added event listeners to child node #' + i);
    }
}

function startDrag(e) {
    console.log('Dragging button');
    e.dataTransfer.setData("Text", "my data");
    e.dataTransfer.dropEffect = "copy";
    $(drop).addClass('dragging');
}

function endDrag(e) {
    console.log('Finished dragging button');
    $(drop).removeClass('dragging');
}

function handleDragEnter(e) {
    stopEvent(e);
    console.log('Entering parent');
    $(drop).addClass('over');
}

function handleDragOver(e) {
    stopEvent(e);
}

function handleDragLeave(e) {

    if (!hasIgnoreClass(drop)) {
        $(drop).removeClass('over');
        console.log('Leaving parent');
    }
}

function handleDrop(e) {
    stopEvent(e); // prevent navigation...