Html – Changing Mouse Cursor for HTML5 Drag Drop Files (GMail Drag Drop)

drag and drophtml

I'm trying to reproduce the way GMail handles html5 drag/drop attachments — where as soon as you drag files over the page, it displays a new element for you to drop them on. I got that part worked out (it wasn't as straight forward as I thought it would be).

Now I'm trying to polish it up by changing the mouse cursor when the mouse is over any other element other than the drop element, to tell the user dropping isn't allowed here. I imagine I can do it with a custom cursor, but that does not appear to be what GMail is doing. The spec would suggest it's possible to change the mouse cursor as well, but I can't seem to get it working right, using dropzone/effectAllowed.

Any help would be appreciated, here's my current setup: http://jsfiddle.net/guYWx/1/

ETA: Here's what I ended up with: http://jsfiddle.net/guYWx/16/

<body style="border: 1px solid black;">
    <div id="d0" style="border: 1px solid black;">drag files onto this page</div>
    <div id="d1" style="border: 1px solid black; display: none; background-color: red;">-&gt; drop here &lt;-</div>
    <div id="d2" style="border: 1px solid black;">and stuff will happen</div>
    <div style="float: left;">mouse them all over&nbsp;</div>
    <div style="float: left;">these elements</div>
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
    <div>end page</div>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
    var resetTimer;

    var reset = function()
    {
        $('#d1').hide();
    };

    var f = function(e)
    {
        var srcElement = e.srcElement? e.srcElement : e.target;

        if ($.inArray('Files', e.dataTransfer.types) > -1)
        {
            e.stopPropagation();
            e.preventDefault();

            e.dataTransfer.dropEffect = (srcElement.id == 'd1') ? 'copy' : 'none';

            if (e.type == "dragover")
            {
                if (resetTimer)
                {
                    clearTimeout(resetTimer);
                }
                $('#d1').show();
                console.info('dropped on <' + srcElement.tagName.toLowerCase() + ' id="' + srcElement.id + '">\n\ne.dataTransfer.types is ' + e.dataTransfer.types + '\n\ne.dataTransfer.files.length is ' + e.dataTransfer.files.length);

            }
            else if (e.type == "dragleave")
            {
                resetTimer = window.setTimeout(reset, 25);
            }
            else if (e.type == "drop")
            {
                reset();
                alert('dropped on <' + srcElement.tagName.toLowerCase() + ' id="' + srcElement.id + '">\n\ne.dataTransfer.files.length is ' + (e.dataTransfer.files ? e.dataTransfer.files.length : 0));
            }
        }
    };

    document.body.addEventListener("dragleave", f, false);
    document.body.addEventListener("dragover", f, false);
    document.body.addEventListener("drop", f, false);
</script>

Best Answer

Did some digging through the source and found that you're supposed to set event.dataTransfer.dropEffect = 'move'; inside your dragover event handler. Googled for dropEffect to read more and found:

dataTransfer.dropEffect

Controls the feedback that the user is given during the dragenter and dragover events. When the user hovers over a target element, the browser's cursor will indicate what type of operation is going to take place (e.g. a copy, a move, etc.). The effect can take on one of the following values: none, copy, link, move.

from: http://www.html5rocks.com/en/tutorials/dnd/basics/

Edit: Here's what I ended up with: http://jsfiddle.net/guYWx/16/

Had to do one additional trick to get it working perfectly. Did this so the dropper wouldn't appear when you select text and drag it around the page:

if ($.inArray('Files', e.dataTransfer.types) > -1)