-
Notifications
You must be signed in to change notification settings - Fork 709
Data Transfer Design
This design document outlines how the dataTransfer
object will be used in version 2.0 of angular-drag-and-drop-lists. The focus lies mainly on which mime type will be used when calling setData
on the dataTransfer
object.
When calling setData
we want to store a serialized version of the item that the user provided us in dnd-draggable
. The HTML5 spec says that the format
we pass to setData
can be any string, but will be converted to ASCII lowercase. It is recommended to use a mime type here, since the drag & drop API is native and therefore the format might read by other applications. Also, when using dnd-external-sources
we don't usually want to accept data that was not generated by this directive.
Since the data we send is in JSON format, a good mime type to use would be application/json
. However, it's not really useful for us to accept drops from other applications when using dnd-external-sources
, since we will most likely not be able to process it correctly. Therefore, we choose a custom mime type, namely application/x-dnd
.
The user can give objects specific types using the dnd-type
attribute, and accordingly limit the types accepted by lists with dnd-allowed-types
. In previous versions of the directive we implemented this using a global variable, which means the type was not transferred when dragging objects across documents with dnd-external-sources
. We can enable this by encoding the dnd-type
in the mime type, e.g. for objects of type foo
our mime type would be application/x-dnd-foo
.
On the receiving side, the dnd-list
will accept all drops that start with the prefix application/x-dnd
. If the dnd-allowed-types
attribute is set, it will limit the mime types it accepts accordingly.
Unfortunately, IE only allows to call setData
with either Text
or URL
format. For this reason, previous versions of the directive were always using the Text
format, which has the disadvantage that our objects can be dropped into any text field outside of our application, and vice versa if we allowed drops from external sources.
The new idea for version 2.0 is to try to set a custom mime type, but then catch the exception that will only be thrown by IE. We can then use the Text
format as fallback. Luckily, IE does also not convert Text
into text/plain
as specified by the HTML5 standard, therefore we can just accept Text
drops on the receiving side without having a negative effect on modern browsers (because modern browsers will never have a Text
type in dataTransfer
).
Now that we use the Text
mime type for Internet Explorer, we have to solve the problem of handling dnd-type
again. There are two options:
- Storing the actual mime type in a global variable. This will work perfectly for operations within the same window, but will fail miserably with
dnd-external-sources
. - Sending the actual mime type within the transferred data, e.g.
{mimeType: 'application/x-dnd-foo', item: {...}}
. This will work for external drops as well as for internal drops. The only catch is that we don't have access togetData
in thedragover
callback, therefore this will always show a placeholder when dragging over adnd-list
, even when dropping will actually not work.
To get the best possible solution in Internet Explorer, we will use both options. As a result IE will work nearly as good as modern browsers, the only thing is that all drops from external sources will show the placeholder while dragging over the target list.
So far so good. Now Microsoft developed a new browser, Edge, that kind of follows the HTML5 standard, except it doesn't. As of Feb 2016 setData
fails when passing a custom mime type, but seems to work for some set of officially defined mime types. Even worse, the workaround for MSIE using Text
no longer works for Edge, because Edge follows the standard in this matter and converts it to text/plain
. We don't want to accept text/plain
though, because that allows any kind of text to be dropped into our lists.
Therefore, we need another mime type for Edge. I decided on using application/json
. As above, we can wrap it inside a try-catch block so it works with MSIE, and then we use the same workarounds for transferring the dnd-type
.
Browser Compatibility Issues (as of Feb 2016)
- IE: Only supports
Text
andURL
format. Does not convertText
totext/plain
in dropzone events - Edge: Does not support custom mime types. Would be interesting to get a list of all supported mime types.
Pseudo-Code for dragstart
- mimeType := "application/x-dnd"
- if dnd-type set, append it to the mimeType
- try setData(mimeType, item)
- on exception:
- Store the mimeType in a global variable
- data := {mimeType: mimeType, item: item}
- try setData("application/json", data)
- on exception setData("Text", data)
Pseudo-Code for dragenter and dragover
- Go through dataTransfer.types to find an acceptable type
- "Text" and "application/json" are always accepted
- If dnd-allowed-types is not set, any type starting with application/x-dnd is accepted
- If dnd-allowed-types is set, the mime type's suffix must be one of those
- If no acceptable type is found, the drop is cancelled
- If the accepted type above was "Text" or "application/json", also do this:
- If the drop comes from an internal source, check the mime type stored in the global variable and cancel the drop if it is not acceptable
- If the drop comes from an external sources, allow it
Pseudo-Code for drop
- Go through dataTransfer.types to find an acceptable type, as for dragover
- Call getData with the type from above and deserialize the data
- If the accepted type above was "Text" or "application/json", also do this:
- Check the mime type stored in the mimeType field of the transferred object cancel the drop if it is not acceptable