Skip to content

Commit

Permalink
Fixes to drag operations page (mdn#20403)
Browse files Browse the repository at this point in the history
* Fixes to drag operations page

* Fix a typo

* Fix page title

* Update files/en-us/web/api/html_drag_and_drop_api/drag_operations/index.md

Co-authored-by: Jean-Yves Perrier <[email protected]>

Co-authored-by: Jean-Yves Perrier <[email protected]>
  • Loading branch information
2 people authored and Himanshu Garg committed Sep 27, 2022
1 parent 5732243 commit 0e0e969
Showing 1 changed file with 53 additions and 39 deletions.
92 changes: 53 additions & 39 deletions files/en-us/web/api/html_drag_and_drop_api/drag_operations/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Drag Operations
title: Drag operations
slug: Web/API/HTML_Drag_and_Drop_API/Drag_operations
page-type: guide
tags:
Expand All @@ -15,7 +15,7 @@ The following describes the steps that occur during a drag and drop operation.

The drag operations described in this document use the {{domxref("DataTransfer")}} interface. This document does _not_ use the {{domxref("DataTransferItem")}} interface nor the {{domxref("DataTransferItemList")}} interface.

## The `draggable` Attribute
## The draggable attribute

In a web page, there are certain cases where a default drag behavior is used. These include text selections, images, and links. When an image or link is dragged, the URL of the image or link is set as the drag data, and a drag begins. For other elements, they must be part of a selection for a default drag to occur. To see this in effect, select an area of a webpage, and then click and hold the mouse and drag the selection. An OS-specific rendering of the selection will appear and follow the mouse pointer as the drag occurs. However, this behavior is only the default drag behavior, if no listeners adjust the data to be dragged.

Expand All @@ -30,9 +30,15 @@ To make other HTML elements draggable, three things must be done:
Here is an example which allows a section of content to be dragged.

```html
<p draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
This text <strong>may</strong> be dragged.
</p>
<p draggable="true">This text <strong>may</strong> be dragged.</p>
```

```js
const draggableElement = document.querySelector('p[draggable="true"]');

draggableElement.addEventListener("dragstart", (event) =>
event.dataTransfer.setData("text/plain", "This text may be dragged")
);
```

The `{{htmlattrxref("draggable")}}` attribute is set to `"true"`, so this element becomes draggable. If this attribute were omitted or set to `"false"`, the element would not be dragged, and instead the text would be selected.
Expand All @@ -41,14 +47,19 @@ The `{{htmlattrxref("draggable")}}` attribute may be used on any element, includ

> **Note:** When an element is made draggable, text or other elements within it can no longer be selected in the normal way by clicking and dragging with the mouse. Instead, the user must hold down the <kbd>Alt</kbd> key to select text with the mouse, or use the keyboard.
## Starting a Drag Operation
## Starting a drag operation

In this example, a listener is added for the {{domxref("HTMLElement/dragstart_event", "dragstart")}} event by using the `ondragstart` attribute.
In this example, we add a listener for the {{domxref("HTMLElement/dragstart_event", "dragstart")}} event by using the `addEventListener()` method.

```html
<p draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
This text <strong>may</strong> be dragged.
</p>
<p draggable="true">This text <strong>may</strong> be dragged.</p>
```

```js
const draggableElement = document.querySelector('p[draggable="true"]');
draggableElement.addEventListener("dragstart", (event) =>
event.dataTransfer.setData("text/plain", "This text may be dragged")
);
```

When a user begins to drag, the {{domxref("HTMLElement/dragstart_event", "dragstart")}} event is fired.
Expand All @@ -57,7 +68,7 @@ In this example the {{domxref("HTMLElement/dragstart_event", "dragstart")}} list

Within the {{domxref("HTMLElement/dragstart_event", "dragstart")}} event, you can specify the **drag data**, the **feedback image**, and the **drag effects**, all of which are described below. However, only the **drag data** is required. (The default image and drag effects are suitable in most situations.)

## Drag Data
## Drag data

All {{domxref("DragEvent","drag events")}} have a property called {{domxref("DragEvent.dataTransfer","dataTransfer")}} which holds the drag data (`dataTransfer` is a {{domxref("DataTransfer")}} object).

Expand Down Expand Up @@ -128,14 +139,14 @@ function dragWithCustomImage(event) {
ctx.stroke();

const dt = event.dataTransfer;
dt.setData('text/plain', 'Data to Drag');
dt.setData("text/plain", "Data to Drag");
dt.setDragImage(canvas, 25, 25);
}
```

In this example, we make one canvas the drag image. As the canvas is `50`×`50` pixels, we use offsets of half of this (`25`) so that the image appears centered on the mouse pointer.

## Drag Effects
## Drag effects

When dragging, there are several operations that may be performed. The `copy` operation is used to indicate that the data being dragged will be copied from its present location to the drop location. The `move` operation is used to indicate that the data being dragged will be moved, and the `link` operation is used to indicate that some form of relationship or connection will be created between the source and drop locations.

Expand Down Expand Up @@ -186,15 +197,22 @@ You can use the value `none` to indicate that no drop is allowed at this locatio

Within the {{domxref("HTMLElement/drop_event", "drop")}} and {{domxref("HTMLElement/dragend_event", "dragend")}} events, you can check the {{domxref("DataTransfer.dropEffect","dropEffect")}} property to determine which effect was ultimately chosen. If the chosen effect were "`move`", then the original data should be removed from the source of the drag within the {{domxref("HTMLElement/dragend_event", "dragend")}} event.

## Specifying Drop Targets
## Specifying drop targets

A listener for the {{domxref("HTMLElement/dragenter_event", "dragenter")}} and {{domxref("HTMLElement/dragover_event", "dragover")}} events are used to indicate valid drop targets, that is, places where dragged items may be dropped. Most areas of a web page or application are not valid places to drop data. Thus, the default handling of these events is not to allow a drop.

If you want to allow a drop, you must prevent the default handling by cancelling both the `dragenter` and `dragover` events. You can do this either by returning `false` from attribute-defined event listeners, or by calling the event's {{domxref("Event.preventDefault","preventDefault()")}} method. The latter may be more feasible in a function defined in a separate script.
If you want to allow a drop, you must prevent the default behavior by cancelling both the `dragenter` and `dragover` events. You can do this by calling their {{domxref("Event.preventDefault","preventDefault()")}} methods:

```html
<div ondragover="return false">
<div ondragover="event.preventDefault()">
```js
const draggableElement = document.querySelector('p[draggable="true"]');

draggableElement.addEventListener("dragenter", (event) => {
event.preventDefault();
});

draggableElement.addEventListener("dragover", (event) => {
event.preventDefault();
});
```

Calling the {{domxref("Event.preventDefault","preventDefault()")}} method during both a {{domxref("HTMLElement/dragenter_event", "dragenter")}} and {{domxref("HTMLElement/dragover_event", "dragover")}} event will indicate that a drop is allowed at that location. However, you will commonly wish to call the {{domxref("Event.preventDefault","preventDefault()")}} method only in certain situations (for example, only if a link is being dragged).
Expand All @@ -216,31 +234,19 @@ In this example, we use the `includes` method to check if the type [`text/uri-li

You may also wish to set either the {{domxref("DataTransfer.effectAllowed","effectAllowed")}}, {{domxref("DataTransfer.dropEffect","dropEffect")}} property, or both at the same time, if you wish to be more specific about the type of operation that will performed. Naturally, changing either property will have no effect if you do not cancel the event as well.

## Drop Feedback
## Drop feedback

There are several ways in which you can indicate to the user that a drop is allowed at a certain location. The mouse pointer will update as necessary depending on the value of the {{domxref("DataTransfer.dropEffect","dropEffect")}} property.

Although the exact appearance depends on the user's platform, typically a plus sign icon will appear for a '`copy`' for example, and a 'cannot drop here' icon will appear when a drop is not allowed. This mouse pointer feedback is sufficient in many cases.

However, you can also update the user interface with an insertion point or highlight as needed. For simple highlighting, you can use the `:-moz-drag-over` CSS pseudoclass on a drop target.

```css
.droparea:-moz-drag-over {
outline: 1px solid black;
}
```

In this example, the element with the class `droparea` will receive a 1 pixel black outline while it is a valid drop target, that is, if the {{domxref("Event.preventDefault","preventDefault()")}} method was called during the {{domxref("HTMLElement/dragenter_event", "dragenter")}} event.

> **Note:** You must cancel the {{domxref("HTMLElement/dragenter_event", "dragenter")}} event for this pseudoclass to apply, as this state is not checked for the {{domxref("HTMLElement/dragover_event", "dragover")}} event.
For more complex visual effects, you can also perform other operations during the {{domxref("HTMLElement/dragenter_event", "dragenter")}} event. For example, by inserting an element at the location where the drop will occur. This might be an insertion marker, or an element that represents the dragged element in its new location. To do this, you could create an [image](/en-US/docs/XUL/image) or [separator](/en-US/docs/XUL/separator) element and insert it into the document during the {{domxref("HTMLElement/dragenter_event", "dragenter")}} event.
For more complex visual effects, you can perform other operations during the {{domxref("HTMLElement/dragenter_event", "dragenter")}} event. For example, by inserting an element at the location where the drop will occur. This might be an insertion marker, or an element that represents the dragged element in its new location. To do this, you could create an [`<img>`](/en-US/docs/Web/HTML/Element/img) element and insert it into the document during the {{domxref("HTMLElement/dragenter_event", "dragenter")}} event.

The {{domxref("HTMLElement/dragover_event", "dragover")}} event will fire at the element the mouse is pointing at. Naturally, you may need to move the insertion marker around a {{domxref("HTMLElement/dragover_event", "dragover")}} event as well. You can use the event's {{domxref("MouseEvent.clientX","clientX")}} and {{domxref("MouseEvent.clientY","clientY")}} properties as with other mouse events to determine the location of the mouse pointer.

Finally, the {{domxref("HTMLElement/dragleave_event", "dragleave")}} event will fire at an element when the drag leaves the element. This is the time when you should remove any insertion markers or highlighting. You do not need to cancel this event. Any highlighting or other visual effects specified using the `:-moz-drag-over` pseudoclass will be removed automatically. The {{domxref("HTMLElement/dragleave_event", "dragleave")}} event will always fire, even if the drag is cancelled, so you can always ensure that any insertion point cleanup can be done during this event.
Finally, the {{domxref("HTMLElement/dragleave_event", "dragleave")}} event will fire at an element when the drag leaves the element. This is the time when you should remove any insertion markers or highlighting. You do not need to cancel this event. The {{domxref("HTMLElement/dragleave_event", "dragleave")}} event will always fire, even if the drag is cancelled, so you can always ensure that any insertion point cleanup can be done during this event.

## Performing a Drop
## Performing a drop

When the user releases the mouse, the drag and drop operation ends.

Expand Down Expand Up @@ -269,13 +275,14 @@ You can retrieve other types of data as well. If the data is a link, it should h
```js
function doDrop(event) {
const lines = event.dataTransfer.getData("text/uri-list").split("\n");
lines.filter((line) => !line.startsWith("#"))
lines
.filter((line) => !line.startsWith("#"))
.forEach((line) => {
const link = document.createElement("a");
link.href = line;
link.textContent = line;
event.target.appendChild(link);
})
});
event.preventDefault();
}
```
Expand All @@ -298,16 +305,23 @@ The following example returns the data associated with the best-supported format

```js
function doDrop(event) {
const supportedTypes = ["application/x-moz-file", "text/uri-list", "text/plain"];
const types = event.dataTransfer.types.filter((type) => supportedTypes.includes(type));
const supportedTypes = [
"application/x-moz-file",
"text/uri-list",
"text/plain",
];
const types = event.dataTransfer.types.filter((type) =>
supportedTypes.includes(type)
);
if (types.length) {
const data = event.dataTransfer.getData(types[0]);
// Use this type of data…
}
event.preventDefault();
}
```

## Finishing a Drag
## Finishing a drag

Once the drag is complete, a {{domxref("HTMLElement/dragend_event", "dragend")}} event is fired at the source of the drag (the same element that received the {{domxref("HTMLElement/dragstart_event", "dragstart")}} event). This event will fire if the drag was successful or if it was cancelled. However, you can use the {{domxref("DataTransfer.dropEffect","dropEffect")}} property to determine which drop operation occurred.

Expand Down

0 comments on commit 0e0e969

Please sign in to comment.