The native drag-and-drop APIs

Drag-and-drop is a way to convert the pointing device's movements and clicks to special commands that are recognized by software to provide quick access to common functions of a program. The user grabs a virtual object, drags it to a different location or another virtual object, and drops it there. Drag-and-drop support for a native browser means faster, more responsive, and more intuitive web applications. Before you use the drag-and-drop feature, make sure you have draggable content.

Draggable content

An abstract Element class has a draggable attribute that indicates whether the element can be dragged and dropped. As all the DOM elements emerge from the Element abstract class, this means all of them support the drag-and-drop operation by default. To make elements draggable, we need to set their draggable attribute to true. This can be done using the following code:

var dragSource = querySelector("#sample_drag_id");
dnd.draggable = true;

Alternatively, you can do this using the following HTML markup:

<p id="sample_dnd_id" draggable="true">Drag me!</p>

If you want to prevent the text contents of draggable elements from being selected, you can style the element, as shown in the following code:

[draggable] {
  -moz-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;
  user-select: none;
  -khtml-user-drag: element;
  -webkit-user-drag: element;
}

Let's open the drag_and_drop project and run it. In the following screenshot, you will see that you can drag the text element within the window of the browser but cannot drop it:

Draggable content

To manage the drag-and-drop operations in the example, add the drag-and-drop event listeners described in the next section.

Note

During a drag operation, the native drag-and-drop API is fired only by the drag events and not the mouse events.

The drag-and-drop events

The native drag-and-drop API fires the following events:

  • dragstart: This event is fired on an element when a drag starts. Information such as the drag data and image to be associated with the drag operation can be set in the listener.
  • dragenter: This event is fired when the cursor is hovered over an element for the first time while a drag begins. A drop operation is not allowed by default. There are one or more listeners that perform drag-and-drop operations. Usually, the listener highlights or marks the drop element where the drop can occur.
  • dragover: This event is fired when the cursor is hovered over an element and a drag is in process.
  • dragleave: This event is fired when the cursor leaves an element while a drag is in process. The listener will remove highlights or markers from the element where the drop can occur.
  • drag: This event is fired on an element where the dragstart event was fired.
  • drop: This event is fired on an element where the drop occurred. It is fired only if the drop is allowed. Users can cancel the drag operation by pressing the Esc key or releasing the mouse button on an invalid drop area.
  • dragend: This event is fired on an element on which the drag was started to inform that the drag operation is complete, regardless of whether it is successful or not.

We will continue to make elements draggable from our example. We need to add a listener for the dartstart event and set the drag data within the listener, as follows:

var dragSource = querySelector("#sample_drag_id")
..draggable = true
..onDragStart.listen((MouseEvent event) {
  //…
});

If an element is made draggable, you cannot select the text by clicking-and-dragging with the mouse.

Note

User must hold down the Alt key to select text with the mouse.

Dragging data

Each drag event has a dataTransfer property that is used to hold data associated with the drag operation. If you drag the selected text, then the associated data is text. If you drag an image, then the associated data is the image itself. The drag data combines the string representation of the format of the data and the data value. We will use the format of the data in the event listeners for the dragenter and dragover events to check whether the drop operation is allowed or not. You can set multiple drag data to call the setData method multiple times with different formats. To delete them, call the clearData method of the dataTransfer property, as shown in the following code:

var dragSource = querySelector("#sample_dnd_id")
..draggable = true
..onDragStart.listen((MouseEvent event) {
  event.dataTransfer.setData("text/plain", "I'm draggable");
  event.dataTransfer.setData("text/data", "1234");
});

Dragging the feedback image

Usually, native drag-and-drop APIs automatically create translucent images that are generated from the drag target of the dragstart event, which follows the mouse pointer during the drag operation. You can use the setDragImage method of the dataTransfer property to specify a custom drag image. The first argument of this function is a custom drag image, which could be a reference to a real image, canvas, or other elements. The second and third arguments are offsets where the image should appear relative to the mouse pointer. The code is as follows:

var dragSource = querySelector("#sample_drag_id")
..draggable = true
..onDragStart.listen((MouseEvent event) {
  event.dataTransfer.setData("text/plain", "I'm draggable");
  event.dataTransfer.setDragImage(new 
    ImageElement(src:'notification.png'), 0, 0);
});

The following feedback image will appear instead of the standard translucent image:

Dragging the feedback image

Dragging effects

The drag-and-drop API supports operations such as copy, move, link, and their combinations that may be performed on data that is draggable. We can use the copy operation to indicate that the data being dragged will be copied from its present location to the drop location. Similarly, you can use the move operation to indicate that the data being dragged will be moved, and the link operation indicates that connections will be created between the source and drop locations. You should specify which operation or combinations are allowed and are performed by setting the effectAllowed property of the dragstart event within a listener, as shown in the following code:

var dragSource = querySelector("#sample_drag_id")
..draggable = true
..onDragStart.listen((MouseEvent event) {
  event.dataTransfer.setData("text/plain", "I'm draggable");
  event.dataTransfer.setDragImage(new 
    ImageElement(src:'notification.png'), 0, 0);
  event.dataTransfer.effectAllowed = 'copy';
});

In the preceding example, we allowed only the copy operation. Let's see all the values that we can use as the name for an operation:

  • none: This operation means that no operation is permitted
  • copy: This operation means that the drag data can only be copied from source to drop location
  • move: This operation means that the drag data can only be moved from source to drop location
  • link: This operation means that the drag data can only be linked from source to drop location
  • copyMove: This operation means that the drag data can be copied or moved from source to drop location
  • copyLink: This operation means that the drag data can be copied or linked from source to drop location
  • all: This operation means that the drag data can be copied, moved, or linked from source to drop location

By default, the effectAllowed property allows all three operations. The permitted operation can be checked in a listener for the dragenter or dragover events via the effectAllowed property, and it should be set in a related dropEffect property to specify which single operation should be performed. The valid operations for the dropEffect property are none, move, or link only, and any other combinations are prohibited. The desired operation will change the mouse pointer, so the cursor might appear with a plus for the copy operation. The desired effect can be modified by a user by pressing the modifier keys. The exact keys vary by platform. On Windows OS, a user typically uses the Shift and Ctrl keys to switch between the copy, move, and link operations. During the dragenter and dragover events, we can modify both the effectAllowed and dropEffect properties to specify the supported operations by a drop target. The effect specified in dropEffect must be the one that is listed within the effectAllowed property. The value of the dropEffect property can tell us exactly the result of the drag operation. If the value of the dropEffect property is none, then the drag was cancelled; otherwise, the specified effect holds the performed operation. The drag-and-drop operation is considered complete after the dragevent is finished.

Note

The none value can be used for either of the property to indicate that no drop operation is allowed at the target location.

The drop target

The drop target is a place where the dragged item may be dropped. The drop target is very important because most areas of a web page are not permitted to drop. Event listeners for the dragenter and dragover events are used to indicate a valid drop target through preventing default handling by canceling events, as shown in the following code:

var dropTarget = querySelector("#sample_drop_id")
  ..onDragOver.listen((MouseEvent event) {
    if (checkTarget(event.target)) {
      event.preventDefault();
      event.dataTransfer.dropEffect = 'copy';
    }
  });

In the preceding code, we call the checkTarget method to be sure that the target is in the right place to be dropped. In our case, the drop target must have the droppable attribute, as shown in the following code:

bool checkTarget(Element target) {
  return target.attributes.containsKey('droppable'),
}

However, it is common that the drop will be accepted or rejected based on the type of drag data within the dataTransfer property. In this case, we should check the property types of the dataTransfer property to decide whether the data can be accepted to be dropped. The code is as follows:

var dropTarget = querySelector("#sample_drop_id")
  ..onDragOver.listen((MouseEvent event) {
    if (checkTarget(event.target) && 
        checkTypes(event.dataTransfer.types)) {
      event.preventDefault();
      event.dataTransfer.dropEffect = 'copy';
    }
  });

In the following code, the checkTypes function accepts only the text/data types specified through the setData method of dataTransfer inside the listener of the dragstart event:

bool checkTypes(List<String> types) {
  return types.contains("text/data");
}

You can now run the web application, drag your box with the Drag me! text, and drop it inside the box with the Drop here text. Let's polish our application and change the text of the drop zone.

Finishing a drop

When a user releases the mouse, the drag-and-drop operation ends. If this happened over an element that was identified as a valid drop target, the drag-and-drop API will fire a drop event at the target. The dataTransfer property of the drop event holds the data that is being dragged. To retrieve the dragged data, we will use the getData method of the dataTransfer property, as follows:

var dropTarget = querySelector("#sample_drop_id")
..onDragOver.listen((MouseEvent event) {
  if (checkTarget(event.target) && 
      checkTypes(event.dataTransfer.types)) {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'copy';
  }
})
..onDrop.listen((MouseEvent event) {
  Element dropTarget = event.target;
  dropTarget.innerHtml = event.dataTransfer.getData('text/plain'),
  event.preventDefault();
});

The getData method will retrieve the string value that was set when the setData method was called. When an empty string is returned from getData, this means that data of the specified type does not exist. At the end of the getData method, you need to call the preventDefault method of the event if you have accepted the drop. Here is the result of the drag-and-drop operation:

Finishing a drop

Finishing a drag

Finally, when the drag operation is complete, the drag-and-drop API generates a dragend event at the source element that received the dragstart event. The API generates that event regardless of the result of the drag-and-drop operation. The value of the dropEffect property can tell us the exact result of the drag operation. If the value of the dropEffect property is none, then the drag was cancelled; otherwise, the specified effect holds the performed operation. The drag-and-drop operation is considered complete after dragevent is finished.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.51.157