← 7 User interactionTable of contents8 The HTML syntax →
    1. 7.9 Drag and drop
      1. 7.9.1 Introduction
      2. 7.9.2 The DragEvent and DataTransfer interfaces
      3. 7.9.3 Events fired during a drag-and-drop action
      4. 7.9.4 Drag-and-drop processing model
        1. 7.9.4.1 When the drag-and-drop operation starts or ends in another document
        2. 7.9.4.2 When the drag-and-drop operation starts or ends in another application
      5. 7.9.5 The draggable attribute
      6. 7.9.6 Security risks in the drag-and-drop model
    2. 7.10 Undo history
      1. 7.10.1 Definitions
      2. 7.10.2 The UndoManager interface
      3. 7.10.3 Undo: moving back in the undo transaction history
      4. 7.10.4 Redo: moving forward in the undo transaction history
      5. 7.10.5 The UndoManagerEvent interface and the undo and redo events
      6. 7.10.6 Implementation notes
    3. 7.11 Editing APIs

7.9 Drag and drop

Status: Last call for comments

This section defines an event-based drag-and-drop mechanism.

This specification does not define exactly what a drag-and-drop operation actually is.

On a visual medium with a pointing device, a drag operation could be the default action of a mousedown event that is followed by a series of mousemove events, and the drop could be triggered by the mouse being released.

On media without a pointing device, the user would probably have to explicitly indicate his intention to perform a drag-and-drop operation, stating what he wishes to drag and what he wishes to drop, respectively.

However it is implemented, drag-and-drop operations must have a starting point (e.g. where the mouse was clicked, or the start of the selection or element that was selected for the drag), may have any number of intermediate steps (elements that the mouse moves over during a drag, or elements that the user picks as possible drop points as he cycles through possibilities), and must either have an end point (the element above which the mouse button was released, or the element that was finally selected), or be canceled. The end point must be the last element selected as a possible drop point before the drop occurs (so if the operation is not canceled, there must be at least one element in the middle step).

7.9.1 Introduction

Status: Last call for comments

This section is non-normative.

To make an element draggable is simple: give the element a draggable attribute, and set an event listener for dragstart that stores the data being dragged.

The event handler typically needs to check that it's not a text selection that is being dragged, and then needs to store data into the DataTransfer object and set the allowed effects (copy, move, link, or some combination).

For example:

<p>What fruits do you like?</p>
<ol ondragstart="dragStartHandler(event)">
 <li draggable data-value="fruit-apple">Apples</li>
 <li draggable data-value="fruit-orange">Oranges</li>
 <li draggable data-value="fruit-pear">Pears</li>
</ol>
<script>
  var internalDNDType = 'text/x-example'; // set this to something specific to your site
  function dragStartHandler(event) {
    if (event.target instanceof HTMLLIElement) {
      // use the element's data-value="" attribute as the value to be moving:
      event.dataTransfer.setData(internalDNDType, event.target.dataset.value);
      event.effectAllowed = 'move'; // only allow moves
    } else {
      event.preventDefault(); // don't allow selection to be dragged
    }
  }
</script>

To accept a drop, the drop target has to listen to at least three events. First, the dragenter event, which is used to determine whether or not the drop target is to accept the drop. If the drop is to be accepted, then this event has to be canceled. Second, the dragover event, which is used to determine what feedback is to be shown to the user. If the event is canceled, then the feedback (typically the cursor) is updated based on the dropEffect attribute's value, as set by the event handler; otherwise, the default behavior (typically to do nothing) is used instead. Finally, the drop event, which allows the actual drop to be performed. This event also needs to be canceled, so that the dropEffect attribute's value can be used by the source (otherwise it's reset).

For example:

<p>Drop your favorite fruits below:</p>
<ol class="dropzone"
    ondragenter="dragEnterHandler(event)"
    ondragover="dragOverHandler(event)"
    ondrop="dropHandler(event)">
</ol>
<script>
  var internalDNDType = 'text/x-example'; // set this to something specific to your site
  function dragEnterHandler(event) {
    // cancel the event if the drag contains data of our type
    if (event.dataTransfer.types.contains(internalDNDType))
      event.preventDefault();
  }
  function dragOverHandler(event) {
    event.dataTransfer.dropEffect = 'move';
    event.preventDefault();
  }
  function dropHandler(event) {
    // drop the data
    var li = document.createElement('li');
    var data = event.dataTransfer.getData(internalDNDType);
    if (data == 'fruit-apple') {
      li.textContent = 'Apples';
    } else if (data == 'fruit-orange') {
      li.textContent = 'Oranges';
    } else if (data == 'fruit-pear') {
      li.textContent = 'Pears';
    } else {
      li.textContent = 'Unknown Fruit';
    }
    event.target.appendChild(li);
  }
</script>

To remove the original element (the one that was dragged) from the display, the dragend event can be used.

For our example here, that means updating the original markup to handle that event:

<p>What fruits do you like?</p>
<ol ondragstart="dragStartHandler(event)" ondragend="dragEndHandler(event)">
 ...as before...
</ol>
<script>
  function dragStartHandler(event) {
    // ...as before...
  }
  function dragEndHandler(event) {
    // remove the dragged element
    event.target.parentNode.removeChild(event.target);
  }
</script>

7.9.2 The DragEvent and DataTransfer interfaces

Status: Last call for comments

The drag-and-drop processing model involves several events. They all use the DragEvent interface.

interface DragEvent : MouseEvent {
  readonly attribute DataTransfer dataTransfer;

  void initDragEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in any dummyArg, in long detailArg, in long screenXArg, in long screenYArg, in long clientXArg, in long clientYArg, in boolean ctrlKeyArg, in boolean altKeyArg, in boolean shiftKeyArg, in boolean metaKeyArg, in unsigned short buttonArg, in EventTarget relatedTargetArg, in DataTransfer dataTransferArg);
};
event . dataTransfer

Returns the DataTransfer object for the event.

The initDragEvent() method must initialize the event in a manner analogous to the similarly-named method in the DOM Events interfaces, except that the dummyArg argument must be ignored. [DOMEVENTS]

The dataTransfer attribute of the DragEvent interface represents the context information for the event.

interface DataTransfer {
           attribute DOMString dropEffect;
           attribute DOMString effectAllowed;

  readonly attribute DOMStringList types;
  void clearData(in optional DOMString format);
  void setData(in DOMString format, in DOMString data);
  DOMString getData(in DOMString format);
  readonly attribute FileList files;

  void setDragImage(in Element image, in long x, in long y);
  void addElement(in Element element);
};

DataTransfer objects can hold pieces of data, each associated with a unique format. Formats are generally given by MIME types, with some values special-cased for legacy reasons. However, the API does not enforce this; non-MIME-type values can be added as well. All formats are identified by strings that are converted to ASCII lowercase by the API.

dataTransfer . dropEffect [ = value ]

Returns the kind of operation that is currently selected. If the kind of operation isn't one of those that is allowed by the effectAllowed attribute, then the operation will fail.

Can be set, to change the selected operation.

The possible values are none, copy, link, and move.

dataTransfer . effectAllowed [ = value ]

Returns the kinds of operations that are to be allowed.

Can be set, to change the allowed operations.

The possible values are none, copy, copyLink, copyMove, link, linkMove, move, all, and uninitialized,

dataTransfer . types

Returns a DOMStringList listing the formats that were set in the dragstart event. In addition, if any files are being dragged, then one of the types will be the string "Files".

dataTransfer . clearData( [ format ] )

Removes the data of the specified formats. Removes all data if the argument is omitted.

dataTransfer . setData(format, data)

Adds the specified data.

data = dataTransfer . getData(format)

Returns the specified data. If there is no such data, returns the empty string.

dataTransfer . files

Returns a FileList of the files being dragged, if any.

dataTransfer . setDragImage(element, x, y)

Uses the given element to update the drag feedback, replacing any previously specified feedback.

dataTransfer . addElement(element)

Adds the given element to the list of elements used to render the drag feedback.

When a DataTransfer object is created, it must be initialized as follows:

The dropEffect attribute controls the drag-and-drop feedback that the user is given during a drag-and-drop operation.

The attribute must ignore any attempts to set it to a value other than none, copy, link, and move. On getting, the attribute must return the last of those four values that it was set to.

The effectAllowed attribute is used in the drag-and-drop processing model to initialize the dropEffect attribute during the dragenter and dragover events.

The attribute must ignore any attempts to set it to a value other than none, copy, copyLink, copyMove, link, linkMove, move, all, and uninitialized. On getting, the attribute must return the last of those values that it was set to.

The types attribute must return a live DOMStringList that contains the list of formats that were added to the DataTransfer object in the corresponding dragstart event. The same object must be returned each time. If any files were included in the drag, then the DOMStringList object must in addition include the string "Files". (This value can be distinguished from the other values because it is not lowercase.)

The clearData() method, when called with no arguments, must clear the DataTransfer object of all data (for all formats).

The clearData() method does not affect whether any files were included in the drag, so the types attribute's list might still not be empty after calling clearData() (it would still contain the "Files" string if any files were included in the drag).

When called with an argument, the clearData(format) method must clear the DataTransfer object of any data associated with the given format, converted to ASCII lowercase. If format (after conversion to lowercase) is the value "text", then it must be treated as "text/plain". If the format (after conversion to lowercase) is "url", then it must be treated as "text/uri-list".

The setData(format, data) method must add data to the data stored in the DataTransfer object, labeled as being of the type format, converted to ASCII lowercase. This must replace any previous data that had been set for that format. If format (after conversion to lowercase) is the value "text", then it must be treated as "text/plain". If the format (after conversion to lowercase) is "url", then it must be treated as "text/uri-list".

The getData(format) method must return the data that is associated with the type format converted to ASCII lowercase, if any, and must return the empty string otherwise. If format (after conversion to lowercase) is the value "text", then it must be treated as "text/plain". If the format (after conversion to lowercase) is "url", then the data associated with the "text/uri-list" format must be parsed as appropriate for text/uri-list data, and the first URL from the list must be returned. If there is no data with that format, or if there is but it has no URLs, then the method must return the empty string. [RFC2483]

The files attribute must return the FileList object that contains the files that are stored in the DataTransfer object. There is one such object per DataTransfer object.

This version of the API does not expose the types of the files during the drag.

The setDragImage(element, x, y) method sets which element to use to generate the drag feedback. The element argument can be any Element; if it is an img element, then the user agent should use the element's image (at its intrinsic size) to generate the feedback, otherwise the user agent should base the feedback on the given element (but the exact mechanism for doing so is not specified).

The addElement(element) method is an alternative way of specifying how the user agent is to render the drag feedback. It adds an element to the DataTransfer object.

The difference between setDragImage() and addElement() is that the latter automatically generates the image based on the current rendering of the elements added, whereas the former uses the exact specified image.

7.9.3 Events fired during a drag-and-drop action

Status: Last call for comments

The following events are involved in the drag-and-drop model.

Whenever the processing model described below causes one of these events to be fired, the event fired must use the DragEvent interface defined above, must have the bubbling and cancelable behaviors given in the table below, and must have the context information set up as described after the table, with the detail attribute set to zero, the mouse and key attributes set according to the state of the input devices as they would be for user interaction events, and the relatedTarget attribute set to null.

If there is no relevant pointing device, the object must have its screenX, screenY, clientX, clientY, and button attributes set to 0.

Event Name Target Bubbles? Cancelable? dataTransfer effectAllowed dropEffect Default Action
dragstart Source node ✓ Bubbles ✓ Cancelable Contains source node unless a selection is being dragged, in which case it is empty; files returns any files included in the drag operation uninitialized none Initiate the drag-and-drop operation
drag Source node ✓ Bubbles ✓ Cancelable Empty Same as last event none Continue the drag-and-drop operation
dragenter Immediate user selection or the body element ✓ Bubbles ✓ Cancelable Empty Same as last event Based on effectAllowed value Reject immediate user selection as potential target element
dragleave Previous target element ✓ Bubbles Empty Same as last event none None
dragover Current target element ✓ Bubbles ✓ Cancelable Empty Same as last event Based on effectAllowed value Reset the current drag operation to "none"
drop Current target element ✓ Bubbles ✓ Cancelable getData() returns data set in dragstart event; files returns any files included in the drag operation Same as last event Current drag operation Varies
dragend Source node ✓ Bubbles Empty Same as last event Current drag operation Varies

"Empty" in the table above means that the getData() and files attributes act as if there is no data being dragged.

The dataTransfer object's contents are empty (the getData() and files attributes act as if there is no data being dragged) except for dragstart events and drop events, for which the contents are set as described in the processing model, below.

The effectAllowed attribute must be set to "uninitialized" for dragstart events, and to whatever value the field had after the last drag-and-drop event was fired for all other events (only counting events fired by the user agent for the purposes of the drag-and-drop model described below).

The dropEffect attribute must be set to "none" for dragstart, drag, and dragleave events (except when stated otherwise in the algorithms given in the sections below), to the value corresponding to the current drag operation for drop and dragend events, and to a value based on the effectAllowed attribute's value and to the drag-and-drop source, as given by the following table, for the remaining events (dragenter and dragover):

effectAllowed dropEffect
none none
copy, copyLink, copyMove, all copy
link, linkMove link
move move
uninitialized when what is being dragged is a selection from a text field move
uninitialized when what is being dragged is a selection copy
uninitialized when what is being dragged is an a element with an href attribute link
Any other case copy

7.9.4 Drag-and-drop processing model

Status: Last call for comments

When the user attempts to begin a drag operation, the user agent must first determine what is being dragged. If the drag operation was invoked on a selection, then it is the selection that is being dragged. Otherwise, it is the first element, going up the ancestor chain, starting at the node that the user tried to drag, that has the IDL attribute draggable set to true. If there is no such element, then nothing is being dragged, the drag-and-drop operation is never started, and the user agent must not continue with this algorithm.

img elements and a elements with an href attribute have their draggable attribute set to true by default.

If the user agent determines that something can be dragged, a dragstart event must then be fired at the source node.

The source node depends on the kind of drag and how it was initiated. If it is a selection that is being dragged, then the source node is the text node that the user started the drag on (typically the text node that the user originally clicked). If the user did not specify a particular node, for example if the user just told the user agent to begin a drag of "the selection", then the source node is the first text node containing a part of the selection. If it is not a selection that is being dragged, then the source node is the element that is being dragged.

Multiple events are fired on the source node during the course of the drag-and-drop operation.


The list of dragged nodes also depends on the kind of drag. If it is a selection that is being dragged, then the list of dragged nodes contains, in tree order, every node that is partially or completely included in the selection (including all their ancestors). Otherwise, the list of dragged nodes contains only the source node.


If it is a selection that is being dragged, the dataTransfer member of the event must be created with no nodes. Otherwise, it must be created containing just the source node. Script can use the addElement() method to add further elements to the list of what is being dragged. (This list is only used for rendering the drag feedback.)

The dataTransfer member of the event also has data added to it, as follows:


If the event is canceled, then the drag-and-drop operation must not occur; the user agent must not continue with this algorithm.

If it is not canceled, then the drag-and-drop operation must be initiated.

Since events with no event listeners registered are, almost by definition, never canceled, drag-and-drop is always available to the user if the author does not specifically prevent it.

The drag-and-drop feedback must be generated from the first of the following sources that is available:

  1. The element specified in the last call to the setDragImage() method of the dataTransfer object of the dragstart event, if the method was called. In visual media, if this is used, the x and y arguments that were passed to that method should be used as hints for where to put the cursor relative to the resulting image. The values are expressed as distances in CSS pixels from the left side and from the top side of the image respectively. [CSS]
  2. The elements that were added to the dataTransfer object, both before the event was fired, and during the handling of the event using the addElement() method, if any such elements were indeed added.
  3. The selection that the user is dragging.

The user agent must take a note of the data that was placed in the dataTransfer object. This data will be made available again when the drop event is fired.

From this point until the end of the drag-and-drop operation, device input events (e.g. mouse and keyboard events) must be suppressed. In addition, the user agent must track all DOM changes made during the drag-and-drop operation, and add them to its undo history as one atomic operation once the drag-and-drop operation has ended.

During the drag operation, the element directly indicated by the user as the drop target is called the immediate user selection. (Only elements can be selected by the user; other nodes must not be made available as drop targets.) However, the immediate user selection is not necessarily the current target element, which is the element currently selected for the drop part of the drag-and-drop operation. The immediate user selection changes as the user selects different elements (either by pointing at them with a pointing device, or by selecting them in some other way). The current target element changes when the immediate user selection changes, based on the results of event listeners in the document, as described below.

Both the current target element and the immediate user selection can be null, which means no target element is selected. They can also both be elements in other (DOM-based) documents, or other (non-Web) programs altogether. (For example, a user could drag text to a word-processor.) The current target element is initially null.

In addition, there is also a current drag operation, which can take on the values "none", "copy", "link", and "move". Initially, it has the value "none". It is updated by the user agent as described in the steps below.

User agents must, as soon as the drag operation is initiated and every 350ms (±200ms) thereafter for as long as the drag operation is ongoing, queue a task to perform the following steps in sequence:

  1. If the user agent is still performing the previous iteration of the sequence (if any) when the next iteration becomes due, the user agent must not execute the overdue iteration, effectively "skipping missed frames" of the drag-and-drop operation.

  2. The user agent must fire a drag event at the source node. If this event is canceled, the user agent must set the current drag operation to none (no drag operation).

  3. Next, if the drag event was not canceled and the user has not ended the drag-and-drop operation, the user agent must check the state of the drag-and-drop operation, as follows:

    1. First, if the user is indicating a different immediate user selection than during the last iteration (or if this is the first iteration), and if this immediate user selection is not the same as the current target element, then the current target element must be updated, as follows:

      If the new immediate user selection is null, or is in a non-DOM document or application

      The user agent must set the current target element to the same value.

      Otherwise

      The user agent must fire a dragenter event at the immediate user selection.

      If the event is canceled, then the current target element must be set to the immediate user selection.

      Otherwise, the user agent must act as follows:

      If the current target element is a text field (e.g. textarea, or an input element whose type attribute is in the Text state) or an editable element

      The current target element must be set to the immediate user selection anyway.

      If the current target element is the body element

      The current target element is left unchanged.

      Otherwise

      The user agent must fire a dragenter event at the body element, and the current target element must be set to the body element, regardless of whether that event was canceled or not. (If the body element is null, then the current target element would be set to null too in this case, it wouldn't be set to the Document object.)

    2. If the previous step caused the current target element to change, and if the previous target element was not null or a part of a non-DOM document, the user agent must fire a dragleave event at the previous target element.

    3. If the current target element is a DOM element, the user agent must fire a dragover event at this current target element.

      If the dragover event is not canceled, the user agent must act as follows:

      If the current target element is a text field (e.g. textarea, or an input element whose type attribute is in the Text state) or an editable element

      The user agent must set the current drag operation to either "copy" or "move", as appropriate given the platform conventions.

      Otherwise

      The user agent must reset the current drag operation to "none".

      Otherwise (if the dragover event is canceled), the current drag operation must be set based on the values the effectAllowed and dropEffect attributes of the dataTransfer object had after the event was handled, as per the following table:

      effectAllowed dropEffect Drag operation
      uninitialized, copy, copyLink, copyMove, or all copy "copy"
      uninitialized, link, copyLink, linkMove, or all link "link"
      uninitialized, move, copyMove, linkMove, or all move "move"
      Any other case "none"

      Then, regardless of whether the dragover event was canceled or not, the drag feedback (e.g. the mouse cursor) must be updated to match the current drag operation, as follows:

      Drag operation Feedback
      "copy" Data will be copied if dropped here.
      "link" Data will be linked if dropped here.
      "move" Data will be moved if dropped here.
      "none" No operation allowed, dropping here will cancel the drag-and-drop operation.
    4. Otherwise, if the current target element is not a DOM element, the user agent must use platform-specific mechanisms to determine what drag operation is being performed (none, copy, link, or move). This sets the current drag operation.

  4. Otherwise, if the user ended the drag-and-drop operation (e.g. by releasing the mouse button in a mouse-driven drag-and-drop interface), or if the drag event was canceled, then this will be the last iteration. The user agent must execute the following steps, then stop looping.

    1. If the current drag operation is none (no drag operation), or, if the user ended the drag-and-drop operation by canceling it (e.g. by hitting the Escape key), or if the current target element is null, then the drag operation failed. If the current target element is a DOM element, the user agent must fire a dragleave event at it; otherwise, if it is not null, it must use platform-specific conventions for drag cancellation.

    2. Otherwise, the drag operation was as success. If the current target element is a DOM element, the user agent must fire a drop event at it; otherwise, it must use platform-specific conventions for indicating a drop.

      When the target is a DOM element, the dropEffect attribute of the event's dataTransfer object must be given the value representing the current drag operation (copy, link, or move), and the object must be set up so that the getData() method will return the data that was added during the dragstart event, and the files attribute will return a FileList object with any files that were dragged.

      If the event is canceled, the current drag operation must be set to the value of the dropEffect attribute of the event's dataTransfer object as it stood after the event was handled.

      Otherwise, the event is not canceled, and the user agent must perform the event's default action, which depends on the exact target as follows:

      If the current target element is a text field (e.g. textarea, or an input element whose type attribute is in the Text state) or an editable element
      The user agent must insert the data associated with the text/plain format, if any, into the text field or editable element in a manner consistent with platform-specific conventions (e.g. inserting it at the current mouse cursor position, or inserting it at the end of the field).
      Otherwise
      Reset the current drag operation to "none".
    3. Finally, the user agent must fire a dragend event at the source node, with the dropEffect attribute of the event's dataTransfer object being set to the value corresponding to the current drag operation.

      The current drag operation can change during the processing of the drop event, if one was fired.

      The event is not cancelable. After the event has been handled, the user agent must act as follows:

      If the current target element is a text field (e.g. textarea, or an input element whose type attribute is in the Text state), and a drop event was fired in the previous step, and the current drag operation is "move", and the source of the drag-and-drop operation is a selection in the DOM
      The user agent should delete the range representing the dragged selection from the DOM.
      If the current target element is a text field (e.g. textarea, or an input element whose type attribute is in the Text state), and a drop event was fired in the previous step, and the current drag operation is "move", and the source of the drag-and-drop operation is a selection in a text field
      The user agent should delete the dragged selection from the relevant text field.
      Otherwise
      The event has no default action.
7.9.4.1 When the drag-and-drop operation starts or ends in another document

Status: Last call for comments

The model described above is independent of which Document object the nodes involved are from; the events must be fired as described above and the rest of the processing model must be followed as described above, irrespective of how many documents are involved in the operation.

7.9.4.2 When the drag-and-drop operation starts or ends in another application

Status: Last call for comments

If the drag is initiated in another application, the source node is not a DOM node, and the user agent must use platform-specific conventions instead when the requirements above involve the source node. User agents in this situation must act as if the dragged data had been added to the DataTransfer object when the drag started, even though no dragstart event was actually fired; user agents must similarly use platform-specific conventions when deciding on what drag feedback to use.

All the format strings must be converted to ASCII lowercase. If the platform conventions do not use MIME types to label the dragged data, the user agent must map the types to MIME types first.

If a drag is started in a document but ends in another application, then the user agent must instead replace the parts of the processing model relating to handling the target according to platform-specific conventions.

In any case, scripts running in the context of the document must not be able to distinguish the case of a drag-and-drop operation being started or ended in another application from the case of a drag-and-drop operation being started or ended in another document from another domain.

7.9.5 The draggable attribute

Status: Last call for comments

All HTML elements may have the draggable content attribute set. The draggable attribute is an enumerated attribute. It has three states. The first state is true and it has the keyword true. The second state is false and it has the keyword false. The third state is auto; it has no keywords but it is the missing value default.

The true state means the element is draggable; the false state means that it is not. The auto state uses the default behavior of the user agent.

element . draggable [ = value ]

Returns true if the element is draggable; otherwise, returns false.

Can be set, to override the default and set the draggable content attribute.

The draggable IDL attribute, whose value depends on the content attribute's in the way described below, controls whether or not the element is draggable. Generally, only text selections are draggable, but elements whose draggable IDL attribute is true become draggable as well.

If an element's draggable content attribute has the state true, the draggable IDL attribute must return true.

Otherwise, if the element's draggable content attribute has the state false, the draggable IDL attribute must return false.

Otherwise, the element's draggable content attribute has the state auto. If the element is an img element, or, if the element is an a element with an href content attribute, the draggable IDL attribute must return true.

Otherwise, the draggable DOM must return false.

If the draggable IDL attribute is set to the value false, the draggable content attribute must be set to the literal value false. If the draggable IDL attribute is set to the value true, the draggable content attribute must be set to the literal value true.

7.9.6 Security risks in the drag-and-drop model

Status: Last call for comments

User agents must not make the data added to the DataTransfer object during the dragstart event available to scripts until the drop event, because otherwise, if a user were to drag sensitive information from one document to a second document, crossing a hostile third document in the process, the hostile document could intercept the data.

For the same reason, user agents must consider a drop to be successful only if the user specifically ended the drag operation — if any scripts end the drag operation, it must be considered unsuccessful (canceled) and the drop event must not be fired.

User agents should take care to not start drag-and-drop operations in response to script actions. For example, in a mouse-and-window environment, if a script moves a window while the user has his mouse button depressed, the UA would not consider that to start a drag. This is important because otherwise UAs could cause data to be dragged from sensitive sources and dropped into hostile documents without the user's consent.

7.10 Undo history

Status: Last call for comments

7.10.1 Definitions

Status: Last call for comments

The user agent must associate an undo transaction history with each HTMLDocument object.

The undo transaction history is a list of entries. The entries are of two types: DOM changes and undo objects.

Each DOM changes entry in the undo transaction history consists of batches of one or more of the following:

Undo object entries consist of objects representing state that scripts running in the document are managing. For example, a Web mail application could use an undo object to keep track of the fact that a user has moved an e-mail to a particular folder, so that the user can undo the action and have the e-mail return to its former location.

Broadly speaking, DOM changes entries are handled by the UA in response to user edits of form controls and editing hosts on the page, and undo object entries are handled by script in response to higher-level user actions (such as interactions with server-side state, or in the implementation of a drawing tool).

7.10.2 The UndoManager interface

Status: Last call for comments

To manage undo object entries in the undo transaction history, the UndoManager interface can be used:

interface UndoManager {
  readonly attribute unsigned long length;
  getter any item(in unsigned long index);
  readonly attribute unsigned long position;
  unsigned long add(in any data, in DOMString title);
  void remove(in unsigned long index);
  void clearUndo();
  void clearRedo();
};
window . undoManager

Returns the UndoManager object.

undoManager . length

Returns the number of entries in the undo history.

data = undoManager . item(index)
undoManager[index]

Returns the entry with index index in the undo history.

Returns null if index is out of range.

undoManager . position

Returns the number of the current entry in the undo history. (Entries at and past this point are redo entries.)

undoManager . add(data, title)

Adds the specified entry to the undo history.

undoManager . remove(index)

Removes the specified entry to the undo history.

Throws an INDEX_SIZE_ERR exception if the given index is out of range.

undoManager . clearUndo()

Removes all entries before the current position in the undo history.

undoManager . clearRedo()

Removes all entries at and after the current position in the undo history.

The undoManager attribute of the Window interface must return the object implementing the UndoManager interface for that Window object's associated HTMLDocument object.

UndoManager objects represent their document's undo transaction history. Only undo object entries are visible with this API, but this does not mean that DOM changes entries are absent from the undo transaction history.

The length attribute must return the number of undo object entries in the undo transaction history. This is the length.

The object's indices of the supported indexed properties are the numbers in the range zero to length-1, unless the length is zero, in which case there are no supported indexed properties.

The item(n) method must return the nth undo object entry in the undo transaction history, if there is one, or null otherwise.

The undo transaction history has a current position. This is the position between two entries in the undo transaction history's list where the previous entry represents what needs to happen if the user invokes the "undo" command (the "undo" side, lower numbers), and the next entry represents what needs to happen if the user invokes the "redo" command (the "redo" side, higher numbers).

The position attribute must return the index of the undo object entry nearest to the undo position, on the "redo" side. If there are no undo object entries on the "redo" side, then the attribute must return the same as the length attribute. If there are no undo object entries on the "undo" side of the undo position, the position attribute returns zero.

Since the undo transaction history contains both undo object entries and DOM changes entries, but the position attribute only returns indices relative to undo object entries, it is possible for several "undo" or "redo" actions to be performed without the value of the position attribute changing.

The add(data, title) method's behavior depends on the current state. Normally, it must insert the data object passed as an argument into the undo transaction history immediately before the undo position, optionally remembering the given title to use in the UI. If the method is called during an undo operation, however, the object must instead be added immediately after the undo position.

If the method is called and there is neither an undo operation in progress nor a redo operation in progress then any entries in the undo transaction history after the undo position must be removed (as if clearRedo() had been called).

The remove(index) method must remove the undo object entry with the specified index. If the index is less than zero or greater than or equal to length then the method must raise an INDEX_SIZE_ERR exception. DOM changes entries are unaffected by this method.

The clearUndo() method must remove all entries in the undo transaction history before the undo position, be they DOM changes entries or undo object entries.

The clearRedo() method must remove all entries in the undo transaction history after the undo position, be they DOM changes entries or undo object entries.

7.10.3 Undo: moving back in the undo transaction history

Status: Last call for comments

When the user invokes an undo operation, or when the execCommand() method is called with the undo command, the user agent must perform an undo operation.

If the undo position is at the start of the undo transaction history, then the user agent must do nothing.

If the entry immediately before the undo position is a DOM changes entry, then the user agent must remove that DOM changes entry, reverse the DOM changes that were listed in that entry, and, if the changes were reversed with no problems, add a new DOM changes entry (consisting of the opposite of those DOM changes) to the undo transaction history on the other side of the undo position.

If the DOM changes cannot be undone (e.g. because the DOM state is no longer consistent with the changes represented in the entry), then the user agent must simply remove the DOM changes entry, without doing anything else.

If the entry immediately before the undo position is an undo object entry, then the user agent must first remove that undo object entry from the undo transaction history, and then must fire an undo event at the Window object, using the undo object entry's associated undo object as the event's data.

Any calls to add() while the event is being handled will be used to populate the redo history, and will then be used if the user invokes the "redo" command to undo his undo.

7.10.4 Redo: moving forward in the undo transaction history

Status: Last call for comments

When the user invokes a redo operation, or when the execCommand() method is called with the redo command, the user agent must perform a redo operation.

This is mostly the opposite of an undo operation, but the full definition is included here for completeness.

If the undo position is at the end of the undo transaction history, then the user agent must do nothing.

If the entry immediately after the undo position is a DOM changes entry, then the user agent must remove that DOM changes entry, reverse the DOM changes that were listed in that entry, and, if the changes were reversed with no problems, add a new DOM changes entry (consisting of the opposite of those DOM changes) to the undo transaction history on the other side of the undo position.

If the DOM changes cannot be redone (e.g. because the DOM state is no longer consistent with the changes represented in the entry), then the user agent must simply remove the DOM changes entry, without doing anything else.

If the entry immediately after the undo position is an undo object entry, then the user agent must first remove that undo object entry from the undo transaction history, and then must fire a redo event at the Window object, using the undo object entry's associated undo object as the event's data.

7.10.5 The UndoManagerEvent interface and the undo and redo events

Status: Last call for comments

interface UndoManagerEvent : Event {
  readonly attribute any data;
  void initUndoManagerEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in any dataArg);
};
event . data

Returns the data that was passed to the add() method.

The initUndoManagerEvent() method must initialize the event in a manner analogous to the similarly-named method in the DOM Events interfaces. [DOMEVENTS]

The data attribute represents the undo object for the event.

The undo and redo events do not bubble, cannot be canceled, and have no default action. When the user agent fires one of these events it must use the UndoManagerEvent interface, with the data field containing the relevant undo object.

7.10.6 Implementation notes

Status: Last call for comments

How user agents present the above conceptual model to the user is not defined. The undo interface could be a filtered view of the undo transaction history, it could manipulate the undo transaction history in ways not described above, and so forth. For example, it is possible to design a UA that appears to have separate undo transaction histories for each form control; similarly, it is possible to design systems where the user has access to more undo information than is present in the official (as described above) undo transaction history (such as providing a tree-based approach to document state). Such UI models should be based upon the single undo transaction history described in this section, however, such that to a script there is no detectable difference.

7.11 Editing APIs

Status: Last call for comments

document . execCommand(commandId [, showUI [, value ] ] )

Runs the action specified by the first argument, as described in the list below. The second and third arguments sometimes affect the action. (If they don't they are ignored.)

document . queryCommandEnabled(commandId)

Returns whether the given command is enabled, as described in the list below.

document . queryCommandIndeterm(commandId)

Returns whether the given command is indeterminate, as described in the list below.

document . queryCommandState(commandId)

Returns the state of the command, as described in the list below.

document . queryCommandSupported(commandId)

Returns true if the command is supported; otherwise, returns false.

document . queryCommandValue(commandId)

Returns the value of the command, as described in the list below.

The execCommand(commandId, showUI, value) method on the HTMLDocument interface allows scripts to perform actions on the current selection or at the current caret position. Generally, these commands would be used to implement editor UI, for example having a "delete" button on a toolbar.

There are three variants to this method, with one, two, and three arguments respectively. The showUI and value parameters, even if specified, are ignored except where otherwise stated.

When execCommand() is invoked, the user agent must follow the following steps:

  1. If the given commandId maps to an entry in the list below whose "Enabled When" entry has a condition that is currently false, do nothing; abort these steps.
  2. Otherwise, execute the "Action" listed below for the given commandId.

A document is ready for editing host commands if it has a selection that is entirely within an editing host, or if it has no selection but its caret is inside an editing host.

The queryCommandEnabled(commandId) method, when invoked, must return true if the condition listed below under "Enabled When" for the given commandId is true, and false otherwise.

The queryCommandIndeterm(commandId) method, when invoked, must return true if the condition listed below under "Indeterminate When" for the given commandId is true, and false otherwise.

The queryCommandState(commandId) method, when invoked, must return the value expressed below under "State" for the given commandId.

The queryCommandSupported(commandId) method, when invoked, must return true if the given commandId is in the list below, and false otherwise.

The queryCommandValue(commandId) method, when invoked, must return the value expressed below under "Value" for the given commandId.

The possible values for commandId, and their corresponding meanings, are as follows. These values must be compared to the argument in an ASCII case-insensitive manner.

bold
Summary: Toggles whether the selection is bold.
Action: The user agent must act as if the user had requested that the selection be wrapped in the semantics of the b element (or, again, unwrapped, or have that semantic inserted or removed, as defined by the UA).
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: True if the selection, or the caret, if there is no selection, is, or is contained within, a b element. False otherwise.
Value: The string "true" if the expression given for the "State" above is true, the string "false" otherwise.
createLink
Summary: Toggles whether the selection is a link or not. If the second argument is true, and a link is to be added, the user agent will ask the user for the address. Otherwise, the third argument will be used as the address.
Action: The user agent must act as if the user had requested that the selection be wrapped in the semantics of the a element (or, again, unwrapped, or have that semantic inserted or removed, as defined by the UA). If the user agent creates an a element or modifies an existing a element, then if the showUI argument is present and has the value false, then the value of the value argument must be used as the URL of the link. Otherwise, the user agent should prompt the user for the URL of the link.
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
delete
Summary: Deletes the selection or the character before the cursor.
Action: The user agent must act as if the user had performed a backspace operation.
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
formatBlock
Summary: Wraps the selection in the element given by the second argument. If the second argument doesn't specify an element that is a formatBlock candidate, does nothing.

Action: The user agent must run the following steps:

  1. If the value argument wasn't specified, abort these steps without doing anything.

  2. If the value argument has a leading U+003C LESS-THAN SIGN character (<) and a trailing U+003E GREATER-THAN SIGN character (>), then remove the first and last characters from value.

  3. If value is (now) an ASCII case-insensitive match for the tag name of an element defined by this specification that is defined to be a formatBlock candidate, then, for every position in the selection, take the nearest formatBlock candidate ancestor element of that position that contains only phrasing content, and, if that element is editable, is not an editing host, and has a parent element whose content model allows that parent to contain any flow content, replace it with an element in the HTML namespace whose name is value, and move all the children that were in it to the new element, and copy all the attributes that were on it to the new element.

    If there is no selection, then, where in the description above refers to the selection, the user agent must act as if the selection was an empty range (with just one position) at the caret position.

Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
forwardDelete
Summary: Deletes the selection or the character after the cursor.
Action: The user agent must act as if the user had performed a forward delete operation.
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
insertImage
Summary: Toggles whether the selection is an image or not. If the second argument is true, and an image is to be added, the user agent will ask the user for the address. Otherwise, the third argument will be used as the address.
Action: The user agent must act as if the user had requested that the selection be wrapped in the semantics of the img element (or, again, unwrapped, or have that semantic inserted or removed, as defined by the UA). If the user agent creates an img element or modifies an existing img element, then if the showUI argument is present and has the value false, then the value of the value argument must be used as the URL of the image. Otherwise, the user agent should prompt the user for the URL of the image.
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
insertHTML
Summary: Replaces the selection with the value of the third argument parsed as HTML.

Action: The user agent must run the following steps:

  1. If the document is an XML document, then throw an INVALID_ACCESS_ERR exception and abort these steps.

  2. If the value argument wasn't specified, abort these steps without doing anything.

  3. If there is a selection, act as if the user had requested that the selection be deleted.

  4. Invoke the HTML fragment parsing algorithm with an arbitrary orphan body element owned by the same Document as the context element and with the value argument as input.

  5. Insert the nodes returned by the previous step into the document at the location of the caret, firing any mutation events as appropriate.

Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
insertLineBreak
Summary: Inserts a line break.
Action: The user agent must act as if the user had requested a line separator.
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
insertOrderedList
Summary: Toggles whether the selection is an ordered list.
Action: The user agent must act as if the user had requested that the selection be wrapped in the semantics of the ol element (or unwrapped, or, if there is no selection, have that semantic inserted or removed — the exact behavior is UA-defined).
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
insertUnorderedList
Summary: Toggles whether the selection is an unordered list.
Action: The user agent must act as if the user had requested that the selection be wrapped in the semantics of the ul element (or unwrapped, or, if there is no selection, have that semantic inserted or removed — the exact behavior is UA-defined).
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
insertParagraph
Summary: Inserts a paragraph break.
Action: The user agent must act as if the user had performed a break block editing action.
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
insertText
Summary: Inserts the text given in the third parameter.
Action: The user agent must act as if the user had inserted text corresponding to the value parameter.
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
italic
Summary: Toggles whether the selection is italic.
Action: The user agent must act as if the user had requested that the selection be wrapped in the semantics of the i element (or, again, unwrapped, or have that semantic inserted or removed, as defined by the UA).
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: True if the selection, or the caret, if there is no selection, is, or is contained within, a i element. False otherwise.
Value: The string "true" if the expression given for the "State" above is true, the string "false" otherwise.
redo
Summary: Acts as if the user had requested a redo.
Action: The user agent must move forward one step in its undo transaction history, restoring the associated state. If the undo position is at the end of the undo transaction history, the user agent must do nothing. See the undo history.
Enabled When: The undo position is not at the end of the undo transaction history.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
selectAll
Summary: Selects all the editable content.
Action: The user agent must change the selection so that all the content in the currently focused editing host is selected. If no editing host is focused, then the content of the entire document must be selected.
Enabled When: Always.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
subscript
Summary: Toggles whether the selection is subscripted.
Action: The user agent must act as if the user had requested that the selection be wrapped in the semantics of the sub element (or, again, unwrapped, or have that semantic inserted or removed, as defined by the UA).
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: True if the selection, or the caret, if there is no selection, is, or is contained within, a sub element. False otherwise.
Value: The string "true" if the expression given for the "State" above is true, the string "false" otherwise.
superscript
Summary: Toggles whether the selection is superscripted.
Action: The user agent must act as if the user had requested that the selection be wrapped in the semantics of the sup element (or unwrapped, or, if there is no selection, have that semantic inserted or removed — the exact behavior is UA-defined).
Enabled When: The document is ready for editing host commands.
Indeterminate When: Never.
State: True if the selection, or the caret, if there is no selection, is, or is contained within, a sup element. False otherwise.
Value: The string "true" if the expression given for the "State" above is true, the string "false" otherwise.
undo
Summary: Acts as if the user had requested an undo.
Action: The user agent must move back one step in its undo transaction history, restoring the associated state. If the undo position is at the start of the undo transaction history, the user agent must do nothing. See the undo history.
Enabled When: The undo position is not at the start of the undo transaction history.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
unlink
Summary: Removes all links from the selection.
Action: The user agent must remove all a elements that have href attributes and that are partially or completely included in the current selection.
Enabled When: The document has a selection that is entirely within an editing host and that contains (either partially or completely) at least one a element that has an href attribute.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
unselect
Summary: Unselects everything.
Action: The user agent must change the selection so that nothing is selected.
Enabled When: Always.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".
vendorID-customCommandID
Action: User agents may implement vendor-specific extensions to this API. Vendor-specific extensions to the list of commands should use the syntax vendorID-customCommandID so as to prevent clashes between extensions from different vendors and future additions to this specification.
Enabled When: UA-defined.
Indeterminate When: UA-defined.
State: UA-defined.
Value: UA-defined.
Anything else
Action: User agents must do nothing.
Enabled When: Never.
Indeterminate When: Never.
State: Always false.
Value: Always the string "false".