Determine what is being dragged from dragenter & dragover events
I wanted to add a very clear answer here so that it was obvious to everyone who wanders past here. It's been said several times in other answers, but here it is, as clear as I can make it:
dragover
DOES NOT HAVE THE RIGHTS to see the data in the drag event.
This information is only available during the DRAG_START and DRAG_END (drop).
The issue is it's not obvious at all and maddening until you happen to read deeply enough on the spec or places like here.
WORK-AROUND:
As a possible work-around I have added special keys to the DataTransfer object and tested those. For example, to improve efficiency I wanted to look up some "drop target" rules when my drag started instead of every time a "drag over" occurred. To do this I added keys identifying each rule onto the dataTransfer object and tested those with "contains".
ev.originalEvent.dataTransfer.types.includes("allow_drop_in_non_folders")
And things like that. To be clear, that "includes" is not a magic bullet and can become a performance concern itself. Take care to understand your usage and scenarios.
The short answer to my question turns out to be: No. The WHATWG spec doesn't provide a reference to the element being dragged (called the "source node" in the spec) in the dragenter
, dragover
, or dragleave
events.
Why not? Two reasons:
First, as Jeffery points out in his comment, the WHATWG spec is based on IE5+'s implementation of drag-and-drop, which predated multi-touch devices. (As of this writing, no major multi-touch browser implements HTML drag-and-drop.) In a "single-touch" context, it's easy to store a global reference to the current dragged element on dragstart
.
Second, HTML drag-and-drop allows you to drag elements across multiple documents. This is awesome, but it also means that providing a reference to the element being dragged in every dragenter
, dragover
, or dragleave
event wouldn't make sense; you can't reference an element in a different document. It's a strength of the API that those events work the same way whether the drag originated in the same document or a different one.
But the inability to provide serialized information to all drag events, except through dataTransfer.types
(as described in my working solution answer), is a glaring omission in the API. I've submitted a proposal for public data in drag events to the WHATWG, and I hope you'll express your support.
A (very inelegant) solution is to store a selector as a type of data in the dataTransfer
object. Here is an example: http://jsfiddle.net/TrevorBurnham/eKHap/
The active lines here are
e.dataTransfer.setData('text/html', 'foo');
e.dataTransfer.setData('draggable', '');
Then in the dragover
and dragenter
events, e.dataTransfer.types
contains the string 'draggable'
, which is the ID needed to determine which element is being dragged. (Note that browsers apparently require data to be set for a recognized MIME type like text/html
as well in order for this to work. Tested in Chrome and Firefox.)
It's an ugly, ugly hack, and if someone can give me a better solution, I'll happily grant them the bounty.
Update: One caveat worth adding is that, in addition to being inelegant, the spec states that all data types will be converted to lower-case ASCII. So be warned that selectors involving capital letters or unicode will break. Jeffery's solution sidesteps this issue.