Refactor block-splitting
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Fri, 13 May 2011 12:06:45 -0600
changeset 112 b82d94bbf47a
parent 111 b6104db990af
child 113 f0364f15f506
Refactor block-splitting

This doesn't reduce the size much if at all, but it's needed for the
future. Shouldn't change any output for the worse.
editcommands.html
implementation.js
source.html
--- a/editcommands.html	Fri May 13 12:06:02 2011 -0600
+++ b/editcommands.html	Fri May 13 12:06:45 2011 -0600
@@ -239,39 +239,143 @@
   <li>If <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> is null, remove all of <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-child title=concept-tree-child>children</a> from <var title="">node</var>, then return <var title="">children</var>.
 
+  <li><a href=#remove-extraneous-line-breaks>Remove extraneous line breaks</a> from <var title="">node</var>.
+
+  <li>If <var title="">node</var> is not an <a href=#inline-node>inline node</a>, and 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> and <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> are both <a href=#inline-node title="inline node">inline
+  nodes</a>, 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="">node</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="">node</var>, and insert the result 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 before <var title="">node</var>.
+
   <li>While <var title="">node</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="">node</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 before
   <var title="">node</var>, <a href=#preserving-ranges>preserving ranges</a>.
 
+  <li>If <var title="">node</var> is not an <a href=#inline-node>inline node</a>, and its
+  <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> are both <a href=#inline-node title="inline
+  node">inline nodes</a> but neither is 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="">node</var>, and insert the result 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 before <var title="">node</var>.
+
   <li>Remove <var title="">node</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>.
 
   <li>Return <var title="">children</var>.
 </ol>
 
-<p>To <dfn id=split-the-parent>split the parent</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>:
+<p>To <dfn id=split-the-parent>split the parent</dfn> of a list <var title="">node list</var> of consecutive
+<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-sibling title=concept-tree-sibling>sibling</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>nodes</a>, with <var title="">new parent</var> either null or an
+<code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code>:
 
 <ol>
-  <li>If <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> or <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> is null, do nothing
-  and abort these steps.
-
-  <li>Let <var title="">parent</var> be 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="">node</var>.
-
-  <li>Let <var title="">new parent</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Node-cloneNode><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-clonenode>cloneNode(false)</a></code>
-  on <var title="">parent</var>.
-
-  <p class=XXX>This will duplicate id's, as well as other bad things.  Do we
-  care?  We don't want to not copy attributes at all, because that wouldn't
-  copy style attributes, and Firefox in CSS mode will actually add style
-  attributes to any elements it feels like.  If we do exclude id's, even though
-  they'd only occur if someone manually added them, do we want to exclude other
-  things like itemid or accesskey or . . .
-
-  <li>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 <var title="">parent</var>
-  immediately after <var title="">parent</var>.
-
-  <li>While 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> is not null, insert 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="">parent</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="">new
-  parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
+  <li>Let <var title="">original parent</var> be 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>.
+
+  <li>If <var title="">original parent</var> is not <a href=#editable>editable</a> or 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> is null, do nothing and abort these steps.
+
+  <li>If 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 the first member of <var title="">node list</var> is
+  not null, and 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 the last member of <var title="">node list</var>
+  is null:
+
+  <div class=XXX>
+  <p>We insert things after the parent.  This is bad, because it will cause
+  them to become part of any ranges that immediately follow.  For instance, if
+  we're hitting "bar" in
+
+  </p><xmp><div><p>foo<p>bar</div>{<p>baz}</xmp>
+
+  <p>it becomes
+
+  </p><xmp><div><p>foo</div>{<p>bar<p>baz}</xmp>
+
+  <p>instead of
+
+  </p><xmp><div><p>foo</div><p>bar{<p>baz}</xmp>
+
+  <p>because of how range mutation rules work.  This doesn't happen if we
+  insert before.  Probably this isn't important enough to try working around,
+  though.
+  </div>
+
+  <ol>
+    <li>If <var title="">new parent</var> is null:
+
+    <ol>
+      <li>If the last member of <var title="">node list</var> and 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="">original parent</var> are both <a href=#inline-node title="inline node">inline
+      nodes</a>, 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="">original parent</var>, then insert the result
+      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 after
+      <var title="">original parent</var>.
+
+      <li>For each <var title="">node</var> in <var title="">node list</var>, <em>in reverse
+      order</em>, 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 after <var title="">original parent</var>,
+      <a href=#preserving-ranges>preserving ranges</a>.
+    </ol>
+
+    <li>Otherwise:
+
+    <ol>
+      <li>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 <var title="">original
+      parent</var> immediately after <var title="">original parent</var>.
+
+      <li>For each <var title="">node</var> in <var title="">node list</var>, <em>in reverse
+      order</em>, 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="">new
+      parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
+    </ol>
+
+    <li>Abort these steps.
+  </ol>
+
+  <li>If 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 the first member of <var title="">node list</var> is
+  not null:
+
+  <ol>
+    <li>Let <var title="">cloned parent</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Node-cloneNode><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-clonenode>cloneNode(false)</a></code>
+    on <var title="">original parent</var>.
+
+    <p class=XXX>This will duplicate id's, as well as other bad things.  Do we
+    care?  We don't want to not copy attributes at all, because that wouldn't
+    copy style attributes, and Firefox in CSS mode will actually add style
+    attributes to any elements it feels like.  If we do exclude id's, even
+    though they'd only occur if someone manually added them, do we want to
+    exclude other things like itemid or accesskey or . . .
+
+    <li>Insert <var title="">cloned 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 <var title="">original
+    parent</var> immediately before <var title="">original parent</var>.
+
+    <li>While 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 the first member of <var title="">node
+    list</var> is not null, 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="">original
+    parent</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="">cloned parent</var>,
+    <a href=#preserving-ranges>preserving ranges</a>.
+  </ol>
+
+  <li>If <var title="">new parent</var> is null:
+
+  <ol>
+    <li>If the first member of <var title="">node list</var> and 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="">original parent</var> are both <a href=#inline-node title="inline node">inline
+    nodes</a>, 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="">original parent</var>, then insert the result
+    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>.
+
+    <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>.
+
+    <li>Abort these steps.
+  </ol>
+
+  <li>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 <var title="">original
+  parent</var> immediately before <var title="">original parent</var>.
+
+  <li>For each <var title="">node</var> in <var title="">node list</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="">new parent</var>, <a href=#preserving-ranges>preserving
+  ranges</a>.
 </ol>
 
 <p>To <dfn id=remove-extraneous-line-breaks>remove extraneous line breaks</dfn> from 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>:
@@ -2681,6 +2785,9 @@
   different from how it would work if you reversed the commands.
   OpenOffice.org 3.2.1 (Ubuntu) and Word 2007 both agree with the spec in this
   case.
+
+  We don't ask whether the node's parent can contain an <ol>.  The only place
+  where this is likely to cause serious problems is <p>, which we special-case.
   -->
 
   <p class=XXX>Similar to a number of other places in the spec, "can be the
@@ -2727,45 +2834,24 @@
       an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, remove the first member from <var title="">node list</var>
       and append it to <var title="">sublist</var>.
 
-      <li>If 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 the first member of <var title="">sublist</var>
-      is null:
-
-      <ol>
-        <li>Let <var title="">ol</var> be 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 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="">sublist</var>.
-
-        <li>If <var title="">ol</var> is not an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>, let <var title="">ol</var> be the result
-        of calling <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("ol")</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 the first member of <var title="">sublist</var>.  Then
-        insert <var title="">ol</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 <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="">sublist</var>, immediately before 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="">sublist</var>.
-
-        <li>For each <var title="">node</var> in <var title="">sublist</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="">ol</var>,
-        <a href=#preserving-ranges>preserving ranges</a>.
-      </ol>
-
-      <li>Otherwise:
-
-      <ol>
-        <li><a href=#split-the-parent>Split the parent</a> of the last member of
-        <var title="">sublist</var>.
-
-        <li>Let <var title="">ol</var> be 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 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="">sublist</var>.
-
-        <li>If <var title="">ol</var> is not an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>, let <var title="">ol</var> be the result
-        of calling <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("ol")</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 the first member of <var title="">sublist</var>.  Then
-        insert <var title="">ol</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 <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="">sublist</var>, immediately after 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="">sublist</var>.
-
-        <li>For each <var title="">node</var> in <var title="">sublist</var> <em>in reverse
-        order</em>, 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="">ol</var>, <a href=#preserving-ranges>preserving ranges</a>.
-      </ol>
+      <li>If 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 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="">sublist</var> is an <a href=#editable>editable</a> <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>, and 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 the first member of <var title="">sublist</var> is null,
+      then for each <var title="">node</var> in <var title="">sublist</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 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 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="">node</var>, <a href=#preserving-ranges>preserving ranges</a>.
+
+      <li>Otherwise, if 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 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="">sublist</var> is an <a href=#editable>editable</a> <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>, and 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 the last member of <var title="">sublist</var> is null, then
+      for each <var title="">node</var> in <var title="">sublist</var> <em>in reverse order</em>,
+      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 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
+      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="">node</var>, <a href=#preserving-ranges>preserving ranges</a>.
+
+      <li>Otherwise, let <var title="">ol</var> be the result of calling <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("ol")</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 the first member of <var title="">sublist</var>.  Then
+      <a href=#split-the-parent>split the parent</a> of <var title="">sublist</var>, with <var title="">new
+      parent</var> <var title="">ol</var>.
     </ol>
 
     <li>Otherwise:
@@ -3169,86 +3255,19 @@
 <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-sibling title=concept-tree-sibling>sibling</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>nodes</a>:
 
 <ol>
-  <li>Let <var title="">parent</var> be 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>.
-
-  <li>If 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 the first member of <var title="">node list</var> is
-  null:
+  <li><a href=#split-the-parent>Split the parent</a> of <var title="">node list</var>, with <var title="">new
+  parent</var> null.
+
+  <li>For each <var title="">node</var> in <var title="">node list</var>:
 
   <ol>
-    <li>For each <var title="">node</var> in <var title="">node list</var>:
-
-    <ol>
-      <li>If <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>, unset its <code class=external data-anolis-spec=html title=attr-li-value><a href=http://www.whatwg.org/html/#attr-li-value>value</a></code> attribute if set.
-
-      <li>If <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> with no attributes, and 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="">parent</var> is not an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>:
-
-      <ol>
-        <li>If 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="">parent</var> 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="">node</var> are both <a href=#inline-node title="inline node">inline
-        nodes</a>, let <var title="">br</var> be the result of calling <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="">node</var>, then insert <var title="">br</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="">parent</var> immediately before
-        <var title="">parent</var>.
-
-        <li>While <var title="">node</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="">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="">parent</var> immediately
-        before <var title="">parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
-
-        <li>Remove <var title="">node</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>
-
-      <li>Otherwise:
-
-      <ol>
-        <li>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="">parent</var>
-        immediately before <var title="">parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
-
-        <li>If <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> and 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="">parent</var> is not an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, <a href=#set-the-tag-name>set the tag
-        name</a> of <var title="">node</var> to <code class=external data-anolis-spec=html title="the div element"><a href=http://www.whatwg.org/html/#the-div-element>div</a></code>.
-      </ol>
-    </ol>
-
-    <li>Abort these steps.
-  </ol>
-
-  <li><a href=#split-the-parent>Split the parent</a> of the last member of <var title="">node list</var>.
-
-  <li>For each <var title="">node</var> in <var title="">node list</var>, <em>in reverse
-  order</em>:
-
-  <ol>
-    <li>If <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>, unset its <code class=external data-anolis-spec=html title=attr-li-value><a href=http://www.whatwg.org/html/#attr-li-value>value</a></code> attribute if set.
-
-    <li>If <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> with no attributes, and 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="">parent</var> is not an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>:
-
-    <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="">node</var> and 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="">parent</var> are both <a href=#inline-node title="inline node">inline nodes</a>,
-      let <var title="">br</var> be the result of calling <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="">node</var>, then insert <var title="">br</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="">parent</var> immediately after <var title="">parent</var>.
-
-      <li>While <var title="">node</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 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="">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="">parent</var> immediately
-      after <var title="">parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
-
-      <li>Remove <var title="">node</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>
-
-    <li>Otherwise:
-
-    <ol>
-      <li>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="">parent</var>
-      immediately after <var title="">parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
-
-      <li>If <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> and 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="">parent</var> is not an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, <a href=#set-the-tag-name>set the tag
-      name</a> of <var title="">node</var> to <code class=external data-anolis-spec=html title="the div element"><a href=http://www.whatwg.org/html/#the-div-element>div</a></code>.
-    </ol>
+    <li>If <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> with no attributes and 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>
+    is not an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, remove <var title="">node</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>,
+    <a href=#preserving-its-descendants>preserving its descendants</a>.
+
+    <li>Otherwise, if <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> and 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> is not an
+    <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, <a href=#set-the-tag-name>set the tag name</a> of <var title="">node</var> to
+    "div".
   </ol>
 </ol>
 
--- a/implementation.js	Fri May 13 12:06:02 2011 -0600
+++ b/implementation.js	Fri May 13 12:06:45 2011 -0600
@@ -396,12 +396,38 @@
 		return children;
 	}
 
+	// "Remove extraneous line breaks from node."
+	removeExtraneousLineBreaks(node);
+
+	// "If node is not an inline node, and its first child and previousSibling
+	// are both inline nodes, and the first child of node is not a br, call
+	// createElement("br") on the ownerDocument of node, and insert the result
+	// into node's parent immediately before node."
+	if (!isInlineNode(node)
+	&& isInlineNode(node.firstChild)
+	&& isInlineNode(node.previousSibling)
+	&& !isHtmlElement(node.firstChild, "BR")) {
+		node.parentNode.insertBefore(node.ownerDocument.createElement("br"), node);
+	}
+
 	// "While node has children, insert the first child of node into node's
 	// parent immediately before node, preserving ranges."
 	while (node.hasChildNodes()) {
 		movePreservingRanges(node.firstChild, node.parentNode, getNodeIndex(node));
 	}
 
+	// "If node is not an inline node, and its previousSibling and nextSibling
+	// are both inline nodes but neither is a br, call createElement("br") on
+	// the ownerDocument of node, and insert the result into node's parent
+	// immediately before node."
+	if (!isInlineNode(node)
+	&& isInlineNode(node.previousSibling)
+	&& isInlineNode(node.nextSibling)
+	&& !isHtmlElement(node.previousSibling, "BR")
+	&& !isHtmlElement(node.nextSibling, "BR")) {
+		node.parentNode.insertBefore(node.ownerDocument.createElement("br"), node);
+	}
+
 	// "Remove node from its parent."
 	node.parentNode.removeChild(node);
 
@@ -409,26 +435,103 @@
 	return children;
 }
 
-function splitParent(node) {
-	// "If node's parent or nextSibling is null, do nothing and abort these
-	// steps."
-	if (!node.parentNode || !node.nextSibling) {
+function splitParent(nodeList, newParent) {
+	// "Let original parent be the parent of the first member of node list."
+	var originalParent = nodeList[0].parentNode;
+
+	// "If original parent is not editable or its parent is null, do nothing
+	// and abort these steps."
+	if (!isEditable(originalParent)
+	|| !originalParent.parentNode) {
 		return;
 	}
 
-	// "Let parent be the parent of node."
-	var parent_ = node.parentNode;
-
-	// "Let new parent be the result of calling cloneNode(false) on parent."
-	var newParent = parent_.cloneNode(false);
-
-	// "Insert new parent into the parent of parent immediately after parent."
-	parent_.parentNode.insertBefore(newParent, parent_.nextSibling);
-
-	// "While the nextSibling of node is not null, insert the last child of
-	// parent as the first child of new parent, preserving ranges."
-	while (node.nextSibling) {
-		movePreservingRanges(parent_.lastChild, newParent, 0);
+	// "If the previousSibling of the first member of node list is not null,
+	// and the nextSibling of the last member of node list is null:"
+	if (nodeList[0].previousSibling
+	&& !nodeList[nodeList.length - 1].nextSibling) {
+		// "If new parent is null:"
+		if (!newParent) {
+			// "If the last member of node list and the nextSibling of original
+			// parent are both inline nodes, call createElement("br") on the
+			// ownerDocument of original parent, then insert the result into
+			// the parent of original parent immediately after original
+			// parent."
+			if (isInlineNode(nodeList[nodeList.length - 1])
+			&& isInlineNode(originalParent.nextSibling)) {
+				originalParent.parentNode.insertBefore(originalParent.ownerDocument.createElement("br"), originalParent.nextSibling);
+			}
+
+			// "For each node in node list, in reverse order, insert node into
+			// the parent of original parent immediately after original parent,
+			// preserving ranges."
+			for (var i = nodeList.length - 1; i >= 0; i--) {
+				movePreservingRanges(nodeList[i], originalParent.parentNode, 1 + getNodeIndex(originalParent));
+			}
+		// "Otherwise:"
+		} else {
+			// "Insert new parent into the parent of original parent
+			// immediately after original parent."
+			originalParent.parentNode.insertBefore(newParent, originalParent.nextSibling);
+
+			// "For each node in node list, in reverse order, insert node as
+			// the first child of new parent, preserving ranges."
+			for (var i = nodeList.length - 1; i >= 0; i--) {
+				movePreservingRanges(nodeList[i], newParent, 0);
+			}
+		}
+
+		// "Abort these steps."
+		return;
+	}
+
+	// "If the previousSibling of the first member of node list is not null:"
+	if (nodeList[0].previousSibling) {
+		// "Let cloned parent be the result of calling cloneNode(false) on
+		// original parent."
+		var clonedParent = originalParent.cloneNode(false);
+
+		// "Insert cloned parent into the parent of original parent immediately
+		// before original parent."
+		originalParent.parentNode.insertBefore(clonedParent, originalParent);
+
+		// "While the previousSibling of the first member of node list is not
+		// null, append the first child of original parent as the last child of
+		// cloned parent, preserving ranges."
+		while (nodeList[0].previousSibling) {
+			movePreservingRanges(originalParent.firstChild, clonedParent, clonedParent.childNodes.length);
+		}
+	}
+
+	// "If new parent is null:"
+	if (!newParent) {
+		// "If the first member of node list and the previousSibling of
+		// original parent are both inline nodes, call createElement("br") on
+		// the ownerDocument of original parent, then insert the result into
+		// the parent of original parent immediately before original parent."
+		if (isInlineNode(nodeList[0])
+		&& isInlineNode(originalParent.previousSibling)) {
+			originalParent.parentNode.insertBefore(originalParent.ownerDocument.createElement("br"), originalParent);
+		}
+
+		// "For each node in node list, insert node into the parent of original
+		// parent immediately before original parent, preserving ranges."
+		for (var i = 0; i < nodeList.length; i++) {
+			movePreservingRanges(nodeList[i], originalParent.parentNode, getNodeIndex(originalParent));
+		}
+
+		// "Abort these steps."
+		return;
+	}
+
+	// "Insert new parent into the parent of original parent immediately before
+	// original parent."
+	originalParent.parentNode.insertBefore(newParent, originalParent);
+
+	// "For each node in node list, append node as the last child of new
+	// parent, preserving ranges."
+	for (var i = 0; i < nodeList.length; i++) {
+		movePreservingRanges(nodeList[i], newParent, newParent.childNodes.length);
 	}
 }
 
@@ -1028,6 +1131,11 @@
 }
 
 function movePreservingRanges(node, newParent, newIndex) {
+	// For convenience, I allow newIndex to be -1 to mean "insert at the end".
+	if (newIndex == -1) {
+		newIndex = newParent.childNodes.length;
+	}
+
 	// "When the user agent is to move a Node to a new location, preserving
 	// ranges, it must remove the Node from its original parent (if any), then
 	// insert it in the new location. In doing so, however, it must ignore the
@@ -2579,53 +2687,37 @@
 					sublist.push(nodeList.shift());
 				}
 
-				// "If the previousSibling of the first member of sublist is
-				// null:"
-				if (!sublist[0].previousSibling) {
-					// "Let ol be the previousSibling of the parent of the
-					// first member of sublist."
-					var ol = sublist[0].parentNode.previousSibling;
-
-					// "If ol is not an ol, let ol be the result of calling
-					// createElement("ol") on the ownerDocument of the first
-					// member of sublist. Then insert ol into the parent of the
-					// parent of the first member of sublist, immediately
-					// before the parent of the first member of sublist."
-					if (!isHtmlElement(ol, "OL")) {
-						ol = sublist[0].ownerDocument.createElement("ol");
-						sublist[0].parentNode.parentNode.insertBefore(ol, sublist[0].parentNode);
-					}
-
-					// "For each node in sublist, append node as the last child
-					// of ol, preserving ranges."
+				// "If the previousSibling of the parent of the first member of
+				// sublist is an editable ol, and the previousSibling of the
+				// first member of sublist is null, then for each node in
+				// sublist, append node as the last child of the
+				// previousSibling of the parent of node, preserving ranges."
+				if (isEditable(sublist[0].parentNode.previousSibling)
+				&& isHtmlElement(sublist[0].parentNode.previousSibling, "OL")
+				&& !sublist[0].previousSibling) {
 					for (var i = 0; i < sublist.length; i++) {
-						movePreservingRanges(sublist[i], ol, ol.childNodes.length);
+						movePreservingRanges(sublist[i], sublist[i].parentNode.previousSibling, -1);
 					}
 
-				// "Otherwise:"
+				// "Otherwise, if the nextSibling of the parent of the first
+				// member of sublist is an editable ol, and the nextSibling of
+				// the last member of sublist is null, then for each node in
+				// sublist in reverse order, insert node as the first child of
+				// the nextSibling of the parent of node, preserving ranges."
+				} else if (isEditable(sublist[0].parentNode.nextSibling)
+				&& isHtmlElement(sublist[0].parentNode.nextSibling, "OL")
+				&& !sublist[sublist.length - 1].nextSibling) {
+					for (var i = sublist.length - 1; i >= 0; i--) {
+						movePreservingRanges(sublist[i], sublist[i].parentNode.nextSibling, 0);
+					}
+
+				// "Otherwise, let ol be the result of calling
+				// createElement("ol") on the ownerDocument of the first member
+				// of sublist. Then split the parent of sublist, with new
+				// parent ol."
 				} else {
-					// "Split the parent of the last member of sublist."
-					splitParent(sublist[sublist.length - 1]);
-
-					// "Let ol be the nextSibling of the parent of the first
-					// member of sublist."
-					var ol = sublist[0].parentNode.nextSibling;
-
-					// "If ol is not an ol, let ol be the result of calling
-					// createElement("ol") on the ownerDocument of the first
-					// member of sublist. Then insert ol into the parent of the
-					// parent of the first member of sublist, immediately after
-					// the parent of the first member of sublist."
-					if (!isHtmlElement(ol, "OL")) {
-						ol = sublist[0].ownerDocument.createElement("ol");
-						sublist[0].parentNode.parentNode.insertBefore(ol, sublist[0].parentNode.nextSibling);
-					}
-
-					// "For each node in sublist in reverse order, insert node
-					// as the first child of ol, preserving ranges."
-					for (var i = sublist.length - 1; i >= 0; i--) {
-						movePreservingRanges(sublist[i], ol, 0);
-					}
+					var ol = sublist[0].ownerDocument.createElement("ol");
+					splitParent(sublist, ol);
 				}
 			// "Otherwise:"
 			} else {
@@ -3370,119 +3462,27 @@
 }
 
 function listOutdent(nodeList) {
-	// "Let parent be the parent of the first member of node list."
-	var parent_ = nodeList[0].parentNode;
-
-	// "If the previousSibling of the first member of node list is null:"
-	if (!nodeList[0].previousSibling) {
-		// "For each node in node list:"
-		for (var i = 0; i < nodeList.length; i++) {
-			var node = nodeList[i];
-
-			// "If node is an li, unset its value attribute if set."
-			if (isHtmlElement(node, "LI")) {
-				node.removeAttribute("value");
-			}
-
-			// "If node is an li with no attributes, and the parent of parent
-			// is not an ol or ul:"
-			if (isHtmlElement(node, "LI")
-			&& !node.attributes.length
-			&& !isHtmlElement(parent_.parentNode, "OL")
-			&& !isHtmlElement(parent_.parentNode, "UL")) {
-				// "If the previousSibling of parent and the first child of
-				// node are both inline nodes, let br be the result of calling
-				// createElement("br") on the ownerDocument of node, then
-				// insert br into the parent of parent immediately before
-				// parent."
-				if (isInlineNode(parent_.previousSibling)
-				&& isInlineNode(node.firstChild)) {
-					var br = node.ownerDocument.createElement("br");
-					parent_.parentNode.insertBefore(br, parent_);
-				}
-
-				// "While node has children, insert the first child of node
-				// into the parent of parent immediately before parent,
-				// preserving ranges."
-				while (node.hasChildNodes()) {
-					movePreservingRanges(node.firstChild, parent_.parentNode, getNodeIndex(parent_));
-				}
-
-				// "Remove node from its parent."
-				node.parentNode.removeChild(node);
-
-			// "Otherwise:"
-			} else {
-				// "Insert node into the parent of parent immediately before
-				// parent, preserving ranges."
-				movePreservingRanges(node, parent_.parentNode, getNodeIndex(parent_));
-
-				// "If node is an li and the parent of parent is not an ol or
-				// ul, set the tag name of node to div."
-				if (isHtmlElement(node, "LI")
-				&& !isHtmlElement(parent_.parentNode, "OL")
-				&& !isHtmlElement(parent_.parentNode, "UL")) {
-					setTagName(node, "div");
-				}
-			}
-		}
-
-		// "Abort these steps."
-		return;
-	}
-
-	// "Split the parent of the last member of node list."
-	splitParent(nodeList[nodeList.length - 1]);
-
-	// "For each node in node list, in reverse order:"
-	for (var i = nodeList.length - 1; i >= 0; i--) {
+	// "Split the parent of node list, with new parent null."
+	splitParent(nodeList, null);
+
+	// "For each node in node list:"
+	for (var i = 0; i < nodeList.length; i++) {
 		var node = nodeList[i];
 
-		// "If node is an li, unset its value attribute if set."
-		if (isHtmlElement(node, "LI")) {
-			node.removeAttribute("value");
-		}
-
-		// "If node is an li with no attributes, and the parent of parent
-		// is not an ol or ul:"
+		// "If node is an li with no attributes and its parent is not an ol or
+		// ul, remove node from its parent, preserving its descendants."
 		if (isHtmlElement(node, "LI")
 		&& !node.attributes.length
-		&& !isHtmlElement(parent_.parentNode, "OL")
-		&& !isHtmlElement(parent_.parentNode, "UL")) {
-			// "If the last child of node and the nextSibling of parent are
-			// both inline nodes, let br be the result of calling
-			// createElement("br") on the ownerDocument of node, then
-			// insert br into the parent of parent immediately after
-			// parent."
-			if (isInlineNode(node.lastChild)
-			&& isInlineNode(parent_.nextSibling)) {
-				var br = node.ownerDocument.createElement("br");
-				parent_.parentNode.insertBefore(br, parent_.nextSibling);
-			}
-
-			// "While node has children, insert the last child of node into
-			// the parent of parent immediately after parent, preserving
-			// ranges."
-			while (node.hasChildNodes()) {
-				movePreservingRanges(node.lastChild, parent_.parentNode, 1 + getNodeIndex(parent_));
-			}
-
-			// "Remove node from its parent."
-			node.parentNode.removeChild(node);
-
-		// "Otherwise:"
-		} else {
-			// "Insert node into the parent of parent immediately after
-			// parent, preserving ranges."
-			movePreservingRanges(node, parent_.parentNode, 1 + getNodeIndex(parent_));
-
-			// "If node is an li and the parent of parent is not an ol or
-			// ul, set the tag name of node to div."
-			if (isHtmlElement(node, "LI")
-			&& !isHtmlElement(parent_.parentNode, "OL")
-			&& !isHtmlElement(parent_.parentNode, "UL")) {
-				setTagName(node, "div");
-			}
+		&& !isHtmlElement(node.parentNode, "OL")
+		&& !isHtmlElement(node.parentNode, "UL")) {
+			removePreservingDescendants(node);
+
+		// "Otherwise, if node is an li and its parent is not an ol or ul, set
+		// the tag name of node to "div"."
+		} else if (isHtmlElement(node, "LI")
+		&& !isHtmlElement(node.parentNode, "OL")
+		&& !isHtmlElement(node.parentNode, "UL")) {
+			setTagName(node, "div");
 		}
 	}
 }
--- a/source.html	Fri May 13 12:06:02 2011 -0600
+++ b/source.html	Fri May 13 12:06:45 2011 -0600
@@ -227,40 +227,149 @@
   <li>If <var>node</var>'s [[parent]] is null, remove all of <var>node</var>'s
   [[children]] from <var>node</var>, then return <var>children</var>.
 
+  <li><span>Remove extraneous line breaks</span> from <var>node</var>.
+
+  <li>If <var>node</var> is not an <span>inline node</span>, and its first
+  [[child]] and [[previoussibling]] are both <span title="inline node">inline
+  nodes</span>, and the first [[child]] of <var>node</var> is not a [[br]],
+  call <code data-anolis-spec=domcore
+  title=dom-Document-createElement>createElement("br")</code> on the
+  [[ownerdocument]] of <var>node</var>, and insert the result into
+  <var>node</var>'s [[parent]] immediately before <var>node</var>.
+
   <li>While <var>node</var> has [[children]], insert the first [[child]] of
   <var>node</var> into <var>node</var>'s [[parent]] immediately before
   <var>node</var>, <span>preserving ranges</span>.
 
+  <li>If <var>node</var> is not an <span>inline node</span>, and its
+  [[previoussibling]] and [[nextsibling]] are both <span title="inline
+  node">inline nodes</span> but neither is a [[br]], call <code
+  data-anolis-spec=domcore
+  title=dom-Document-createElement>createElement("br")</code> on the
+  [[ownerdocument]] of <var>node</var>, and insert the result into
+  <var>node</var>'s [[parent]] immediately before <var>node</var>.
+
   <li>Remove <var>node</var> from its [[parent]].
 
   <li>Return <var>children</var>.
 </ol>
 
-<p>To <dfn>split the parent</dfn> of a [[node]] <var>node</var>:
+<p>To <dfn>split the parent</dfn> of a list <var>node list</var> of consecutive
+[[sibling]] [[nodes]], with <var>new parent</var> either null or an
+[[element]]:
 
 <ol>
-  <li>If <var>node</var>'s [[parent]] or [[nextsibling]] is null, do nothing
-  and abort these steps.
-
-  <li>Let <var>parent</var> be the [[parent]] of <var>node</var>.
-
-  <li>Let <var>new parent</var> be the result of calling <code
-  data-anolis-spec=domcore title=dom-Node-cloneNode>cloneNode(false)</code>
-  on <var>parent</var>.
-
-  <p class=XXX>This will duplicate id's, as well as other bad things.  Do we
-  care?  We don't want to not copy attributes at all, because that wouldn't
-  copy style attributes, and Firefox in CSS mode will actually add style
-  attributes to any elements it feels like.  If we do exclude id's, even though
-  they'd only occur if someone manually added them, do we want to exclude other
-  things like itemid or accesskey or . . .
-
-  <li>Insert <var>new parent</var> into the [[parent]] of <var>parent</var>
-  immediately after <var>parent</var>.
-
-  <li>While the [[nextsibling]] of <var>node</var> is not null, insert the last
-  [[child]] of <var>parent</var> as the first [[child]] of <var>new
-  parent</var>, <span>preserving ranges</span>.
+  <li>Let <var>original parent</var> be the [[parent]] of the first member of
+  <var>node list</var>.
+
+  <li>If <var>original parent</var> is not <span>editable</span> or its
+  [[parent]] is null, do nothing and abort these steps.
+
+  <li>If the [[previoussibling]] of the first member of <var>node list</var> is
+  not null, and the [[nextsibling]] of the last member of <var>node list</var>
+  is null:
+
+  <div class=XXX>
+  <p>We insert things after the parent.  This is bad, because it will cause
+  them to become part of any ranges that immediately follow.  For instance, if
+  we're hitting "bar" in
+
+  <xmp><div><p>foo<p>bar</div>{<p>baz}</xmp>
+
+  <p>it becomes
+
+  <xmp><div><p>foo</div>{<p>bar<p>baz}</xmp>
+
+  <p>instead of
+
+  <xmp><div><p>foo</div><p>bar{<p>baz}</xmp>
+
+  <p>because of how range mutation rules work.  This doesn't happen if we
+  insert before.  Probably this isn't important enough to try working around,
+  though.
+  </div>
+
+  <ol>
+    <li>If <var>new parent</var> is null:
+
+    <ol>
+      <li>If the last member of <var>node list</var> and the [[nextsibling]] of
+      <var>original parent</var> are both <span title="inline node">inline
+      nodes</span>, call <code data-anolis-spec=domcore
+      title=dom-Document-createElement>createElement("br")</code> on the
+      [[ownerdocument]] of <var>original parent</var>, then insert the result
+      into the [[parent]] of <var>original parent</var> immediately after
+      <var>original parent</var>.
+
+      <li>For each <var>node</var> in <var>node list</var>, <em>in reverse
+      order</em>, insert <var>node</var> into the [[parent]] of <var>original
+      parent</var> immediately after <var>original parent</var>,
+      <span>preserving ranges</span>.
+    </ol>
+
+    <li>Otherwise:
+
+    <ol>
+      <li>Insert <var>new parent</var> into the [[parent]] of <var>original
+      parent</var> immediately after <var>original parent</var>.
+
+      <li>For each <var>node</var> in <var>node list</var>, <em>in reverse
+      order</em>, insert <var>node</var> as the first [[child]] of <var>new
+      parent</var>, <span>preserving ranges</span>.
+    </ol>
+
+    <li>Abort these steps.
+  </ol>
+
+  <li>If the [[previoussibling]] of the first member of <var>node list</var> is
+  not null:
+
+  <ol>
+    <li>Let <var>cloned parent</var> be the result of calling <code
+    data-anolis-spec=domcore title=dom-Node-cloneNode>cloneNode(false)</code>
+    on <var>original parent</var>.
+
+    <p class=XXX>This will duplicate id's, as well as other bad things.  Do we
+    care?  We don't want to not copy attributes at all, because that wouldn't
+    copy style attributes, and Firefox in CSS mode will actually add style
+    attributes to any elements it feels like.  If we do exclude id's, even
+    though they'd only occur if someone manually added them, do we want to
+    exclude other things like itemid or accesskey or . . .
+
+    <li>Insert <var>cloned parent</var> into the [[parent]] of <var>original
+    parent</var> immediately before <var>original parent</var>.
+
+    <li>While the [[previoussibling]] of the first member of <var>node
+    list</var> is not null, append the first [[child]] of <var>original
+    parent</var> as the last [[child]] of <var>cloned parent</var>,
+    <span>preserving ranges</span>.
+  </ol>
+
+  <li>If <var>new parent</var> is null:
+
+  <ol>
+    <li>If the first member of <var>node list</var> and the [[previoussibling]]
+    of <var>original parent</var> are both <span title="inline node">inline
+    nodes</span>, call <code data-anolis-spec=domcore
+    title=dom-Document-createElement>createElement("br")</code> on the
+    [[ownerdocument]] of <var>original parent</var>, then insert the result
+    into the [[parent]] of <var>original parent</var> immediately before
+    <var>original parent</var>.
+
+    <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>.
+
+    <li>Abort these steps.
+  </ol>
+
+  <li>Insert <var>new parent</var> into the [[parent]] of <var>original
+  parent</var> immediately before <var>original parent</var>.
+
+  <li>For each <var>node</var> in <var>node list</var>, append <var>node</var>
+  as the last [[child]] of <var>new parent</var>, <span>preserving
+  ranges</span>.
 </ol>
 
 <p>To <dfn>remove extraneous line breaks</dfn> from a [[node]] <var>node</var>:
@@ -2724,6 +2833,9 @@
   different from how it would work if you reversed the commands.
   OpenOffice.org 3.2.1 (Ubuntu) and Word 2007 both agree with the spec in this
   case.
+
+  We don't ask whether the node's parent can contain an <ol>.  The only place
+  where this is likely to cause serious problems is <p>, which we special-case.
   -->
 
   <p class=XXX>Similar to a number of other places in the spec, "can be the
@@ -2770,47 +2882,26 @@
       an [[ol]] or [[ul]], remove the first member from <var>node list</var>
       and append it to <var>sublist</var>.
 
-      <li>If the [[previoussibling]] of the first member of <var>sublist</var>
-      is null:
-
-      <ol>
-        <li>Let <var>ol</var> be the [[previoussibling]] of the [[parent]] of
-        the first member of <var>sublist</var>.
-
-        <li>If <var>ol</var> is not an [[ol]], let <var>ol</var> be the result
-        of calling <code data-anolis-spec=domcore
-        title=dom-Document-createElement>createElement("ol")</code> on the
-        [[ownerdocument]] of the first member of <var>sublist</var>.  Then
-        insert <var>ol</var> into the [[parent]] of the [[parent]] of the first
-        member of <var>sublist</var>, immediately before the [[parent]] of the
-        first member of <var>sublist</var>.
-
-        <li>For each <var>node</var> in <var>sublist</var>, append
-        <var>node</var> as the last [[child]] of <var>ol</var>,
-        <span>preserving ranges</span>.
-      </ol>
-
-      <li>Otherwise:
-
-      <ol>
-        <li><span>Split the parent</span> of the last member of
-        <var>sublist</var>.
-
-        <li>Let <var>ol</var> be the [[nextsibling]] of the [[parent]] of the
-        first member of <var>sublist</var>.
-
-        <li>If <var>ol</var> is not an [[ol]], let <var>ol</var> be the result
-        of calling <code data-anolis-spec=domcore
-        title=dom-Document-createElement>createElement("ol")</code> on the
-        [[ownerdocument]] of the first member of <var>sublist</var>.  Then
-        insert <var>ol</var> into the [[parent]] of the [[parent]] of the first
-        member of <var>sublist</var>, immediately after the [[parent]] of the
-        first member of <var>sublist</var>.
-
-        <li>For each <var>node</var> in <var>sublist</var> <em>in reverse
-        order</em>, insert <var>node</var> as the first [[child]] of
-        <var>ol</var>, <span>preserving ranges</span>.
-      </ol>
+      <li>If the [[previoussibling]] of the [[parent]] of the first member of
+      <var>sublist</var> is an <span>editable</span> [[ol]], and the
+      [[previoussibling]] of the first member of <var>sublist</var> is null,
+      then for each <var>node</var> in <var>sublist</var>, append
+      <var>node</var> as the last [[child]] of the [[previoussibling]] of the
+      [[parent]] of <var>node</var>, <span>preserving ranges</span>.
+
+      <li>Otherwise, if the [[nextsibling]] of the [[parent]] of the first
+      member of <var>sublist</var> is an <span>editable</span> [[ol]], and the
+      [[nextsibling]] of the last member of <var>sublist</var> is null, then
+      for each <var>node</var> in <var>sublist</var> <em>in reverse order</em>,
+      insert <var>node</var> as the first [[child]] of the [[nextsibling]] of
+      the [[parent]] of <var>node</var>, <span>preserving ranges</span>.
+
+      <li>Otherwise, let <var>ol</var> be the result of calling <code
+      data-anolis-spec=domcore
+      title=dom-Document-createElement>createElement("ol")</code> on the
+      [[ownerdocument]] of the first member of <var>sublist</var>.  Then
+      <span>split the parent</span> of <var>sublist</var>, with <var>new
+      parent</var> <var>ol</var>.
     </ol>
 
     <li>Otherwise:
@@ -3227,91 +3318,19 @@
 [[sibling]] [[nodes]]:
 
 <ol>
-  <li>Let <var>parent</var> be the [[parent]] of the first member of <var>node
-  list</var>.
-
-  <li>If the [[previoussibling]] of the first member of <var>node list</var> is
-  null:
+  <li><span>Split the parent</span> of <var>node list</var>, with <var>new
+  parent</var> null.
+
+  <li>For each <var>node</var> in <var>node list</var>:
 
   <ol>
-    <li>For each <var>node</var> in <var>node list</var>:
-
-    <ol>
-      <li>If <var>node</var> is an [[li]], unset its <code data-anolis-spec=html
-      title=attr-li-value>value</code> attribute if set.
-
-      <li>If <var>node</var> is an [[li]] with no attributes, and the [[parent]]
-      of <var>parent</var> is not an [[ol]] or [[ul]]:
-
-      <ol>
-        <li>If the [[previoussibling]] of <var>parent</var> and the first
-        [[child]] of <var>node</var> are both <span title="inline node">inline
-        nodes</span>, let <var>br</var> be the result of calling <code
-        data-anolis-spec=domcore
-        title=dom-Document-createElement>createElement("br")</code> on the
-        [[ownerdocument]] of <var>node</var>, then insert <var>br</var> into
-        the [[parent]] of <var>parent</var> immediately before
-        <var>parent</var>.
-
-        <li>While <var>node</var> has [[children]], insert the first [[child]] of
-        <var>node</var> into the [[parent]] of <var>parent</var> immediately
-        before <var>parent</var>, <span>preserving ranges</span>.
-
-        <li>Remove <var>node</var> from its [[parent]].
-      </ol>
-
-      <li>Otherwise:
-
-      <ol>
-        <li>Insert <var>node</var> into the [[parent]] of <var>parent</var>
-        immediately before <var>parent</var>, <span>preserving ranges</span>.
-
-        <li>If <var>node</var> is an [[li]] and the [[parent]] of
-        <var>parent</var> is not an [[ol]] or [[ul]], <span>set the tag
-        name</span> of <var>node</var> to [[div]].
-      </ol>
-    </ol>
-
-    <li>Abort these steps.
-  </ol>
-
-  <li><span>Split the parent</span> of the last member of <var>node list</var>.
-
-  <li>For each <var>node</var> in <var>node list</var>, <em>in reverse
-  order</em>:
-
-  <ol>
-    <li>If <var>node</var> is an [[li]], unset its <code data-anolis-spec=html
-    title=attr-li-value>value</code> attribute if set.
-
-    <li>If <var>node</var> is an [[li]] with no attributes, and the [[parent]]
-    of <var>parent</var> is not an [[ol]] or [[ul]]:
-
-    <ol>
-      <li>If the last [[child]] of <var>node</var> and the [[nextsibling]] of
-      <var>parent</var> are both <span title="inline node">inline nodes</span>,
-      let <var>br</var> be the result of calling <code data-anolis-spec=domcore
-      title=dom-Document-createElement>createElement("br")</code> on the
-      [[ownerdocument]] of <var>node</var>, then insert <var>br</var> into the
-      [[parent]] of <var>parent</var> immediately after <var>parent</var>.
-
-      <li>While <var>node</var> has [[children]], insert the last [[child]] of
-      <var>node</var> into the [[parent]] of <var>parent</var> immediately
-      after <var>parent</var>, <span>preserving ranges</span>.
-
-      <li>Remove <var>node</var> from its [[parent]].
-    </ol>
-
-    <li>Otherwise:
-
-    <ol>
-      <li>Insert <var>node</var> into the [[parent]] of <var>parent</var>
-      immediately after <var>parent</var>, <span>preserving ranges</span>.
-
-      <li>If <var>node</var> is an [[li]] and the [[parent]] of
-      <var>parent</var> is not an [[ol]] or [[ul]], <span>set the tag
-      name</span> of <var>node</var> to [[div]].
-    </ol>
+    <li>If <var>node</var> is an [[li]] with no attributes and its [[parent]]
+    is not an [[ol]] or [[ul]], remove <var>node</var> from its [[parent]],
+    <span>preserving its descendants</span>.
+
+    <li>Otherwise, if <var>node</var> is an [[li]] and its [[parent]] is not an
+    [[ol]] or [[ul]], <span>set the tag name</span> of <var>node</var> to
+    "div".
   </ol>
 </ol>