source.html
author Ryosuke Niwa <rniwa@webkit.org>
Mon, 20 Aug 2012 23:11:11 -0700
changeset 19 e0d51f4b3b45
parent 18 bd3820a27e2d
child 20 9db51ae75f47
permissions -rwxr-xr-x
Disallow nested transactions as we have previously discussed
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>UndoManager and DOM Transaction</title>
<link rel="stylesheet" type="text/css" href="http://www.whatwg.org/style/specification">
</head>
<body class="draft">

<div class="head">
<h1>UndoManager and DOM Transaction</h1>

<h2 class="no-num no-toc">Editor's draft — 20 August 2012</h2>

<dl>
<dt>Editor:</dt>
<dd>Ryosuke Niwa &lt;<a href="mailto:rniwa@webkit.org">rniwa@webkit.org</a>&gt;
</dd>

<dt>Acknowledgements</dt>
<dd>Anne van Kesteren, Annie Sullivan, Alex Russell, Alex Vincent, Aryeh Gregor, Caio Marcelo de Oliveira Filho, Ehsan Akhgari, Eric Uhrhane,
Frederico Caldeira Knabben, Ian Hickson, Johan "Spocke" Sörlin, Jonas Sicking, Ojan Vafai, Olli Pettay, Rakesh Chaitanya KN, Sukolsak Sakshuwong</dd>

<dt>Latest version:</dt>
<dd><a href="http://dvcs.w3.org/hg/undomanager/raw-file/tip/undomanager.html">
http://dvcs.w3.org/hg/undomanager/raw-file/tip/undomanager.html</a></dd>

<dt>Previous versions:</dt>
<dd><a href="http://dvcs.w3.org/hg/undomanager/raw-file/77b8999a67d6/undomanager.html">
http://dvcs.w3.org/hg/undomanager/raw-file/77b8999a67d6/undomanager.html</a> (20 August 2012)</dd>
<dd><a href="http://dvcs.w3.org/hg/undomanager/raw-file/3fbf142909a7/undomanager.html">
http://dvcs.w3.org/hg/undomanager/raw-file/3fbf142909a7/undomanager.html</a> (8 June 2012)</dd>
<dd><a href="http://dvcs.w3.org/hg/undomanager/raw-file/17a725399127/undomanager.html">
http://dvcs.w3.org/hg/undomanager/raw-file/17a725399127/undomanager.html</a> (29 May 2012)</dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-03-27.html">
http://rniwa.com/editing/undomanager-2011-03-27.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-12-05.html">
http://rniwa.com/editing/undomanager-2011-12-05.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-12-01.html">
http://rniwa.com/editing/undomanager-2011-12-01.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-11-29.html">
http://rniwa.com/editing/undomanager-2011-11-29.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-10-27.html">
http://rniwa.com/editing/undomanager-2011-10-27.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-10-20.html">
http://rniwa.com/editing/undomanager-2011-10-20.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-10-09.html">
http://rniwa.com/editing/undomanager-2011-10-09.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-09-11.html">
http://rniwa.com/editing/undomanager-2011-09-11.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-08-30.html">
http://rniwa.com/editing/undomanager-2011-08-30.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-08-09.html">
http://rniwa.com/editing/undomanager-2011-08-09.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-08-08.html">
http://rniwa.com/editing/undomanager-2011-08-08.html</a></dd>
<dd><a href="http://rniwa.com/editing/undomanager-2011-07-26.html">
http://rniwa.com/editing/undomanager-2011-07-26.html</a></dd>

<dt>Use cases:</dt>
<dd><a href="http://wiki.whatwg.org/wiki/UndoManager_Problem_Descriptions">
http://wiki.whatwg.org/wiki/UndoManager_Problem_Descriptions</a></dd>

</dl>

</div>

<h2 class="no-num no-toc">Status</h2>

<p>This document is an early proposal of the specification for Undo Manager and
DOM transaction. This specification will replace the <a href="http://www.whatwg.org/specs/web-apps/current-work/#undomanager">UndoManager</a> section
of the main <a href="http://www.whatwg.org/html">HTML</a> specification.</p>

<h2 class="no-num no-toc">Table of Contents</h2>

<!--toc-->

<h2>Introduction</h2>

    <p>This specification defines the API to manage user agent's <a href="#undo-transaction-history">undo transaction history</a>
    (also known as <dfn id="undo-stack">undo stack</dfn>) and make objects that can be managed by
    the <a href="#undo-transaction-history">undo transaction history</a>.</p>

    <p>Many rich text editors on the Web add editing operations that are not natively supported by execCommand and other Web APIs.
    For example, many editors make modifications to DOM after an user agent executed user editing actions to work-around user agent bugs
    and to customize for their use.</p>

    <p>However, doing so breaks user agent's native undo and redo because the user agent cannot undo DOM modifications made by scripts.
    This forces the editors to re-implement undo and redo entirely from scratch, and many editors, indeed, store innerHTML as string and recreate
    the entire editable region whenever a user tires to undo and redo. This is very inefficient and has limited the depth of their <a href="#undo-stack">undo stack</a>.</p>

    <p>Also, any Web app that tries to mix contenteditable region or text fields with canvas or other non-text editable regions will have to
    reimplement undo and redo of contenteditable regions as well because the user agent typically has one <a href="#undo-transaction-history">undo transaction history</a> per document,
    and there is no easy way to add new undo entry to the user agent's native <a href="#undo-transaction-history">undo transaction history</a>.</p>

    <p>This specification tries to address above issues by providing ways to define <a href="#undo-scope">undo scopes</a>, add items to user agent's native
    <a href="#undo-transaction-history">undo transaction history</a>, and create a sequence of <a href="#dom-changes">DOM changes</a> that can be automatically undone or redone
    by user agents.</p>

<h2>Undo Scope and Undo Manager</h2>

<h3>Definitions</h3>

    <p>The user agent must associate an <dfn>undo transaction history</dfn>,
    a list of sequences of <a href="#dom-transaction">DOM transactions</a>,
    with each <code><a href="#undomanager">UndoManager</a></code> object.</p>

    <p>The <a href="#undo-transaction-history">undo transaction history</a> has an <dfn id="undo-position">undo position</dfn>.
    This is the position between two entries in the <a href="#undo-transaction-history">undo transaction history</a>'s list where the next
    entry represents what needs to happen when <a href="#undo">undo</a> is done,
    and the previous entry represents what needs to happen when <a href="#redo">redo</a></code> is done.</p>

    <p>The <dfn id="undo-scope" title="undo-scope">undo scope</dfn> is the collection of DOM nodes that are managed by the same <code><a href="#undomanager">UndoManager</a></code>.
    A document node or an element with <code><a href="#attr-undoscope">undoscope</a></code> attribute that is either an <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editing-host">editing host</a>
    or not <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editable">editable</a> defines a new <a href="#undo-scope">undo scope</a>,
    and all descendent nodes of the element, excluding elements with and descendent nodes of elements with <code><a href="#attr-undoscope">undoscope</a></code> attribute,
    will be managed by a new <code><a href="#undomanager">UndoManager</a></code>.
    An <dfn id="undo-scope-host">undo scope host</dfn> is a document, or an element with <code><a href="#attr-undoscope">undoscope</a></code> attribute that is either
    an <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editing-host">editing host</a>
    or not <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editable">editable</a>.</p>

<h3>Scoping Undo Transaction History</h3>
    <p>The <dfn id="attr-undoscope" title="attr-undoscope"><code>undoscope</code></dfn> attribute is a
    <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#boolean-attribute">boolean attribute</a>
    that controls the default <a href="#undo-scope">undo scope</a> of an element. It is to separate <a href="#undo-transaction-history">undo transaction histories</a> of multiple editable regions without scripts.
    Using <code><a href="#attr-undoscope">undoscope</a></code> content attribute, authors can easily set text fields in a widget to have a separate <a href="#undo-transaction-history">undo transaction histories</a> for example.</p>

    <p>When the <code><a href="#attr-undoscope">undoscope</a></code> content attribute is added to an <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editing-host">editing host</a>
    or an element that is not <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editable">editable</a>, the user agent must define new <a href="#undo-scope">undo scope</a> for the element,
    and create a new <code><a href="#undomanager">UndoManager</a></code> to manage any <a href="#dom-changes">DOM changes</a> made to all descendent nodes of
    the element excluding <a href="#undo-scope-host">undo scope hosts</a> and their descendents.</p>
    
    <p>When the <code><a href="#attr-undoscope">undoscope</a></code> content attribute is removed from an <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editing-host">editing host</a>
    or an element that is not <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editable">editable</a>, the user agent must remove all entries in the <a href="#undo-transaction-history">undo transaction history</a>
    of the corresponding <a href="#undo-scope">undo scope</a> without <a href="#dom-transaction-unapply">unapplying</a> or <a href="#dom-transaction-reapply">reapplying</a> them and
    <a href="#disconnect-undomanager">disconnect</a> the corresponding <code><a href="#undomanager">UndoManager</a></code> for the scope.
    After the removal, the node from which the content attribute is removed and their descendent nodes, excluding <a href="#undo-scope-host">undo scope hosts</a> and their descendents,
    belong to the <a href="#undo-scope">undo scope</a> of the closest ancestor with
    the <code><a href="#attr-undoscope">undoscope</a></code> content attribute or of the document.</p>

<h4>Undo scope and contenteditable</h4>
    <p><code><a href="http://www.whatwg.org/specs/web-apps/current-work/#attr-contenteditable">contenteditable</a></code> content attribute does not define a new <a href="#undo-scope">undo scope</a>
    and all <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editing-host">editing hosts</a> share the same <code><a href="#undomanager">UndoManager</a></code> by default.
    And the <code><a href="#attr-undoscope">undoscope</a></code> content attribute on an <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editable">editable</a> element is ignored
    except on <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editing-host">editing hosts</a>.</p>

    <p>When the <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#contenteditable">contenteditable</a></code> content attribute is set to <code>true</code> on an element,
    the user agent must <a href="#disconnect-undomanager">disconnect</a> the <code><a href="#undomanager">UndoManager</a></code>s
    of all descendent <a href="#undo-scope">undo scope hosts</a> of the element that have become
    <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editable">editable</a> due to the change
    as if the <code><a href="#attr-undoscope">undoscope</a></code> content attribute was removed from those nodes.</p>

    <p>Conversely, when the <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#contenteditable">contenteditable</a></code>
    content attribute is removed from an element or set to <code>false</code>, the user agent must behave as if
    <code><a href="#attr-undoscope">undoscope</a></code> content attribute is removed and added back to all descendent nodes of the element that have become
    non-<a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#editable">editable</a> due to the change.</p>

    <div class="example">
        <p>In the following example, the first child element of the container becomes editable when the container's
        <code>contentEditable</code> IDL is set to true, resulting in the first child element's <code><a href="#undomanager">UndoManager</a></code>
        to be <a href="#disconnect-undomanager">disconnected</a>.
        The second child element's <code><a href="#undomanager">UndoManager</a></code> isn't <a href="#disconnect-undomanager">disconnected</a>
        because the second child did not become editable as a result of the assignment.</p>

        <pre>
&lt;div id="container"&gt;
    &lt;div undoscope&gt;This will be editable&lt;/div&gt;
    &lt;div contenteditable="false" undoscope&gt;This will remain not editable.&lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
var container = document.getElementById('container');
var children = container.getElementsByTagName('*');
children[0].undoManager.transact({executeAutomatic: function () {}});
children[1].undoManager.transact({executeAutomatic: function () {}});
container.contentEditable = true;
alert(children[0].undoManager); // Alerts null
alert(children[1].undoManager.length); // Alerts 1
&lt;/script&gt;
</pre>
    </div>

<h4>undoScope IDL attribute</h4>

    <pre class="idl">partial interface <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-745549614">Element</a> {
    attribute boolean <a href="#dom-undoscope">undoScope</a>;
};</pre>
    <dl class="domintro">
        <dt><var title="">element</var> . <code title="dom-undoScope"><a href="#dom-undoscope">undoScope</a></code></dt>
        <dd><p>Returns <code>true</code> if the element is an undo scope host and <code>false</code> otherwise.</p></dd>
    </dl>

    <div class="impl">
        <p>The <dfn id="dom-undoscope"><code>undoScope</code></dfn> IDL attribute of <code><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-745549614">Element</a></code> interfaces must <a href="http://www.whatwg.org/specs/web-apps/current-work/complete/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes">reflect</a>
        the <code><a href="#attr-undoscope">undoscope</a></code> content attribute.</p>
    </div>

<h3>The <code><a href="#undomanager">UndoManager</a></code> interface</h3>

    <p>To manage transaction entries in the undo transaction history, the <code><a href="#undomanager">UndoManager</a></code> interface can be used:</p>

    <pre class="idl">interface <dfn id="undomanager">UndoManager</dfn> {
    void <a href="#dom-undomanager-transact" title="dom-UndoManager-transact">transact</a>(in DOMTransaction transaction, in boolean merge);
    void <a href="#dom-undomanager-undo" title="dom-UndoManager-undo">undo</a>();
    void <a href="#dom-undomanager-redo" title="dom-UndoManager-redo">redo</a>();
    getter DOMTransaction[] <a href="#dom-undomanager-item" title="dom-UndoManager-item">item</a>(in unsigned long index);
    readonly attribute unsigned long <a href="#dom-undomanager-length" title="dom-UndoManager-length">length</a>;
    readonly attribute unsigned long <a href="#dom-undomanager-position" title="dom-UndoManager-position">position</a>;
    void <a href="#dom-undomanager-clearUndo" title="dom-UndoManager-clearUndo">clearUndo</a>();
    void <a href="#dom-undomanager-clearRedo" title="dom-UndoManager-clearRedo">clearRedo</a>();
};</pre>

    <dl class="domintro">
        <dt><var title="">document</var> . <code title="dom-undoManager"><a href="#dom-undomanager">undoManager</a></code></dt>
        <dd><p>Returns the <code><a href="#undomanager">UndoManager</a></code> object.</p></dd>

        <dt><var title="">element</var> . <code title="dom-undoManager"><a href="#dom-undomanager">undoManager</a></code></dt>
        <dd><p>Returns the <code><a href="#undomanager">UndoManager</a></code> object.</p></dd>

        <dt><var title="">undoManager</var> . <code title="dom-UndoManager-transact"><a href="#dom-undomanager-transact">transact</a>(<var title="">transaction</var>,
            <var title="">merge</var>)</code></dt>
        <dd><p>Clears entries above the current undo position, <a href="#dom-transaction-apply">applies</a> <var title="">transaction</var>,
            and adds it to the beginning of the first entry in <a href="#undo-transaction-history">undo transaction history<a>,
            or of a new <a href="#undo-transaction-history">undo transaction history<a> if <var title="">merge</var> is set to false.</p></dd>

        <dt><var title="">undoManager</var> . <code title="dom-UndoManager-undo"><a href="#dom-undomanager-undo">undo</a>()</code></dt>
        <dd><p>Unapplies all <a href="#dom-transaction">DOM transactions</a> in the entry immediately after
            the current position in the reverse order and increments
            <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code> by 1
            if <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code> &lt;
            <code title="dom-UndoManager-length"><a href="#dom-undomanager-length">length</a></code>.</p></dd>

        <dt><var title="">undoManager</var> . <code title="dom-UndoManager-redo"><a href="#dom-undomanager-redo">redo</a>()</code></dt>
        <dd><p>Reapplies all <a href="#dom-transaction">DOM transactions</a> in the entry immediately before
            the current position and decrements <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code> by 1
            if <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code> &gt; 0</p></dd>

        <dt><var title="">undoManager</var> . <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code></dt>
        <dd><p>Returns the number of the current entry in the <a href="#undo-transaction-history">undo transaction history<a>. (Entries at and past this point are redo entries.)</p></dd>

        <dt><var title="">undoManager</var> . <code title="dom-UndoManager-length"><a href="#dom-undomanager-length">length</a></code></dt>
        <dd><p>Returns the number of entries in the <a href="#undo-transaction-history">undo transaction history<a>.</p></dd>

        <dt><var title="">data</var> = <var title="">undoManager</var> . <code title="dom-UndoManager-item"><a href="#dom-undomanager-item">item</a></code>(<var title="">index</var>)</dt>
        <dt><var title="">undoManager</var>[<var title="">index</var>]</dt>
        <dd><p>Returns the entry with index <var title="">index</var> in the <a href="#undo-transaction-history">undo transaction history<a>.</p>
            <p>Returns null if <var title="">index</var> is out of range.</p></dd>

        <dt><var title="">undoManager</var> . <code title="dom-UndoManager-clearundo"><a href="#dom-undomanager-clearundo">clearUndo</a>()</code></dt>
        <dd><p>Removes entries in the <a href="#undo-transaction-history">undo transaction history<a> before
            <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code> and
            resets <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code> to 0.</p></dd>

        <dt><var title="">undoManager</var> . <code title="dom-UndoManager-clearredo"><a href="#dom-undomanager-clearredo">clearRedo</a>()</code></dt>
        <dd><p>Removes entries in the <a href="#undo-transaction-history">undo transaction history<a> after
            <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code>.</p></dd>

    </dl>

    <div class="impl">
        <p><code><a href="#undomanager">UndoManager</a></code> objects represent and manage their node's
        <a href="#undo-transaction-history">undo transaction history</a>.</p>

        <p>The object's <a href="http://www.whatwg.org/specs/web-apps/current-work/#supported-property-indices">supported property indices</a> are the
        numbers in the range zero to <span title=""><var title="dom-UndoManager-length"><a href="#dom-undomanager-length">length</a></var>-1</span>,
        unless the <var title="dom-UndoManager-length"><a href="#dom-undomanager-length">length</a></var> is zero, in which
        case there are no <a href="http://www.whatwg.org/specs/web-apps/current-work/#supported-property-indices">supported property indices</a>.</p>

        <p>The <dfn id="dom-undomanager-transact" title="dom-UndoManager-transact"><code>transact(<var title="">transaction</var>, <var title="">merge</var>)</code></dfn> will</p>
        <ol>
            <li>If any <code><a href="#undomanager">UndoManager</a></code> is already in the process of <a href="#dom-transaction-apply">applying</a>,
                <a href="#dom-transaction-unapply">unapplying</a>, or <a href="#dom-transaction-reapply">reapplying</a> a <a href="#dom-transaction">DOM transaction</a>,
                or the <code><a href="#undomanager">UndoManager</a></code> had been <a href="#disconnect-undomanager">disconnected</a>, then throw
                <code class="external"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMException-INVALID_ACCESS_ERR">INVALID_ACCESS_ERR</a></code> and stop.</li>
            <li>Clear all entries between before the current <a href="#undo-position">undo position</a> without <a href="#dom-transaction-unapply">unapplying</a>
            or <a href="#dom-transaction-reapply">reapplying</a> the <a href="#dom-transaction">transactions</a> in the entires.</code></li>
            <li><a href="#dom-transaction-apply">Apply</a> the <var title="">transaction</var>.</li>
            <li>If <var title="">merge</var> is set to false, add an empty entry to the beginning of the <a href="#undo-transaction-history">undo transaction history</a>.</li>
            <li>Add the applied transaction to the beginning of the first entry in the <a href="#undo-transaction-history">undo transaction history</a>.</li>
            <li><a href="#fire-a-dom-transaction-event">Fire a DOM transaction event</a> for the transaction applied in step 3 at the <a href="#undo-scope-host">undo scope host</a>
            of this <code><a href="#undomanager">UndoManager</a></code> if the <code><a href="#undomanager">UndoManager</a></code> had not already been <a href="#disconnect-undomanager">disconnected</a>.</li>
        </ol>

        <p>The <dfn id="dom-undomanager-undo" title="dom-UndoManager-undo"><code>undo()</code></dfn> will</p>
        <ol>
            <li>If any <code><a href="#undomanager">UndoManager</a></code> is already in the process of <a href="#dom-transaction-apply">applying</a>,
                <a href="#dom-transaction-unapply">unapplying</a>, or <a href="#dom-transaction-reapply">reapplying</a> a <a href="#dom-transaction">DOM transaction</a>,
                or the <code><a href="#undomanager">UndoManager</a></code> had been <a href="#disconnect-undomanager">disconnected</a>, then throw
                <code class="external"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMException-INVALID_ACCESS_ERR">INVALID_ACCESS_ERR</a></code> and stop.</li>
            <li>If <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code> &#8804; <code title="dom-UndoManager-length"><a href="#dom-undomanager-length">length</a></code>, stop.</li>
            <li>Otherwise, <a href="#dom-transaction-unapply">unapply</a> <a href="#dom-transaction">DOM transactions</a> in the entry immediately after
            the <a href="#undo-position">undo position</a> in the order and increment <a href="#dom-undomanager-position">position</a></code> by 1.</li>
            <li><a href="#fire-an-undo-event">Fire an undo event</a> for the transaction unapplied in step 3 at the <a href="#undo-scope-host">undo scope host</a>
            of this <code><a href="#undomanager">UndoManager</a></code> if the <code><a href="#undomanager">UndoManager</a></code> had not already been <a href="#disconnect-undomanager">disconnected</a>.</li>
        </ol>

        <p>The <dfn id="dom-undomanager-redo" title="dom-UndoManager-redo"><code>redo()</code></dfn> will</p>
        <ol>
            <li>If any <code><a href="#undomanager">UndoManager</a></code> is already in the process of <a href="#dom-transaction-apply">applying</a>,
                <a href="#dom-transaction-unapply">unapplying</a>, or <a href="#dom-transaction-reapply">reapplying</a> a <a href="#dom-transaction">DOM transaction</a>,
                or the <code><a href="#undomanager">UndoManager</a></code> had been <a href="#disconnect-undomanager">disconnected</a>, then throw
                <code class="external"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMException-INVALID_ACCESS_ERR">INVALID_ACCESS_ERR</a></code> and stop.</li>
            <li>If <code title="dom-UndoManager-position"><a href="#dom-undomanager-position">position</a></code> &#8804; 0, stop.</li>
            <li>Otherwise, <a href="#dom-transaction-reapply">reapply</a> <a href="#dom-transaction">DOM transactions</a> in the entry immediately before
            the <a href="#undo-position">undo position</a> in the reverse order and decrement <a href="#dom-undomanager-position">position</a></code> by 1.</li>
            <li><a href="#fire-a-redo-event">Fire a redo event</a> for the transaction unapplied in step 3 at the <a href="#undo-scope-host">undo scope host</a>
            of this <code><a href="#undomanager">UndoManager</a></code> if the <code><a href="#undomanager">UndoManager</a></code> had not already been <a href="#disconnect-undomanager">disconnected</a>.</li>
        </ol>

        <p>The <dfn id="dom-undomanager-item" title="dom-UndoManager-item"><code>item(<var title="">n</var>)</code></dfn>
        method must return a new array representing the <var title="">n</var>th entry in the <a href="#undo-transaction-history">undo transaction history</a> if
        0 &#8804; <var>n</var> &lt; <code title="dom-UndoManager-length"><a href="#dom-undomanager-length">length</a></code>, or null otherwise.</p>

        <p class="note">Being able to access an arbitrary element in the <a href="#undo-transaction-history">undo transaction history</a> is needed to allow scripts to determine
        whether new DOM transaction and the last DOM transaction should being to the same entry or not.</p>

        <p>The <dfn id="dom-undomanager-position" title="dom-UndoManager-position"><code>position</code></dfn>
        attribute must return the index of the <a href="#undo-position">undo position</a> in the <a href="#undo-transaction-history">undo transaction history</a>.
        If there are no <a href="#dom-transaction">DOM transaction</a>s to undo, then the value must be same as
        <code title="dom-UndoManager-length"><a href="#dom-undomanager-length">length</a></code> attribute.
        If there are no <a href="#dom-transaction">DOM transaction</a>s to redo, then the value must be zero.</p>

        <p>The <dfn id="dom-undomanager-length" title="dom-UndoManager-length"><code>length</code></dfn>
        attribute must return the number of entries in the <a href="#undo-transaction-history">undo transaction history</a>.
        This is the <var title="dom-UndoManager-length"><a href="#dom-undomanager-length">length</a></var>.</p>

        <p>The <dfn id="dom-undomanager-clearundo" title="dom-UndoManager-clearUndo"><code>clearUndo()</code></dfn>
        method must throw <code class="external"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMException-INVALID_ACCESS_ERR">INVALID_ACCESS_ERR</a></code>
        if any <code><a href="#undomanager">UndoManager</a></code> is already in the process of <a href="#dom-transaction-apply">applying</a>,
        <a href="#dom-transaction-unapply">unapplying</a>, or <a href="#dom-transaction-reapply">reapplying</a> a <a href="#dom-transaction">DOM transaction</a>,
        or the <code><a href="#undomanager">UndoManager</a></code> had been <a href="#disconnect-undomanager">disconnected</a>, 
        otherwise it must remove all entries in the <a href="#undo-transaction-history">undo transaction history</a> before the <a href="#undo-position">undo position</a>,
        and move the <a href="#undo-position">undo position</a> to the top (set <a href="#dom-undomanager-position">position</a></code> to zero).</p>

        <p>The <dfn id="dom-undomanager-clearredo" title="dom-UndoManager-clearRedo"><code>clearRedo()</code></dfn>
        method must throw <code class="external"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMException-INVALID_ACCESS_ERR">INVALID_ACCESS_ERR</a></code>
        if any <code><a href="#undomanager">UndoManager</a></code> is already in the process of <a href="#dom-transaction-apply">applying</a>,
        <a href="#dom-transaction-unapply">unapplying</a>, or <a href="#dom-transaction-reapply">reapplying</a> a <a href="#dom-transaction">DOM transaction</a>,
        or the <code><a href="#undomanager">UndoManager</a></code> had been <a href="#disconnect-undomanager">disconnected</a>, 
        otherwise it must remove all entries in the <a href="#undo-transaction-history">undo transaction history</a> after the <a href="#undo-position">undo position</a>.</p>

        <p><dfn id="the-active-undo-manager">The active undo manager</dfn> is the <code><a href="#undomanager">UndoManager</a></code> of the focused node in the document.
        If no node has focus, then it's assumed to be of the document.</p>

        <p>To <dfn id="disconnect-undomanager">disconnect an UndoManager</dfn> means to deprive the ability to add or remove entries in
        the <a href="#undo-transaction-history">undo transaction history</a> of the <code><a href="#undomanager">UndoManager</a></code>.
        Once the <code><a href="#undomanager">UndoManager</a></code> is disconnected, <code><a href="#dom-undomanager-transact">transact</a>()</code>,
        <code><a href="#dom-undomanager-undo">undo</a>()</code>, <code><a href="#dom-undomanager-redo">redo</a>()</code>, <code><a href="#dom-undomanager-clearundo">clearUndo</a>()</code>,
        and <code><a href="#dom-undomanager-clearundo">clearRedo</a>()</code> will all throw
        <code class="external"><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMException-INVALID_ACCESS_ERR">INVALID_ACCESS_ERR</a></code>.<p>
    </div>

    <p>Each entry in the <a href="#undo-manager">UndoManager</a> consists of one or more <a href="#dom-transaction">DOM transactions</a>,
    all of which are <a href="#dom-transaction-unapply">unapplied</a> and <a href="#dom-transaction-reapply">reapplied</a> togehter in one
    <a href="#undo">undo</a> or <a href="#redo">redo</a>.
    </p>

    <div class="example">
        <p>Because <code><a href="#dom-undomanager-item">item()</a></code> returns new array on each call,
        modifying the array does not have any effect on the sequence of <a href="#dom-transaction">DOM transactions</a> of the entry,
        and two return values of <code><a href="#dom-undomanager-item">item()</a></code> are alwys different objects.</p>

        <pre>
document.undoManager.transact(...);
document.undoManager.transact(..., true);
document.undoManager.transact(..., true);
alert(document.undoManager.item(0).length); // Alerts 3
document.undoManager.item(0).pop();
alert(document.undoManager.item(0).length); // Still alerts 3
alert(document.undoManager.item(0) === document.undoManager.item(0)); // Alerts false
</pre>
    </div>

    <p class="note">A typical use case for having multiple <a href="#dom-transaction">DOM transactions</a> in one entry is for typing
    multiple letters, spaces, and new lines that must be undone or redone in one step.</p>

    <div class="example">
        <p>In the following example, letters "o" and "k" are inserted by two <a href="#automatic-dom-transaction">automatic DOM transactions</a>
        that form one entry in the <a href="#undo-transaction-history">undo transaction history</a> of the <a href="#undo-manager">UndoManager</a>.
        A br element and string "hi" are then inserted by another two <a href="#automatic-dom-transaction">automatic DOM transactions</a>
        to form entry in the <a href="#undo-transaction-history">undo transaction history</a>. All transactions have the label "Typing".</p>

        <pre>
// Assume myEditor is some element that has undoscope attribute, and insert(node) is a function that inserts the specified node at where the caret is.
myEditor.undoManager.transact({executeAutomatic: function () {
    insert(document.createTextNode('o')); }, label: 'Typing'});
myEditor.undoManager.transact({executeAutomatic: function () {
    insert(document.createTextNode('k')); }, label: 'Typing'}, true);
myEditor.undoManager.transact({executeAutomatic: function () {
    insert(document.createElement('br')); }, label: 'Typing'});
myEditor.undoManager.transact({executeAutomatic: function () {
    insert(document.createTextNode('hi')); }, label: 'Typing'}), true);
</pre>
        <p>When the first <a href="#undo">undo</a> is executed immediately after this code is ran, the last two transactions are <a href="#dom-transaction-unapply">unapplied</a>,
        and the br element and string "hi" will be removed from the DOM. The second <a href="#undo">undo</a> will <a href="#dom-transaction-unapply">unapply</a> the first two transactions and remove "o" and "k".</p>
    </div>

    <p class="note">Because Mac OS X and other frameworks expect applications to provide an array of undo items, simply dispatching undo and redo events
    and having scripts manage <a href="#undo-transaction-history">undo transaction history</a> would not let the user agent populate the native UI properly.</p>

<h4>undoManager IDL attribute</h4>

    <pre class="idl">partial interface <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-745549614">Element</a> {
    attribute <a href="#undomanager">UndoManager</a> <a href="#dom-undomanager">undoManager</a>;
};</pre>
    <dl class="domintro">
        <dt><var title="">element</var> . <code title="dom-undoManager"><a href="#dom-undomanager">undoManager</a></code></dt>
        <dd><p>Returns the <code><a href="#undomanager">UndoManager</a></code> object associated with the element's <a href="#undo-scope">undo scope</a>
        if the element is an <a href="#undo-scope-host">undo scope host</a>, or <code>null</code> otherwise.</p></dd>
    </dl>

    <pre class="idl">partial interface <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#i-Document">Document</a> {
    attribute <a href="#undomanager">UndoManager</a> <a href="#dom-undomanager">undoManager</a>;
};</pre>
    <dl class="domintro">
        <dt><var title="">document</var> . <code title="dom-undoManager"><a href="#dom-undomanager">undoManager</a></code></dt>
        <dd><p>Returns the <code><a href="#undomanager">UndoManager</a></code> object associated with the document.</p></dd>
    </dl>

    <div class="impl">
        <p>The <dfn id="dom-undomanager" title="dom-undoManager"><code>undoManager</code></dfn> IDL attribute of
        <code class="external"><a href="http://www.whatwg.org/specs/web-apps/current-work/#document">Document</a></code> and
        <code class="external"><a href="http://www.whatwg.org/specs/web-apps/current-work/#element">Element</a></code> interfaces must return the object implementing
        the <code><a href="#undomanager">UndoManager</a></code> interface for the <a href="#undo-scope">undo scope</a> if the node is an <a href="#undo-scope-host">undo scope host</a>.
        If the node is not an <a href="#undo-scope-host">undo scope host</a>, it must return <code>null</code>.</p>
    </div>

<h3>Undo: moving forward in the undo transaction history</h3>

    <p>When the user invokes an undo operation, or when the
    <code class="external"><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#execCommand">execCommand()</a></code> method is called with
    the undo command, the user agent must perform an <dfn>undo</dfn> operation on <a href="#the-active-undo-manager">the active undo manager</a> by calling
    the <code><a href="#dom-undomanager-undo">undo</a>()</code> method.</p>

<h3>Redo: moving backward in the undo transaction history</h3>

    <p>When the user invokes a redo operation, or when the
    <code class="external"><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#execCommand">execCommand()</a></code> method is called with
    the redo command, the user agent must perform an <dfn>redo</dfn> operation on <a href="#the-active-undo-manager">the active undo manager</a> by calling
    the <code><a href="#dom-undomanager-redo">redo</a>()</code> method.</p>

<h2>DOM Transaction and DOM changes</h2>

    <p>A <dfn>DOM transaction</dfn> is an ordered set of <a href="#dom-changes">DOM changes</a> associated with
    a unique <a href="#undo-scope-host">undo scope host</a> that can be <a href="#dom-transaction-apply">applied</a>, <a href="#dom-transaction-unapply">unapplied</a>,
    or <a href="#dom-transaction-reapply">reapplied</a>.</p>

    <p>To <dfn id="dom-transaction-apply" title="dom-transaction-apply">apply</dfn> a <a href="#dom-transaction">DOM transaction</a> means to make the associated <a href="#dom-changes">DOM changes</a>
    under the associated <a href="#undo-scope-host">undo scope host</a>.
    And to <dfn id="dom-transaction-unapply" title="dom-transaction-unapply">unapply</dfn> and to <dfn id="dom-transaction-reapply" title="dom-transaction-reapply">reapply</dfn>
    a <a href="#dom-transaction">DOM transaction</a> means, respectively, to revert and to remake the associated <a href="#dom-changes">DOM changes</a> under the associated <a href="#undo-scope-host">undo scope host</a>.

    <p>A <a href="#dom-transaction">DOM transaction</a> can be <a href="#dom-transaction-unapply">unapplied</a> or <a href="#dom-transaction-reapply">reapplied</a> if it appears, respectively, immediately after or immediately before
    the <a href="#undo-position">undo position</a> in the associated <code><a href="#undomanager">UndoManager</a></code>'s <a href="#undo-transaction-history">undo transaction history</a>.</p>

<h3>Mutations of DOM</h3>
    <p><dfn>DOM changes</dfn> of a node is a sequence s<sub>1</sub>, s<sub>2</sub>, ... s<sub>n</sub> where each s<sub>i</sub> with 1 &#8804; i &#8804; n is either one of:</p>
    <ul>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-insert">Inserting</a> or <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-remove">removing</a> a node under the element.</li>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-cd-replace">Replacement of character data</a>.</li>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-append">Appending</a>, <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-remove">removing</a>,
        or <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attribute-change">changing</a> a content attribute of the element or descendent nodes of the element.</li>
        <li>Setting <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-textarea-element">textarea</a></code> element's
        <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#dom-textarea-value">value</a></code> IDL attribute
        or <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element">input</a></code> elment's
        <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#dom-input-value">value</a></code> IDL attribute.</li>
    </ul>

    <p>The <dfn>DOM state</dfn> of a node is the state of all descendent nodes and their attributes that are affected by <a href="#dom-changes">DOM changes</a> of the element.
    If two <a href="#dom-states">DOM states</a> of a node are equal, then the node and all its descendent nodes must be identical.</p>

<h4>Reverting DOM changes</h4>

    <p>To <dfn>revert DOM changes</dfn> of the sequence s<sub>1</sub>, s<sub>2</sub>, ... s<sub>n</sub>,
    revert each s<sub>i</sub> with 1 &#8804; i &#8804; n in the reverse order s<sub>n</sub>, s<sub>n-1</sub>, ... s<sub>1</sub> as specified below:</p>

    <p>To revert <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-insert">inserting</a> a <var>node</var> into a <var>parent</var> before a <var>child</var>,
    run these steps:</p>
    <ol>
        <li>If <var>node</var> is not null and its parent is not <var>parent</var>, then terminate these steps.</li>
        <li>If <var>child</var> is not null and its parent is not <var>parent</var>, then terminate these steps.</li>
        <li>If <var>child</var> is not null and its previous sibling is not <var>node</var>, then terminate these steps.</li>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-pre-remove">Pre-remove</a> <var>node</var> from <var>parent</var>.</li>
    </ol>

    <p>To revert <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-remove">removing</a> a <var>node</var> from a <var>parent</var>,
    let <var>child</var> be the next sibling of <var>node</var> before the removal, and run these steps:</p>
    <ol>
        <li>If <var>node</var> is not null and its parent is not null, then terminate these steps.</li>
        <li>If <var>child</var> is not null and its parent is not <var>parent</var>, then terminate these steps.</li>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-pre-insert">Pre-insert</a> <var>child</var> into <var>parent</var> before <var>child</var>.</li>
    </ol>

    <p>To revert <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-cd-replace">replacing</a> data of a <var>node</var> with an <var>offset</var>, <var>count</var>, and <var>data</var>,
    let <var>replacedData</var> be the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-cd-replace">substringed data</a> with <var>node</var>, <var>offset</var>, and <var>count</var> before the replacement,
    and run these steps:</p>
    <ol>
        <li>If node's <code><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-length">length</a></code> attribute is less than <var>offset</var>, terminate these steps.</li>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-cd-replace">Replace data</a> of <var>node</var> with <var>offset</var>, the length of data, and <var>replacedData</var>.</li>
    </ol>

    <p>To revert <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-change">changing</a> an attribute whose
    <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var> and
    <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var> to <var>value</var>,
    let <var>oldValue</var> be the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-value">content attribute value</a> before the change,
    <var>oldPrefix</var> be the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a> before the change,
    and <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-change">change</a> the attribute to <var>oldValue</var>
    and set the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a> to <var>oldPrefix</var>.</p>

    <p>To revert <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-append">appending</a> an attribute whose
    <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var> and
    <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var> to a node
    and setting the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a> to <var>prefix</var>,
    run these steps.</p>
    <ol>
        <li>If a content attribute whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a>
        is <var>namespace</var> and <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a>
        is <var>localName</var> doesn't exist on the node, then terminate these steps.</li>
        <li>Otherwise, <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-remove">remove</a> the attribute
        whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var> and
        <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var>.</li>
    </ol>

    <p>To revert <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-remove">removing</a> an attribute whose
    <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var> and
    <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var> from a node,
    let <var>oldValue</var> be the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-value">content attribute value</a> and
    <var>oldPrefix</var> be the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a>
    both before the removal, and run these steps.</p>
    <ol>
        <li>If a content attribute whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a>
        is <var>namespace</var> and <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a>
        is <var>localName</var> exists on the node, then terminate these steps.</li>
        <li>Otherwise, create and append the attribute whose
        <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var> and
        <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var>,
        with <var>oldValue</var> as the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-value">content attribute value</a>
        and set the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a>
        to <var>oldPrefix</var>.</li>
    </ol>

    <p>To revert setting <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-textarea-element">textarea</a></code>
    element's <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#dom-textarea-value">value</a></code> IDL attribute
    and <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element">input</a></code> element's
    <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#dom-input-value">value</a></code> IDL attribute
    to <var>value</var>, set element's <code>value</code> IDL attribute to
    the <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#concept-textarea-raw-value">raw value</a> of the textarea element
    and the <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#concept-fe-value">value</a> of the input element
    before the setting respectively.</p>

<h4>Reapplying DOM changes</h4>

    <p>To <dfn>reapply DOM changes</dfn> of the sequence s<sub>1</sub>, s<sub>2</sub>, ... s<sub>n</sub>,
    reapply each s<sub>i</sub> with 1 &#8804; i &#8804; n in the same order s<sub>1</sub>, s<sub>2</sub>, ... s<sub>n</sub> as specified below:</p>

    <p>To reapply <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-insert">inserting</a>
    a <var>node</var> into a <var>parent</var> before a <var>child</var>, run these steps:</p>
    <ol>
        <li>If <var>node</var> is not null and its parent is not null, then terminate these steps.</li>
        <li>If <var>child</var> is not null and its parent is not <var>parent</var>, then terminate these steps.</li>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-pre-insert">Pre-insert</a>
        <var>child</var> into <var>parent</var> before <var>child</var>.</li>
    </ol>

    <p>To reapply <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-remove">removing</a>
    a <var>node</var> from a <var>parent</var>, let <var>child</var> be the next sibling of <var>node</var> before the removal,
    and run these steps:</p>
    <ol>
        <li>If <var>node</var> is not null and its parent is not <var>parent</var>, then terminate these steps.</li>
        <li>If <var>child</var> is not null and its parent is not <var>parent</var>, then terminate these steps.</li>
        <li>If <var>child</var> is not null and its previous sibling is not <var>node</var>, then terminate these steps.</li>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-pre-remove">Pre-remove</a>
        <var>node</var> from <var>parent</var>.</li>
    </ol>

    <p>To reapply <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-cd-replace">replacing</a> data
    of a <var>node</var> with an <var>offset</var>, <var>count</var>, and <var>data</var>, and run these steps:</p>
    <ol>
        <li>If node's <code><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-length">length</a></code>
        attribute is less than <var>offset</var>, terminate these steps.</li>
        <li><a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-cd-replace">Replace data</a> of <var>node</var>
        with <var>offset</var>, <var>count</var>, and <var>replacedData</var>.</li>
    </ol>

    <p>To reapply <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-change">changing</a> an attribute
    whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var>
    and <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var>
    to <var>value</var>, let <var>prefix</var> be the
    <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a> after the change,
    and change the attribute to <var>value</var> and set
    the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a> to <var>prefix</var>.</p>

    <p>To reapply <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-append">appending</a>
    an attribute whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var>
    and <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var>
    with <var>value</var> as the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-value">content attribute value</a>
    to a node and setting the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a>
    to <var>prefix</var>, run these steps:</p>
    <ol>
        <li>If a content attribute whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a>
        is <var>namespace</var> and <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is
        <var>localName</var> exists on the node, then terminate these steps.</li>
        <li>Otherwise, <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-append">append</a> the attribute
        whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var> and
        <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var>
        with <var>value</var> as the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-value">content attribute value</a>
        to the node, and set <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace-prefix">namespace prefix</a>
        to <var>prefix</var>.</li>
    </ol>

    <p>To reapply <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-remove">removing</a>
    an attribute whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var>
    and <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var>
    from a node, run these steps.</p>
    <ol>
        <li>If a content attribute whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is
        <var>namespace</var> and <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is
        <var>localName</var> doesn't exist on the node, then terminate these steps.</li>
        <li>Otherwise, <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-attributes-remove">remove</a> the attribute
        whose <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-namespace">namespace</a> is <var>namespace</var> and
        <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name">local name</a> is <var>localName</var>.</li>
    </ol>

    <p>To reapply setting <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-textarea-element">textarea</a></code>
    element's <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#dom-textarea-value">value</a></code> IDL attribute
    or <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element">input</a></code> elment's
    <code><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#dom-input-value">value</a></code> IDL attribute
    to <var>value</var>, set element's <code>value</code> IDL attribute to <var>value</var>.</p>

<h3>The <code><a href="#dom-domtransaction">DOMTransaction</a></code> interface</h3>

    <pre class="idl">[NoInterfaceObject]
interface <dfn id="dom-domtransaction">DOMTransaction</dfn> {
    attribute DOMString <a href="#dom-domtransaction-label">label</a>;
    attribute <a href="http://www.whatwg.org/specs/web-apps/current-work/complete/webappapis.html#function">Function</a>? <a href="#dom-domtransaction-executeautomatic">executeAutomatic</a>;
    attribute <a href="http://www.whatwg.org/specs/web-apps/current-work/complete/webappapis.html#function">Function</a>? <a href="#dom-domtransaction-execute">execute</a>;
    attribute <a href="http://www.whatwg.org/specs/web-apps/current-work/complete/webappapis.html#function">Function</a>? <a href="#dom-domtransaction-undo">undo</a>;
    attribute <a href="http://www.whatwg.org/specs/web-apps/current-work/complete/webappapis.html#function">Function</a>? <a href="#dom-domtransaction-redo">redo</a>;
};</pre>

    <div class="impl">
        <p>The <code><a href="#dom-domtransaction">DOMTransaction</a></code> interface is to be implemented by content scripts that implement a <a href="#dom-transaction">DOM transaction</a>.</p>

        <p><dfn id="dom-domtransaction-label"><code>label</code></dfn> attribute must return <code>null</code> or a string that
        describes the semantics of the transaction such as "Inserting text" or "Deleting selection".
        The user agent may expose this string or a part of this string through its native UI such as menu bar or context menu.
        When there are multiple <a href="#dom-transaction">transactions</a> in a single entry of
        the <a href="#undo-transaction-history">undo transaction history</a>, the user agent that doesn't support displaying
        multiple labels for each entry must use the label of the first transaction in the sequence of the entry.</p>

        <p><dfn id="dom-domtransaction-executeautomatic"><code>executeAutomatic()</code></dfn>, <dfn id="dom-domtransaction-execute"><code>execute()</code></dfn>,
        <dfn id="dom-domtransaction-undo"><code>undo()</code></dfn>, and <dfn id="dom-domtransaction-redo"><code>redo()</code></dfn> are attributes that must be supported,
        as IDL attributes, by objects implementing the <code><a href="#dom-domtransaction">DOMTransaction</a></code> interface.</p>
    </div>

    <div class="example">
        <p>Any changes made to the value of <code><a href="#dom-domtransaction-executeautomatic">executeAutomatic</a></code>,
        <code><a href="#dom-domtransaction-execute">execute</a></code>, <code><a href="#dom-domtransaction-undo">undo</a></code>,
        or <code><a href="#dom-domtransaction-redo">redo</a></code> attributes will take effect immediately. In the following example,
        <code><a href="#dom-domtransaction-execute">execute</a></code> and <code><a href="#dom-domtransaction-undo">undo</a></code> attributes are modified:</p>

        <pre>
document.undoManager.transact({ execute: function () {
    this.execute = function () { alert('foo'); }
    alert('bar');
}, undo: function () { alert('baz'); } }); // alerts 'bar'
document.undoManager.item(0)[0].undo = function() { alert('foobar'); }
docuemnt.undoManager.undo(); // alerts 'foobar'
</pre></div>

    <div class="impl">
        <p><dfn id="dom-domtransaction-executeautomatic"><code>executeAutomatic</code></dfn> attribute must return a valid function if the transaction is a <a href="#automatic-dom-transaction">automatic DOM transaction</a>,
        and <code>undefined</code> if it is a <a href="#manual-dom-transaction">manual DOM transaction</a> immediately before the transaction is <a href="#dom-transaction-apply">applied</a>.
        Any changes made to the value of the <code><a href="#dom-domtransaction-executeautomatic">executeAutomatic</a></code> attribute while the transaction is being <a href="#dom-transaction-apply">applied</a> or after the transaction had been <a href="#dom-transaction-apply">applied</a>
        should not change the type of the <a href="#dom-transaction">DOM transaction</a>.</p>
    </div>

    <div class="example">
        <p>All <a href="#dom-changes">DOM changes</a> made in <code><a href="#dom-domtransaction-execute">execute</a></code> or
        <code><a href="#dom-domtransaction-executeautomatic">executeAutomatic</a></code> take effect immediately.
        Sometimes, this <a href="#disconnect-undomanager">disconnects</a> the undoManager to which it belongs.</p>

        <pre>
var scope = document.createElement('div');
scope.undoScope = true;
document.body.appendChild(scope);
scope.undoManager.transact({executeAutomatic: function () {
    scope.appendChild("foo");
    alert(scope.textContent); // "foo"
    scope.undoScope = false;
}});
scope.undoManager.undo(); // Throws an error because undoManager returns null.
</pre></div>

<h3>Automatic DOM transactions</h3>

    <p>An <dfn>automatic DOM transaction</dfn> is a <a href="#dom-transaction">DOM transaction</a> where <a href="#dom-changes">DOM changes</a>
    are tracked by the user agent and the logic to <a href="#dom-transaction-unapply">unapply</a> or <a href="#dom-transaction-reapply">reapply</a>
    the transaction is implicitly created by the user agent. </p>

    <div class="impl">
        <p>When an <a href="#automatic-dom-transaction">automatic DOM transaction</a> is <a href="#dom-transaction-apply">applied</a>,
        the user agent must call the function returned by the <code><a id="dom-domtransaction-executeautomatic">executeAutomatic</a></code> attribute if the attribute returns a valid function object.
        All <a href="#dom-changes">DOM changes</a> made by the method in the corresponding <a href="#undo-scope">undo scope</a> of the <code><a href="#undomanager">UndoManager<a></code>
        must be tracked by the user agent.</p>
    </div>

    <div class="example">
        <p>All <a href="#dom-changes">DOM changes</a> made outside of the <a href="#undo-scope">undo scope</a> take effect immediately
        but are ignored for the purpose of undo and redo.
        In the following example, <code><a href="#dom-undomanager-undo">undo</a>()</code> will only remove "bar" and "foo"
        remains in the body.</p>

        <pre>
var scope = document.createElement('div');
scope.undoScope = true;
document.body.appendChild(scope);
scope.undoManager.transact({executeAutomatic: function () {
    document.body.appendChild("foo");
    scope.appendChild("bar");
}});
scope.undoManager.undo();
alert(document.body.textContent); // Alerts "foo".
</pre>
    </div>

    <div class="impl">
        <p>When an <a href="#automatic-dom-transaction">automatic DOM transaction</a> is <a href="#dom-transaction-unapply">unapplied</a>,
        the user agent must <a href="#revert-dom-changes">revert DOM changes</a> made inside the <a href="#undo-scope">undo scope</a> of the the <code><a href="#undomanager">UndoManager<a></code>
        while <a href="#dom-transaction-apply">applying</a> the transaction, and call the function returned by the <code><a id="dom-domtransaction-undo">undo</a></code> attribute if the attribute returns a valid function object.</p>

        <p>When an <a href="#automatic-dom-transaction">automatic DOM transaction</a> is <a href="#dom-transaction-reapply">reapplied</a>,
        the user agent must <a href="#unrevert-dom-changes">reapply DOM changes</a> made inside the <a href="#undo-scope">undo scope</a> of the the <code><a href="#undomanager">UndoManager<a></code>
        while <a href="#dom-transaction-apply">applying</a> the transaction.
        The user agent must then call the function returned by the <code><a id="dom-domtransaction-redo">redo</a></code> attribute if the attribute returns a valid function object.</p>

        <p>The user agent must also restore <a href="https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#concept-selection">selection</a> after
        <a href="#dom-transaction-unapply">unapplying</a> or <a href="#dom-transaction-reapply">reapplying</a> an <a href="#automatic-dom-transaction">automatic DOM transaction</a>
        in accordance to user agent's platform convention.</p>

        <p>The user agent must implement <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#user-editing-actions">user editing actions</a> and
        <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dnd">drag and drop</a>
        as <a href="#automatic-dom-transaction">automatic DOM transactions</a>, and any application defined <a href="#automatic-dom-transactions">automatic DOM transactions</a> must be compatible with
        <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#user-editing-actions">user editing actions</a>.</p>
    </div>

    <p>In an <a href="#automatic-dom-transaction">automatic DOM transaction</a>, <code><a id="dom-domtransaction-execute">execute</a></code> attribute is ignored.</p>

<h4>Automatic transactions and manual DOM changes</h4>
    <p>Authors should not modify nodes that are used by <a href="#automatic-dom-transaction">automatic DOM transactions</a>
    in <a href="#revert-dom-changes">reverting</a> or <a href="#unrevert-dom-changes">reapplying</a>
    <a href="#dom-changes">DOM changes</a> as it will interfere with the user agent's attempt to <a href="#transaction-unapply">unapply</a>
    or <a href="#transaction-reapply">reapply</a> automatic DOM transactions.</p>

    <div class="example">
        <p>In the following example, the user agent terminates steps early while reverting
        the <a href="http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-insert">insertion</a> of
        the text node <code>" world"</code> in the first call to <code><a href="#dom-undomanager-undo">undo</a>()</code>
        and doesn't make any <a href="#dom-changes">DOM changes</a>.</p>
        <pre>
var b = document.createTextNode("b");
b.appendChild(document.createTextNode("hello"));
document.body.appendChild(b);
document.undoManager.transact({ executeAutomatic: function () {
    document.body.appendChild(document.createTextNode(" world")); }});
b.appendChild(document.body.lastChild);
document.undoManager.undo(); // No-op.
</pre>

        <p>On the other hand, if we store the <a href="#dom-state">DOM state</a> as done below, then the call to
        <code><a href="#dom-undomanager-undo">undo</a>()</code> will successfully remove the the text node from the body.</p>
<pre>
document.undoManager.redo(); // No-op.
document.body.appendChild(b.lastChild);
document.undoManager.undo(); // " world" is removed from document.body
</pre></div>

<h3>Manual DOM transactions</h3>
    <p>A <dfn>manual DOM transaction</dfn> is a <a href="#dom-transaction">DOM transaction</a> where the logic to
    <a href="#dom-transaction-unapply">apply</a>, <a href="#dom-transaction-unapply">unapply</a>, or <a href="#dom-transaction-reapply">reapply</a>
    the transaction is explicitly defined by an application.
    It provides a way to communicate with user agent's <a href="#undo-transaction-history">undo transaction history</a>, e.g. to populate user agent's undo menu.</p>

    <div class="impl">
        <p>When a <a href="#manual-dom-transaction">manual DOM transaction</a> is <a href="#dom-transaction-apply">applied</a>, the user agent must call
        the function returned by the <code><a id="dom-domtransaction-execute">execute</a></code> if the attribute returns a valid function object.</p>

        <p>When a <a href="#manual-dom-transaction">manual DOM transaction</a> is <a href="#dom-transaction-unapply">unapplied</a>, the user agent must call
        the function returned by the <code><a id="dom-domtransaction-undo">undo</a></code> attribute if the attribute returns a valid function object.</p>

        <p>When a <a href="#manual-dom-transaction">manual DOM transaction</a> is <a href="#dom-transaction-reapply">reapplied</a>, the user agent must call
        the function returned by the <code><a id="dom-domtransaction-redo">redo</a></code> attribute if the attribute returns a valid function object.</p>
    </div>

    <p>In a <a href="#manual-dom-transaction">manual DOM transaction</a>, <code><a id="dom-domtransaction-executeautomatic">executeAutomatic</a></code> attribute is ignored.</p>

    <p class="note">Manual DOM transactions may be incompatible with automatic DOM transactions, in particular,
    with <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#user-editing-actions">user editing actions</a>
    if manual DOM transaction mutates nodes that are dependent on by <a href="#automatic-dom-transaction">automatic DOM transactions</a>.</p>

    <div class="example">
        <p><a href="#manual-dom-transaction">Manual DOM transactions</a> will let authors populate items
        in the <a href="#undo-transaction-history">undo transaction history</a>. In particular, this will let
        the user agent to fill native UIs such as menu bars to display undoable actions.</p>

        <pre>
function drawLine(start, end, style) {
    document.undoManager.transact({ execute: function () {
            // Draw a line on canvas
        }, undo: function () {
            // Undraw a line
        }, redo: function () { this.execute(); },
        'Draw a line'
    });
}
</pre>

        <p>In this example, <var>drawLine()</var> will add a new entry to the document's
        <a href="#undo-transaction-history">undo transaction history</a> and the user agent can communicate the existence
        of this undoable action via UIs such as context menu and menubars.</p></div>
    </div>

<h2>Transaction, Undo, and Redo Events</h2>

    <p>When a new <a href="#dom-transaction">DOM transaction</a> is <a href="#dom-transaction-apply">applied</a> by <code><a href="#dom-undomanager-transact">transact</a>()</code> method to an <a href="#undo-transaction-history">undo transaction history</a>
    of a <code><a href="#undomanager">UndoManager</a></code>, the user agent must fire a <dfn>DOM transaction event</dfn> using
    the <code><dfn id="dom-transactionevent" title="dom-transactionEvent">TransactionEvent</dfn></code> interface.
    When a <a href="#dom-transaction">DOM transaction</a> is <a href="#dom-transaction-unapply">unapplied</a> or <a href="#dom-transaction-reapply">reapplied</a> though <code><a href="#dom-undomanager-undo">undo</a>()</code> method or
    <code><a href="#dom-undomanager-redo">redo</a>()</code> method, of a <code><a href="#undomanager">UndoManager</a></code>, the user agent must fire
    an <dfn>undo event</dfn> and a <dfn>redo event</dfn> respectively.</p>

<h3>The <code><a href="#domtransactionevent">DOMTransactionEvent</a></code> interface</h3>

    <pre class="idl">[Constructor(DOMString type, optional EventInit eventInitDict)]
interface <dfn id="domtransactionevent">DOMTransactionEvent</dfn> : <a href="http://www.whatwg.org/specs/web-apps/current-work/#event">Event</a> {
    readonly attribute Object <a href="#dom-domtransactionevent-transaction">transaction</a>;
};</pre>

    <dl class="domintro">
        <dt><var title="">DOMTransactionEvent</var> . <code title="dom-domtransactionevent-transaction"><a href="#dom-domtransactionevent-transaction">transaction</a></code></dt>
        <dd><p>Returns the transaction object that triggered this event.</p></dd>
    </dl>

    <div class="impl">
        <p>The <dfn id="dom-domtransactionevent-transaction" title="dom-DOMTransactionEvent-transaction"><code>transaction</code></dfn> attribute of
        the <code><a href="#dom-domtransactionevent">DOMTransactionEvent</a></code> interface must return the object that implements
        the <code><a href="#dom-domtransaction">DOMTransactionEvent</a></code> interface that triggered the event.</p>

        <p>When the user agent is required to <dfn>fire a DOM transaction event</dfn> for a <a href="#dom-transaction">DOM transaction</a> <var>t</var> at
        an <a href="#undo-scope-host">undo scope host</a> <var>h</var>, the user agent must run the following steps:</p>
        <ol>
            <li>Create a <code><a href="#dom-domtransactionevent">DOMTransactionEvent</a></code> object and initialize it to have the name "<code>DOMTransaction</code>",
            to bubble, to not cancelable, and to have the <code>transaction</code> attribute initialized to <var>t</var>.</li>
            <li>Dispatch the newly created <code><a href="#dom-domtransactionevent">DOMTransactionEvent</a></code> object at the node <var>h</var>.</li>
        </ol>

        <p>When the user agent is required to <dfn>fire an undo event</dfn> and <dfn>fire a redo event</dfn> for a <a href="#dom-transaction">DOM transaction</a> <var>t</var> at
        an <a href="#undo-scope-host">undo scope host</a> <var>h</var>, the user agent must run the following steps:</p>
        <ol>
            <li>Create a <code><a href="#dom-domtransactionevent">DOMTransactionEvent</a></code> object and initialize it to have the name "<code>undo</code>" and
            "<code>redo</code>" respectively, to bubble, to not cancelable, and to have the <code>transaction</code> attribute initialized to <var>t</var>.</li>
            <li>Dispatch the newly created <code><a href="#dom-domtransactionevent">TransactionEvent</a></code> object at the node <var>h</var>.</li>
        </ol>

        <p class="note">The target node is always set to a <a href="#undo-scope-host">undo scope host</a> or a node that was a <a href="#undo-scope-host">undo scope host</a>
        immediately before <var>t</var> was applied, unapplied, or reapplied.</p>
    </div>

<script src="http://www.whatwg.org/specs/web-apps/current-work/dfn.js"></script>
</body>
</html>