Refactor some of the force-value algorithm
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Thu, 26 May 2011 11:37:49 -0600
changeset 179 80d0b644c1f8
parent 178 8400d57ca296
child 180 beea6b6c9d05
Refactor some of the force-value algorithm
editcommands.html
implementation.js
source.html
--- a/editcommands.html	Thu May 26 10:51:05 2011 -0600
+++ b/editcommands.html	Thu May 26 11:37:49 2011 -0600
@@ -602,6 +602,12 @@
   <li>For each <var title="">node</var> in <var title="">node list</var>, insert <var title="">node</var>
   into the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of <var title="">original parent</var> immediately before
   <var title="">original parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
+  <!-- Notice that a boundary point that was immediately before the element
+  will now be immediately before its children, just because of the regular
+  range mutation rules, without needing to worry about preserving ranges.
+  Likewise for boundary points immediately after the element, if we wind up
+  removing the element in the final step.  Preserving ranges is only necessary
+  for the sake of boundary points in the element or its descendants. -->
 
   <li>If the last member of <var title="">node list</var> is an <a href=#inline-node>inline node</a>
   other than a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, and the first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">original parent</var> is
@@ -637,6 +643,11 @@
   <li>Otherwise, run the <a href=#new-parent-instructions>new parent instructions</a>, and let <var title="">new
   parent</var> be the result.
 
+  <li>If <var title="">new parent</var> is null, abort these steps and return null.
+  <!-- This can only happen if the new parent instructions are run and they
+  return null.  This can be used to only merge with adjacent siblings, in case
+  you don't want to create a new parent if that fails. -->
+
   <li>If <var title="">new parent</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is null, insert <var title="">new
   parent</var> into the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of the first member of <var title="">node list</var>
   immediately before the first member of <var title="">node list</var>.
@@ -648,10 +659,10 @@
   list</var> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>:
 
   <ol>
-    <li>If the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var> and the first member of
-    <var title="">node list</var> are both <a href=#inline-node title="inline node">inline
-    nodes</a>, and the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var> is not a
-    <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the
+    <li>If <var title="">new parent</var> is not an <a href=#inline-node>inline node</a>, but the
+    last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var> and the first member of <var title="">node
+    list</var> are both <a href=#inline-node title="inline node">inline nodes</a>, and the
+    last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var> is not a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the
     <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">new parent</var> and append the result as the
     last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var>.
 
@@ -663,10 +674,10 @@
   <li>Otherwise:
 
   <ol>
-    <li>If the first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var> and the last member of
-    <var title="">node list</var> are both <a href=#inline-node title="inline node">inline
-    nodes</a>, and the last member of <var title="">node list</var> is not a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>,
-    call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the
+    <li>If <var title="">new parent</var> is not an <a href=#inline-node>inline node</a>, but the
+    first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var> and the last member of <var title="">node
+    list</var> are both <a href=#inline-node title="inline node">inline nodes</a>, and the
+    last member of <var title="">node list</var> is not a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the
     <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">new parent</var> and insert the result as the
     first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var>.
 
@@ -686,7 +697,8 @@
   to merge them in this case. -->
 
   <ol>
-    <li>If <var title="">new parent</var>'s last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> and <var title="">new parent</var>'s
+    <li>If <var title="">new parent</var> is not an <a href=#inline-node>inline node</a>, but
+    <var title="">new parent</var>'s last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> and <var title="">new parent</var>'s
     <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code>'s first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> are both <a href=#inline-node title="inline node">inline
     nodes</a>, and <var title="">new parent</var>'s last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is not a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>,
     call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the
@@ -1223,6 +1235,58 @@
   <li>Return null.
 </ol>
 
+<p>To <dfn id=reorder-modifiable-descendants>reorder modifiable descendants</dfn> of a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <var title="">node</var>,
+given a <a href=#command>command</a> <var title="">command</var> and a value <var title="">new
+value</var>:
+
+<ol>
+  <li>Let <var title="">candidate</var> equal <var title="">node</var>.
+
+  <li>While <var title="">candidate</var> is a <a href=#modifiable-element>modifiable element</a>, and
+  <var title="">candidate</var> has exactly one <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, and that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is also a
+  <a href=#modifiable-element>modifiable element</a>, and <var title="">candidate</var> is not a
+  <a href=#simple-modifiable-element>simple modifiable element</a> or <var title="">candidate</var>'s
+  <a href=#specified-value>specified value</a> for <var title="">command</var> is not <var title="">new
+  value</var>, set <var title="">candidate</var> to its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>.
+
+  <li>If <var title="">candidate</var> is <var title="">node</var>, or is not a <a href=#simple-modifiable-element>simple
+  modifiable element</a>, or its <a href=#specified-value>specified value</a> and
+  <a href=#effective-value>effective value</a> for <var title="">command</var> are not both <var title="">new
+  value</var>, abort these steps.
+
+  <li>While <var title="">candidate</var> has <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>, insert the first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>
+  of <var title="">candidate</var> into <var title="">candidate</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> immediately
+  before <var title="">candidate</var>, <a href=#preserving-ranges>preserving ranges</a>.
+
+  <li>Insert <var title="">candidate</var> into <var title="">node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> immediately
+  after <var title="">node</var>.
+  <!--
+  If candidate had no children, any boundary point inside it will get moved to
+  its parent here, which is okay.  We don't want to preserve ranges, because
+  that would move boundary points that originally were in candidate but were
+  moved to its parent by the last step to move to node's parent.
+
+  We move to after node so that boundary points before and after node wind up
+  consistently inside candidate when we move preserving ranges.  If we had
+    {<node>foo<candidate></candidate></node>}
+  it thus becomes
+    {<node>foo</node>}<candidate></candidate>
+  by the range mutation rules, and then when we move preserving ranges, it
+  becomes
+    <candidate>{<node>foo</node>}</candidate>
+  which is reasonable.
+
+  If we had inserted candidate before node, instead it would go
+    {<candidate></candidate><node>foo</node>}
+    {<candidate><node>foo</node>}</candidate>
+  because of the interaction of regular range mutation rules with
+  preserving-ranges rules.
+  -->
+
+  <li>Append the <var title="">node</var> as the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">candidate</var>,
+  <a href=#preserving-ranges>preserving ranges</a>.
+</ol>
+
 
 <h3 id=decomposing-a-range-into-nodes><span class=secno>6.3 </span>Decomposing a range into nodes</h3>
 <p>To <dfn id=decompose>decompose</dfn> a <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a> <var title="">range</var>:
@@ -1292,15 +1356,7 @@
   <ol>
     <li>Let <var title="">children</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a> of <var title="">element</var>.
 
-    <li>While <var title="">element</var> has <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>, insert its first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>
-    into its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> immediately before it, <a href=#preserving-ranges>preserving ranges</a>.
-
-    <li>Remove <var title="">element</var> from its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
-    <!-- Notice that a boundary point that was immediately before or after the
-    element will now be immediately before or after its children, just because
-    of the regular range mutation rules, without needing to worry about
-    preserving ranges.  Preserving ranges is only necessary for the sake of
-    boundary points in the element or its descendants. -->
+    <li>Remove <var title="">element</var>, <a href=#preserving-its-descendants>preserving its descendants</a>.
 
     <li>Return <var title="">children</var>.
   </ol>
@@ -1508,91 +1564,19 @@
     Theoretically this algorithm could pointlessly reorganize the DOM in the
     event of unreasonable style rules, but it's not a big enough deal for us to
     care, since the resulting style will still be right. -->
-    <li>Let <var title="">candidate</var> be <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code>.
-
-    <li>While <var title="">candidate</var> is a <a href=#modifiable-element>modifiable element</a>, and
-    <var title="">candidate</var> has exactly one <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, and that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is also
-    a <a href=#modifiable-element>modifiable element</a>, and <var title="">candidate</var> is not a
-    <a href=#simple-modifiable-element>simple modifiable element</a> or <var title="">candidate</var>'s
-    <a href=#specified-value>specified value</a> for <var title="">command</var> is not <var title="">new
-    value</var>, set <var title="">candidate</var> to its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>.
-
-    <li>If <var title="">candidate</var> is a <a href=#simple-modifiable-element>simple modifiable element</a>
-    whose <a href=#specified-value>specified value</a> and <a href=#effective-value>effective value</a> for
-    <var title="">command</var> are both <var title="">new value</var>, and <var title="">candidate</var>
-    is not the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">node</var>:
-
-    <ol>
-      <li>While <var title="">candidate</var> has <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>, insert the first
-      <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">candidate</var> into <var title="">candidate</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>
-      immediately before <var title="">candidate</var>, <a href=#preserving-ranges>preserving ranges</a>.
-
-      <li>Insert <var title="">candidate</var> into <var title="">node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> before
-      <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code>.  <!-- If candidate had no
-      children, any boundary point inside it will get moved to its parent here,
-      which is okay.  We don't want to preserve ranges, because that would move
-      boundary points that originally were in candidate but were moved to its
-      parent by the last step to move to node's parent.  We move to before the
-      previous sibling so that boundary points before and after the previous
-      sibling wind up before or after candidate. -->
-
-      <li>Append the <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code> of <var title="">candidate</var> as the last
-      <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">candidate</var>, <a href=#preserving-ranges>preserving ranges</a>.
-    </ol>
-
-    <li>Let <var title="">candidate</var> be <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code>.
-
-    <li>While <var title="">candidate</var> is a <a href=#modifiable-element>modifiable element</a>, and
-    <var title="">candidate</var> has exactly one <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, and that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is also
-    a <a href=#modifiable-element>modifiable element</a>, and <var title="">candidate</var> is not a
-    <a href=#simple-modifiable-element>simple modifiable element</a> or <var title="">candidate</var>'s
-    <a href=#specified-value>specified value</a> for <var title="">command</var> is not <var title="">new
-    value</var>, set <var title="">candidate</var> to its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>.
-
-    <li>If <var title="">candidate</var> is a <a href=#simple-modifiable-element>simple modifiable element</a>
-    whose <a href=#specified-value>specified value</a> and <a href=#effective-value>effective value</a> for
-    <var title="">command</var> are both <var title="">new value</var>, and <var title="">candidate</var>
-    is not the <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code> of <var title="">node</var>:
-
-    <ol>
-      <li>While <var title="">candidate</var> has <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>, insert the first
-      <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">candidate</var> into <var title="">candidate</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>
-      immediately before <var title="">candidate</var>, <a href=#preserving-ranges>preserving ranges</a>.
-
-      <li>Insert <var title="">candidate</var> into <var title="">node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> after
-      <var title="">node</var>. <!-- Thus candidate is between the same boundary points
-      as node's next sibling, not the same as node.  When inserting, the new
-      thing always gets put in the same place as its next sibling, not its
-      previous sibling: a boundary point at the place it's inserted moves
-      before the new node, not after. -->
-
-      <li>Append the <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code> of <var title="">candidate</var> as the last
-      <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">candidate</var>, <a href=#preserving-ranges>preserving ranges</a>.
-    </ol>
-
-    <li>Let <var title="">previous sibling</var> and <var title="">next sibling</var> be
-    <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> and <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code>.
-
-    <li>If <var title="">previous sibling</var> is a <a href=#simple-modifiable-element>simple modifiable
+    <li><a href=#reorder-modifiable-descendants>Reorder modifiable descendants</a> of <var title="">node</var>'s
+    <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code>.
+
+    <li><a href=#reorder-modifiable-descendants>Reorder modifiable descendants</a> of <var title="">node</var>'s
+    <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code>.
+
+    <li><a href=#wrap>Wrap</a> the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of <var title="">node</var>,
+    with <a href=#sibling-criteria>sibling criteria</a> matching a <a href=#simple-modifiable-element>simple modifiable
     element</a> whose <a href=#specified-value>specified value</a> and <a href=#effective-value>effective
-    value</a> for <var title="">command</var> are both <var title="">new value</var>, append
-    <var title="">node</var> as the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">previous sibling</var>,
-    <a href=#preserving-ranges>preserving ranges</a>.
-
-    <li>If <var title="">next sibling</var> is a <a href=#simple-modifiable-element>simple modifiable element</a>
-    whose <a href=#specified-value>specified value</a> and <a href=#effective-value>effective value</a> for
-    <var title="">command</var> are both <var title="">new value</var>:
-
-    <ol>
-      <li>If <var title="">node</var> is not a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">previous sibling</var>,
-      insert <var title="">node</var> as the first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">next sibling</var>,
-      <a href=#preserving-ranges>preserving ranges</a>.
-
-      <li>Otherwise, while <var title="">next sibling</var> has <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>, append the
-      first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">next sibling</var> as the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of
-      <var title="">previous sibling</var>, <a href=#preserving-ranges>preserving ranges</a>.  Then remove
-      <var title="">next sibling</var> from its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
-    </ol>
+    value</a> for <var title="">command</var> are both <var title="">new value</var>, and with
+    <a href=#new-parent-instructions>new parent instructions</a> returning null.
+    <!-- The new parent instructions are too complicated to reasonably feed
+    into the wrap algorithm. -->
   </ol>
 
   <li>If the <a href=#effective-value>effective value</a> of <var title="">command</var> is <var title="">new
--- a/implementation.js	Thu May 26 10:51:05 2011 -0600
+++ b/implementation.js	Thu May 26 11:37:49 2011 -0600
@@ -574,6 +574,11 @@
 		newParent = newParentInstructions();
 	}
 
+	// "If new parent is null, abort these steps and return null."
+	if (!newParent) {
+		return null;
+	}
+
 	// "If new parent's parent is null, insert new parent into the parent of
 	// the first member of node list immediately before the first member of
 	// node list."
@@ -586,11 +591,13 @@
 
 	// "If new parent is before the first member of node list in tree order:"
 	if (isBefore(newParent, nodeList[0])) {
-		// "If the last child of new parent and the first member of node list
-		// are both inline nodes, and the last child of new parent is not a br,
-		// call createElement("br") on the ownerDocument of new parent and
-		// append the result as the last child of new parent."
-		if (isInlineNode(newParent.lastChild)
+		// "If new parent is not an inline node, but the last child of new
+		// parent and the first member of node list are both inline nodes, and
+		// the last child of new parent is not a br, call createElement("br")
+		// on the ownerDocument of new parent and append the result as the last
+		// child of new parent."
+		if (!isInlineNode(newParent)
+		&& isInlineNode(newParent.lastChild)
 		&& isInlineNode(nodeList[0])
 		&& !isHtmlElement(newParent.lastChild, "BR")) {
 			newParent.appendChild(newParent.ownerDocument.createElement("br"));
@@ -604,11 +611,13 @@
 
 	// "Otherwise:"
 	} else {
-		// "If the first child of new parent and the last member of node list
-		// are both inline nodes, and the last member of node list is not a br,
-		// call createElement("br") on the ownerDocument of new parent and
-		// insert the result as the first child of new parent."
-		if (isInlineNode(newParent.firstChild)
+		// "If new parent is not an inline node, but the first child of new
+		// parent and the last member of node list are both inline nodes, and
+		// the last member of node list is not a br, call createElement("br")
+		// on the ownerDocument of new parent and insert the result as the
+		// first child of new parent."
+		if (!isInlineNode(newParent)
+		&& isInlineNode(newParent.firstChild)
 		&& isInlineNode(nodeList[nodeList.length - 1])
 		&& !isHtmlElement(nodeList[nodeList.length - 1], "BR")) {
 			newParent.insertBefore(newParent.ownerDocument.createElement("br"), newParent.firstChild);
@@ -631,11 +640,13 @@
 	// criteria:"
 	if (isEditable(newParent.nextSibling)
 	&& siblingCriteria(newParent.nextSibling)) {
-		// "If new parent's last child and new parent's nextSibling's first
-		// child are both inline nodes, and new parent's last child is not a
-		// br, call createElement("br") on the ownerDocument of new parent and
-		// append the result as the last child of new parent."
-		if (isInlineNode(newParent.lastChild)
+		// "If new parent is not an inline node, but new parent's last child
+		// and new parent's nextSibling's first child are both inline nodes,
+		// and new parent's last child is not a br, call createElement("br") on
+		// the ownerDocument of new parent and append the result as the last
+		// child of new parent."
+		if (!isInlineNode(newParent)
+		&& isInlineNode(newParent.lastChild)
 		&& isInlineNode(newParent.nextSibling.firstChild)
 		&& !isHtmlElement(newParent.lastChild, "BR")) {
 			newParent.appendChild(newParent.ownerDocument.createElement("br"));
@@ -1473,6 +1484,44 @@
 	return null;
 }
 
+function reorderModifiableDescendants(node, command, newValue) {
+	// "Let candidate equal node."
+	var candidate = node;
+
+	// "While candidate is a modifiable element, and candidate has exactly one
+	// child, and that child is also a modifiable element, and candidate is not
+	// a simple modifiable element or candidate's specified value for command
+	// is not new value, set candidate to its child."
+	while (isModifiableElement(candidate)
+	&& candidate.childNodes.length == 1
+	&& (!isSimpleModifiableElement(candidate)
+	|| !valuesEqual(command, getSpecifiedValue(candidate, command), newValue))) {
+		candidate = candidate.firstChild;
+	}
+
+	// "If candidate is node, or is not a simple modifiable element, or its
+	// specified value and effective value for command are not both new value,
+	// abort these steps."
+	if (candidate == node
+	|| !isSimpleModifiableElement(candidate)
+	|| !valuesEqual(command, getSpecifiedValue(candidate, command), newValue)
+	|| !valuesEqual(command, getEffectiveValue(candidate, command), newValue)) {
+		return;
+	}
+
+	// "While candidate has children, insert the first child of candidate into
+	// candidate's parent immediately before candidate, preserving ranges."
+	while (candidate.hasChildNodes()) {
+		movePreservingRanges(candidate.firstChild, candidate.parentNode, getNodeIndex(candidate));
+	}
+
+	// "Insert candidate into node's parent immediately after node."
+	node.parentNode.insertBefore(candidate, node.nextSibling);
+
+	// "Append the node as the last child of candidate, preserving ranges."
+	movePreservingRanges(node, candidate, -1);
+}
+
 // "A modifiable element is a b, em, i, s, span, strong, sub, sup, or u element
 // with no attributes except possibly style; or a font element with no
 // attributes except possibly style, color, face, and/or size; or an a element
@@ -2192,114 +2241,24 @@
 	|| node.nodeType == Node.COMMENT_NODE
 	|| node.nodeType == Node.PROCESSING_INSTRUCTION_NODE)
 	&& !isUnwrappableNode(node)) {
-		// "Let candidate be node's previousSibling."
-		var candidate = node.previousSibling;
-
-		// "While candidate is a modifiable element, and candidate has exactly one
-		// child, and that child is also a modifiable element, and candidate is
-		// not a simple modifiable element or candidate's specified value for
-		// command is not new value, set candidate to its child."
-		while (isModifiableElement(candidate)
-		&& candidate.childNodes.length == 1
-		&& isModifiableElement(candidate.firstChild)
-		&& (!isSimpleModifiableElement(candidate)
-		|| !valuesEqual(command, getSpecifiedValue(candidate, command), newValue))) {
-			candidate = candidate.firstChild;
-		}
-
-		// "If candidate is a simple modifiable element whose specified value and
-		// effective value for command are both new value, and candidate is
-		// not the previousSibling of node:"
-		if (isSimpleModifiableElement(candidate)
-		&& valuesEqual(command, getSpecifiedValue(candidate, command), newValue)
-		&& valuesEqual(command, getEffectiveValue(candidate, command), newValue)
-		&& candidate != node.previousSibling) {
-			// "While candidate has children, insert the first child of
-			// candidate into candidate's parent immediately before candidate,
-			// preserving ranges."
-			while (candidate.childNodes.length > 0) {
-				movePreservingRanges(candidate.firstChild, candidate.parentNode, getNodeIndex(candidate));
-			}
-
-			// "Insert candidate into node's parent before node's
-			// previousSibling."
-			node.parentNode.insertBefore(candidate, node.previousSibling);
-
-			// "Append the nextSibling of candidate as the last child of
-			// candidate, preserving ranges."
-			movePreservingRanges(candidate.nextSibling, candidate, candidate.childNodes.length);
-		}
-
-		// "Let candidate be node's nextSibling."
-		var candidate = node.nextSibling;
-
-		// "While candidate is a modifiable element, and candidate has exactly one
-		// child, and that child is also a modifiable element, and candidate is
-		// not a simple modifiable element or candidate's specified value for
-		// command is not new value, set candidate to its child."
-		while (isModifiableElement(candidate)
-		&& candidate.childNodes.length == 1
-		&& isModifiableElement(candidate.firstChild)
-		&& (!isSimpleModifiableElement(candidate)
-		|| !valuesEqual(command, getSpecifiedValue(candidate, command), newValue))) {
-			candidate = candidate.firstChild;
-		}
-
-		// "If candidate is a simple modifiable element whose specified value and
-		// effective value for command are both new value, and candidate is
-		// not the nextSibling of node:"
-		if (isSimpleModifiableElement(candidate)
-		&& valuesEqual(command, getSpecifiedValue(candidate, command), newValue)
-		&& valuesEqual(command, getEffectiveValue(candidate, command), newValue)
-		&& candidate != node.nextSibling) {
-			// "While candidate has children, insert the first child of
-			// candidate into candidate's parent immediately before candidate,
-			// preserving ranges."
-			while (candidate.childNodes.length > 0) {
-				movePreservingRanges(candidate.firstChild, candidate.parentNode, getNodeIndex(candidate));
-			}
-
-			// "Insert candidate into node's parent after node."
-			node.parentNode.insertBefore(candidate, node.nextSibling);
-
-			// "Append the nextSibling of candidate as the last child of
-			// candidate, preserving ranges."
-			movePreservingRanges(candidate.nextSibling, candidate, candidate.childNodes.length);
-		}
-
-		// "Let previous sibling and next sibling be node's previousSibling and
-		// nextSibling."
-		var previousSibling = node.previousSibling;
-		var nextSibling = node.nextSibling;
-
-		// "If previous sibling is a simple modifiable element whose specified
-		// value and effective value for command are both new value, append
-		// node as the last child of previous sibling, preserving ranges."
-		if (isSimpleModifiableElement(previousSibling)
-		&& valuesEqual(command, getSpecifiedValue(previousSibling, command), newValue)
-		&& valuesEqual(command, getEffectiveValue(previousSibling, command), newValue)) {
-			movePreservingRanges(node, previousSibling, previousSibling.childNodes.length);
-		}
-
-		// "If next sibling is a simple modifiable element whose specified value
-		// and effective value for command are both new value:"
-		if (isSimpleModifiableElement(nextSibling)
-		&& valuesEqual(command, getSpecifiedValue(nextSibling, command), newValue)
-		&& valuesEqual(command, getEffectiveValue(nextSibling, command), newValue)) {
-			// "If node is not a child of previous sibling, insert node as the
-			// first child of next sibling, preserving ranges."
-			if (node.parentNode != previousSibling) {
-				movePreservingRanges(node, nextSibling, 0);
-			// "Otherwise, while next sibling has children, append the first
-			// child of next sibling as the last child of previous sibling,
-			// preserving ranges.  Then remove next sibling from its parent."
-			} else {
-				while (nextSibling.childNodes.length) {
-					movePreservingRanges(nextSibling.firstChild, previousSibling, previousSibling.childNodes.length);
-				}
-				nextSibling.parentNode.removeChild(nextSibling);
-			}
-		}
+		// "Reorder modifiable descendants of node's previousSibling."
+		reorderModifiableDescendants(node.previousSibling, command, newValue);
+
+		// "Reorder modifiable descendants of node's nextSibling."
+		reorderModifiableDescendants(node.nextSibling, command, newValue);
+
+		// "Wrap the one-node list consisting of node, with sibling criteria
+		// matching a simple modifiable element whose specified value and
+		// effective value for command are both new value, and with new parent
+		// instructions returning null."
+		wrap([node],
+			function(node) {
+				return isSimpleModifiableElement(node)
+					&& valuesEqual(command, getSpecifiedValue(node, command), newValue)
+					&& valuesEqual(command, getEffectiveValue(node, command), newValue);
+			},
+			function() { return null }
+		);
 	}
 
 	// "If the effective value of command is new value on node, abort this
--- a/source.html	Thu May 26 10:51:05 2011 -0600
+++ b/source.html	Thu May 26 11:37:49 2011 -0600
@@ -561,6 +561,12 @@
   <li>For each <var>node</var> in <var>node list</var>, insert <var>node</var>
   into the [[parent]] of <var>original parent</var> immediately before
   <var>original parent</var>, <span>preserving ranges</span>.
+  <!-- Notice that a boundary point that was immediately before the element
+  will now be immediately before its children, just because of the regular
+  range mutation rules, without needing to worry about preserving ranges.
+  Likewise for boundary points immediately after the element, if we wind up
+  removing the element in the final step.  Preserving ranges is only necessary
+  for the sake of boundary points in the element or its descendants. -->
 
   <li>If the last member of <var>node list</var> is an <span>inline node</span>
   other than a [[br]], and the first [[child]] of <var>original parent</var> is
@@ -596,6 +602,11 @@
   <li>Otherwise, run the <span>new parent instructions</span>, and let <var>new
   parent</var> be the result.
 
+  <li>If <var>new parent</var> is null, abort these steps and return null.
+  <!-- This can only happen if the new parent instructions are run and they
+  return null.  This can be used to only merge with adjacent siblings, in case
+  you don't want to create a new parent if that fails. -->
+
   <li>If <var>new parent</var>'s [[parent]] is null, insert <var>new
   parent</var> into the [[parent]] of the first member of <var>node list</var>
   immediately before the first member of <var>node list</var>.
@@ -607,10 +618,11 @@
   list</var> in [[treeorder]]:
 
   <ol>
-    <li>If the last [[child]] of <var>new parent</var> and the first member of
-    <var>node list</var> are both <span title="inline node">inline
-    nodes</span>, and the last [[child]] of <var>new parent</var> is not a
-    [[br]], call <code data-anolis-spec=domcore
+    <li>If <var>new parent</var> is not an <span>inline node</span>, but the
+    last [[child]] of <var>new parent</var> and the first member of <var>node
+    list</var> are both <span title="inline node">inline nodes</span>, and the
+    last [[child]] of <var>new parent</var> is not a [[br]], call <code
+    data-anolis-spec=domcore
     title=dom-Document-createElement>createElement("br")</code> on the
     [[ownerdocument]] of <var>new parent</var> and append the result as the
     last [[child]] of <var>new parent</var>.
@@ -623,10 +635,11 @@
   <li>Otherwise:
 
   <ol>
-    <li>If the first [[child]] of <var>new parent</var> and the last member of
-    <var>node list</var> are both <span title="inline node">inline
-    nodes</span>, and the last member of <var>node list</var> is not a [[br]],
-    call <code data-anolis-spec=domcore
+    <li>If <var>new parent</var> is not an <span>inline node</span>, but the
+    first [[child]] of <var>new parent</var> and the last member of <var>node
+    list</var> are both <span title="inline node">inline nodes</span>, and the
+    last member of <var>node list</var> is not a [[br]], call <code
+    data-anolis-spec=domcore
     title=dom-Document-createElement>createElement("br")</code> on the
     [[ownerdocument]] of <var>new parent</var> and insert the result as the
     first [[child]] of <var>new parent</var>.
@@ -647,7 +660,8 @@
   to merge them in this case. -->
 
   <ol>
-    <li>If <var>new parent</var>'s last [[child]] and <var>new parent</var>'s
+    <li>If <var>new parent</var> is not an <span>inline node</span>, but
+    <var>new parent</var>'s last [[child]] and <var>new parent</var>'s
     [[nextsibling]]'s first [[child]] are both <span title="inline node">inline
     nodes</span>, and <var>new parent</var>'s last [[child]] is not a [[br]],
     call <code data-anolis-spec=domcore
@@ -1192,6 +1206,58 @@
   <li>Return null.
 </ol>
 
+<p>To <dfn>reorder modifiable descendants</dfn> of a [[node]] <var>node</var>,
+given a <span>command</span> <var>command</var> and a value <var>new
+value</var>:
+
+<ol>
+  <li>Let <var>candidate</var> equal <var>node</var>.
+
+  <li>While <var>candidate</var> is a <span>modifiable element</span>, and
+  <var>candidate</var> has exactly one [[child]], and that [[child]] is also a
+  <span>modifiable element</span>, and <var>candidate</var> is not a
+  <span>simple modifiable element</span> or <var>candidate</var>'s
+  <span>specified value</span> for <var>command</var> is not <var>new
+  value</var>, set <var>candidate</var> to its [[child]].
+
+  <li>If <var>candidate</var> is <var>node</var>, or is not a <span>simple
+  modifiable element</span>, or its <span>specified value</span> and
+  <span>effective value</span> for <var>command</var> are not both <var>new
+  value</var>, abort these steps.
+
+  <li>While <var>candidate</var> has [[children]], insert the first [[child]]
+  of <var>candidate</var> into <var>candidate</var>'s [[parent]] immediately
+  before <var>candidate</var>, <span>preserving ranges</span>.
+
+  <li>Insert <var>candidate</var> into <var>node</var>'s [[parent]] immediately
+  after <var>node</var>.
+  <!--
+  If candidate had no children, any boundary point inside it will get moved to
+  its parent here, which is okay.  We don't want to preserve ranges, because
+  that would move boundary points that originally were in candidate but were
+  moved to its parent by the last step to move to node's parent.
+
+  We move to after node so that boundary points before and after node wind up
+  consistently inside candidate when we move preserving ranges.  If we had
+    {<node>foo<candidate></candidate></node>}
+  it thus becomes
+    {<node>foo</node>}<candidate></candidate>
+  by the range mutation rules, and then when we move preserving ranges, it
+  becomes
+    <candidate>{<node>foo</node>}</candidate>
+  which is reasonable.
+
+  If we had inserted candidate before node, instead it would go
+    {<candidate></candidate><node>foo</node>}
+    {<candidate><node>foo</node>}</candidate>
+  because of the interaction of regular range mutation rules with
+  preserving-ranges rules.
+  -->
+
+  <li>Append the <var>node</var> as the last [[child]] of <var>candidate</var>,
+  <span>preserving ranges</span>.
+</ol>
+
 
 <h3>Decomposing a range into nodes</h3>
 <p>To <dfn>decompose</dfn> a [[range]] <var>range</var>:
@@ -1265,15 +1331,7 @@
   <ol>
     <li>Let <var>children</var> be the [[children]] of <var>element</var>.
 
-    <li>While <var>element</var> has [[children]], insert its first [[child]]
-    into its [[parent]] immediately before it, <span>preserving ranges</span>.
-
-    <li>Remove <var>element</var> from its [[parent]].
-    <!-- Notice that a boundary point that was immediately before or after the
-    element will now be immediately before or after its children, just because
-    of the regular range mutation rules, without needing to worry about
-    preserving ranges.  Preserving ranges is only necessary for the sake of
-    boundary points in the element or its descendants. -->
+    <li>Remove <var>element</var>, <span>preserving its descendants</span>.
 
     <li>Return <var>children</var>.
   </ol>
@@ -1482,91 +1540,19 @@
     Theoretically this algorithm could pointlessly reorganize the DOM in the
     event of unreasonable style rules, but it's not a big enough deal for us to
     care, since the resulting style will still be right. -->
-    <li>Let <var>candidate</var> be <var>node</var>'s [[previoussibling]].
-
-    <li>While <var>candidate</var> is a <span>modifiable element</span>, and
-    <var>candidate</var> has exactly one [[child]], and that [[child]] is also
-    a <span>modifiable element</span>, and <var>candidate</var> is not a
-    <span>simple modifiable element</span> or <var>candidate</var>'s
-    <span>specified value</span> for <var>command</var> is not <var>new
-    value</var>, set <var>candidate</var> to its [[child]].
-
-    <li>If <var>candidate</var> is a <span>simple modifiable element</span>
-    whose <span>specified value</span> and <span>effective value</span> for
-    <var>command</var> are both <var>new value</var>, and <var>candidate</var>
-    is not the [[previoussibling]] of <var>node</var>:
-
-    <ol>
-      <li>While <var>candidate</var> has [[children]], insert the first
-      [[child]] of <var>candidate</var> into <var>candidate</var>'s [[parent]]
-      immediately before <var>candidate</var>, <span>preserving ranges</span>.
-
-      <li>Insert <var>candidate</var> into <var>node</var>'s [[parent]] before
-      <var>node</var>'s [[previoussibling]].  <!-- If candidate had no
-      children, any boundary point inside it will get moved to its parent here,
-      which is okay.  We don't want to preserve ranges, because that would move
-      boundary points that originally were in candidate but were moved to its
-      parent by the last step to move to node's parent.  We move to before the
-      previous sibling so that boundary points before and after the previous
-      sibling wind up before or after candidate. -->
-
-      <li>Append the [[nextsibling]] of <var>candidate</var> as the last
-      [[child]] of <var>candidate</var>, <span>preserving ranges</span>.
-    </ol>
-
-    <li>Let <var>candidate</var> be <var>node</var>'s [[nextsibling]].
-
-    <li>While <var>candidate</var> is a <span>modifiable element</span>, and
-    <var>candidate</var> has exactly one [[child]], and that [[child]] is also
-    a <span>modifiable element</span>, and <var>candidate</var> is not a
-    <span>simple modifiable element</span> or <var>candidate</var>'s
-    <span>specified value</span> for <var>command</var> is not <var>new
-    value</var>, set <var>candidate</var> to its [[child]].
-
-    <li>If <var>candidate</var> is a <span>simple modifiable element</span>
-    whose <span>specified value</span> and <span>effective value</span> for
-    <var>command</var> are both <var>new value</var>, and <var>candidate</var>
-    is not the [[nextsibling]] of <var>node</var>:
-
-    <ol>
-      <li>While <var>candidate</var> has [[children]], insert the first
-      [[child]] of <var>candidate</var> into <var>candidate</var>'s [[parent]]
-      immediately before <var>candidate</var>, <span>preserving ranges</span>.
-
-      <li>Insert <var>candidate</var> into <var>node</var>'s [[parent]] after
-      <var>node</var>. <!-- Thus candidate is between the same boundary points
-      as node's next sibling, not the same as node.  When inserting, the new
-      thing always gets put in the same place as its next sibling, not its
-      previous sibling: a boundary point at the place it's inserted moves
-      before the new node, not after. -->
-
-      <li>Append the [[nextsibling]] of <var>candidate</var> as the last
-      [[child]] of <var>candidate</var>, <span>preserving ranges</span>.
-    </ol>
-
-    <li>Let <var>previous sibling</var> and <var>next sibling</var> be
-    <var>node</var>'s [[previoussibling]] and [[nextsibling]].
-
-    <li>If <var>previous sibling</var> is a <span>simple modifiable
+    <li><span>Reorder modifiable descendants</span> of <var>node</var>'s
+    [[previoussibling]].
+
+    <li><span>Reorder modifiable descendants</span> of <var>node</var>'s
+    [[nextsibling]].
+
+    <li><span>Wrap</span> the one-[[node]] list consisting of <var>node</var>,
+    with <span>sibling criteria</span> matching a <span>simple modifiable
     element</span> whose <span>specified value</span> and <span>effective
-    value</span> for <var>command</var> are both <var>new value</var>, append
-    <var>node</var> as the last [[child]] of <var>previous sibling</var>,
-    <span>preserving ranges</span>.
-
-    <li>If <var>next sibling</var> is a <span>simple modifiable element</span>
-    whose <span>specified value</span> and <span>effective value</span> for
-    <var>command</var> are both <var>new value</var>:
-
-    <ol>
-      <li>If <var>node</var> is not a [[child]] of <var>previous sibling</var>,
-      insert <var>node</var> as the first [[child]] of <var>next sibling</var>,
-      <span>preserving ranges</span>.
-
-      <li>Otherwise, while <var>next sibling</var> has [[children]], append the
-      first [[child]] of <var>next sibling</var> as the last [[child]] of
-      <var>previous sibling</var>, <span>preserving ranges</span>.  Then remove
-      <var>next sibling</var> from its [[parent]].
-    </ol>
+    value</span> for <var>command</var> are both <var>new value</var>, and with
+    <span>new parent instructions</span> returning null.
+    <!-- The new parent instructions are too complicated to reasonably feed
+    into the wrap algorithm. -->
   </ol>
 
   <li>If the <span>effective value</span> of <var>command</var> is <var>new