This library handles dragging and dropping using the API from the HTML 5 recommendation at https://www.w3.org/TR/html/editing.html#drag-and-drop.
It provides attributes and a model/update to handle dragging and dropping between your elements.
Types are parametrized with a dragId
and a dropId
parameter, which are the
types for the drag identifier passed to the draggable
function
and the drop identifier passed to the droppable
function.
You can put whatever data you like in these, but don't use function types.
You can use several instances of this model at the same time and they won't interfere with each other. Drag and drop are connected to an instance by the Msg constructor used, and the update function will not send a result if a drop was made from another instance.
To use on mobile, you can include the following polyfill: https://github.com/Bernardo-Castilho/dragdroptouch
Note that drag and drop does not work out of the box in Firefox.
See the example folder in github for an example that uses ports
to do event.dataTransfer.setData('text', '')
. to fix this.
The drag and drop state.
This should be placed inside your application's model like this:
type alias Model =
{ ...
, dragDrop : Html5.DragDrop.Model DragId DropId
}
init : Model dragId dropId
The initial drag and drop state.
You should use this as the initital value for the drag and drop state in your model.
The drag and drop messages.
This should be placed inside your application's messages like this:
type Msg
= ...
| DragDropMsg (Html5.DragDrop.Msg DragId DropId)
{ width : Basics.Int
, height : Basics.Int
, x : Basics.Int
, y : Basics.Int
}
The position inside a droppable. Contains the droppable's
width and height, as well as the current x and y position,
using the currentTarget.clientWidth
, currentTarget.clientHeight
, offsetX
, and offsetY
from the ondragover
event.
Note, that in some cases, x and y may be negative, or larger than the clientWidth and height, if a drop event is registered outside the CSS padding edge.
update : Msg dragId dropId -> Model dragId dropId -> ( Model dragId dropId, Maybe ( dragId, dropId, Position ) )
The update function.
When a successful drag and drop is made, this function will return a result
consisting of the dragId
and dropId
that was specified in the
draggable
and droppable
calls for the corresponding nodes. It will also return a Position
for the drop event.
This should be placed inside your application's update function, like this:
update msg model =
case msg of
...
DragDropMsg msg_ ->
let
( model_, result ) =
Html5.DragDrop.update msg_ model.dragDrop
in
{ model
| dragDrop = model_
, ...use result if available...
}
updateSticky : Msg dragId dropId -> Model dragId dropId -> ( Model dragId dropId, Maybe ( dragId, dropId, Position ) )
A "sticky" version of the update
function.
It's used the same way as the update
function, but when you use this version,
droppables are "sticky" so when you drag out of them and release the mouse button,
a drop will still be registered at the last droppable. You should preferably
provide some sort of indication (using getDropId
) where the drop will take
place if you use this function.
draggable : (Msg dragId dropId -> msg) -> dragId -> List (Html.Attribute msg)
Attributes to make a node draggable.
The node you put these attributes on will be draggable with the dragId
you provide.
It should be used like this:
view =
...
div (... ++ Html5.DragDrop.draggable DragDropMsg dragId) [...]
droppable : (Msg dragId dropId -> msg) -> dropId -> List (Html.Attribute msg)
Attributes to make a node droppable.
The node you put these attributes on will be droppable with the dropId
you provide.
It should be used like this:
view =
...
div (... ++ Html5.DragDrop.droppable DragDropMsg dropId) [...]
getDragId : Model dragId dropId -> Maybe dragId
Get the current dragId
if available.
This function can be used for instance to hide the draggable when dragging.
getDropId : Model dragId dropId -> Maybe dropId
Get the current dropId
if available.
This function can be used for instance to highlight the droppable when dragging over it.
Note that for efficiency reasons, the dragover
event is being propagated,
so if you have a droppable inside another droppable you could get the wrong info
from getDropId
. The package tries to ignore the extra events, but it may fail.
getDroppablePosition : Model dragId dropId -> Maybe Position
Get the current Position
when dragging over the droppable.
getDragstartEvent : Msg dragId dropId -> Maybe { dragId : dragId, event : Json.Decode.Value }
Get the dragstart
event Value
so that you can pass it to a port.
This is useful to fix Firefox behaviour. See the example directory in github
for how you can do that.
You can also use the event to do other things from Javascript, such as setting the drag image.