2
votes

I have a weird issue with drag & drop in HTML5.

There are 3 target zones which are divs with text in them and 1 source zone which is a div containing a image.

I use dragenter and dragleave events to change the border of the active target zone to project where the dragged object is going to land.

The problem is that as soon as you drag it over text, it for some reason fires the dragleave event, removing the border.

Here is a jsfiddle example illustrating the problem

And here is some inline code:

HTML

<h1>Targets</h1>
<div class="targets">
    <div class="target">I am a target<br/>Touch text while dragging to see the problem</div>
    <div class="target">I am a target<br/>Touch text while dragging to see the problem</div>
    <div class="target">I am a target<br/>Touch text while dragging to see the problem</div>
</div>
<h1>Source</h1>
<div class="source" draggable="true">
    <img class="source_image" src="http://lorempixel.com/output/technics-q-c-184-69-8.jpg" alt="image" width="184" height="69"/>
</div>

JS

$("div.source").on('dragstart', function(e) {
    $(this).fadeTo('slow', 0.4);
});

$("div.source").on('dragend', function(e) {
    $(this).fadeTo('slow', 1);
});

$("div.target").on('dragover', function(e) {
    if (e.preventDefault) {
        e.preventDefault();
    }

    e.dataTransfer.dropEffect = 'move';

    return false;
});

$("div.target").on('dragenter', function(e) {
    $(this).addClass('over');
});

$("div.target").on('dragleave', function(e) {
    $(this).removeClass('over');
});

CSS

h1 {
    font-size: 2em;
    text-align: center;
}

.target {
    margin: 1em;
    display:inline-block;
    width: 184px;
    height: 69px;
    border: 5px #995555 solid;
    border-radius: 5px;
    background-color: #AAAAAA;
    vertical-align: bottom;
    text-align: center;
    font-size: 1.1em;
    font-weight: bold;
    line-height: 0.9em;
}

.target.over {
    border: 5px #0A0 dashed;
}

.source {
    margin: 1em;
    display:inline-block;
    width: 184px;
    height: 69px;
    border: 5px #555599 solid;
    border-radius: 5px;
    background-color: #CCCCCC;
    vertical-align: bottom;
    text-align: center;
    font-size: 1.4em;
    font-weight: bold;      
}

Does anyone know of any solutions to keep the border changed even when touching text?

Another question would be whether it is possible to keep the border around the source div being dragged?

On a final note, I realize that both of these things can be done by using jQuery UI draggable and droppable, but I'm specifically wondering if it is possible to do this with native HTML5 drag & drop.

1

1 Answers

2
votes

The problem is that the text constitutes an extra node in the DOM, and dragleave and dragenter take into account child elements as well as parent elements. When the cursor enters the text node, it leaves the div. This is similar to the mouseout vs mouseleave issue. A simple way to work around it is to keep a count of the events and only remove the style when all are accounted for:

var count=0;
$("div.target").on('dragenter', function(e) {
    $(this).addClass('over');
    count++;
}).on('dragleave', function(e) {
    if (--count<=0) {
        $(this).removeClass('over');
    }
});

This isn't necessarily completely reliable (remember to set count to zero in the drop event), but it'll work better than your current setup. Another option is to not put any content in the div elements at all, instead add it with CSS:

.target:after {
    content: 'I am a target \A Touch text while dragging to see the problem';
    white-space: pre-wrap;
}

This has some accessibility drawbacks, because generated content is invisible to assistive technology, and will only let you add text, but is in many ways a cleaner solution.