Rewrite toggle lists algorithm
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Tue, 12 Jul 2011 14:16:24 -0600
changeset 399 3f2d1b0bf985
parent 398 d1445d8ac836
child 400 b3d61e8688c6
Rewrite toggle lists algorithm

This fixes one bug: something like
<ul><li>foo</li><ol><li>[bar</ol><li>baz]</ul>
would become
<ul><li>foo</li><ol><li>[bar</ol></ul><ol><li>baz]</ol>
instead of
<ul><li>foo</ul><ol><ol><li>[bar</ol><li>baz]</ol>.
I also expected to be able to make it shorter, but it seems to have
become longer, sadly.
editcommands.html
implementation.js
source.html
--- a/editcommands.html	Tue Jul 12 11:51:47 2011 -0600
+++ b/editcommands.html	Tue Jul 12 14:16:24 2011 -0600
@@ -894,7 +894,9 @@
 
 <p>To <dfn id=wrap>wrap</dfn> 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>, given <dfn id=sibling-criteria>sibling criteria</dfn> and <dfn id=new-parent-instructions>new parent
-instructions</dfn>:
+instructions</dfn>, run the following algorithm.  If not provided,
+<a href=#sibling-criteria>sibling criteria</a> match nothing and <a href=#new-parent-instructions>new parent
+instructions</a> return null.
 
 <ol>
   <li>If <var title="">node list</var> is empty, or the first member of <var title="">node
@@ -4850,6 +4852,38 @@
   <li><a href=#block-extend>Block-extend</a> the <a href=#active-range>active range</a>, and let <var title="">new
   range</var> be the result.
 
+  <li>If <var title="">mode</var> is "enable", then let <var title="">lists to convert</var>
+  consist of every <a href=#editable>editable</a> <a href=#html-element>HTML element</a> with
+  <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">other tag name</var> that is <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">new
+  range</var>, and for every <var title="">list</var> in <var title="">lists to convert</var>:
+
+  <ol>
+    <li>If <var title="">list</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> 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 an
+    <a href=#editable>editable</a> <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">tag
+    name</var>:
+    <!-- Convert it to the right name.  If possible, we want to merge with a
+    neighboring list of the correct type.  Failing that, we set the tag name.
+    -->
+
+    <ol>
+      <li>Let <var title="">children</var> be <var title="">list</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>.
+
+      <li><a href=#record-the-values>Record the values</a> of <var title="">children</var>, and let
+      <var title="">values</var> be the result.
+
+      <li><a href=#split-the-parent>Split the parent</a> of <var title="">children</var>.
+
+      <li><a href=#wrap>Wrap</a> <var title="">children</var>, with <a href=#sibling-criteria>sibling
+      criteria</a> matching any <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a>
+      <var title="">tag name</var>.
+
+      <li><a href=#restore-the-values>Restore the values</a> from <var title="">values</var>.
+    </ol>
+
+    <li>Otherwise, <a href=#set-the-tag-name>set the tag name</a> of <var title="">list</var> to <var title="">tag
+    name</var>.
+  </ol>
+
   <li>Let <var title="">node list</var> be a list of <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>, initially empty.
 
   <li>For each <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> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">new range</var>,
@@ -4875,6 +4909,19 @@
   case.
   -->
 
+  <li>If <var title="">mode</var> is "enable", remove from <var title="">node list</var> any
+  <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> whose <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 also 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>.
+  <!--
+  We don't want to touch these.  E.g., assuming tag name is "ol",
+    [foo<ol><li>bar</ol>baz]
+    -> <ol><li>[foo<li>bar<li>baz]</ol>
+    not <ol><li>[foo</li><ol><li>bar</ol><li>baz]</ol>.
+  But
+    <ul><li>foo<li>[bar</li><ol><li>baz</ol><li>quz]</ul>
+    -> <ul><li>foo</ul><ol><li>[bar</li><ol><li>baz</ol><li>quz]</ol>
+    not <ul><li>foo</ul><ol><li>[bar</ol><ul><ol><li>baz</ol></ul><ol><li>quz]</ol>
+  -->
+
   <li>If <var title="">mode</var> is "disable", then while <var title="">node list</var> is not
   empty:
 
@@ -4910,140 +4957,110 @@
   <ol>
     <li>Let <var title="">sublist</var> be an empty list of <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>.
 
-    <li>Remove the first member from <var title="">node list</var> and append it to
-    <var title="">sublist</var>.
-
-    <li>While <var title="">node list</var> is not empty, and the first member of
-    <var title="">node list</var> is 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>, and the last member of <var title="">sublist</var> and first
-    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="">sublist</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>,
-    remove the first member from <var title="">node list</var> and append it to
-    <var title="">sublist</var>.
-
-    <li>If <var title="">sublist</var> contains more than one member, <a href=#wrap>wrap</a>
-    <var title="">sublist</var>, with <a href=#sibling-criteria>sibling criteria</a> matching nothing and
-    <a href=#new-parent-instructions>new parent instructions</a> returning 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("li")</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.  Let <var title="">node</var> be
-    the result.
-
-    <li>Otherwise, let <var title="">node</var> be the sole member of
-    <var title="">sublist</var>.
-
-    <li>If <var title="">node</var> is an <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a>
-    <var title="">other tag name</var>:
+    <li>While either <var title="">sublist</var> is empty, or <var title="">node list</var> is
+    not empty and its first member is 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="">sublist</var>'s last member:
+    <!-- Accumulate consecutive sibling nodes in sublist, first converting them
+    all to li's (except if they're already lists). -->
 
     <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="">node</var>.
-
-      <li><a href=#record-the-values>Record the values</a> of <var title="">children</var>, and let
+      <li>If <var title="">node list</var>'s first member is a <code class=external data-anolis-spec=html title="the p element"><a href=http://www.whatwg.org/html/#the-p-element>p</a></code> or <code class=external data-anolis-spec=html title="the div element"><a href=http://www.whatwg.org/html/#the-div-element>div</a></code>,
+      <a href=#set-the-tag-name>set the tag name</a> of <var title="">node list</var>'s first member to
+      "li", and append the result to <var title="">sublist</var>.  Remove the first
+      member from <var title="">node list</var>.
+      <!-- Thus <p>foo</p> becomes <ol><li>foo</ol> instead of
+      <ol><li><p>foo</ol>, and likewise for div, but other things will be put
+      inside the <li>. -->
+
+      <li>Otherwise, if the first member of <var title="">node list</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>
+      or <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 it from <var title="">node list</var> and append it to
+      <var title="">sublist</var>.
+
+      <li>Otherwise:
+
+      <ol>
+        <li>Let <var title="">nodes to wrap</var> be a list of <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>, initially
+        empty.
+
+        <li>While <var title="">nodes to wrap</var> is empty, or <var title="">node list</var> is
+        not empty and its first member is 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="">nodes to wrap</var>'s last member and the first member of
+        <var title="">node list</var> is an <a href=#inline-node>inline node</a> and the last member
+        of <var title="">nodes to wrap</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>, remove the first member from <var title="">node list</var> and append it
+        to <var title="">nodes to wrap</var>.
+
+        <li><a href=#wrap>Wrap</a> <var title="">nodes to wrap</var>, with <a href=#new-parent-instructions>new parent
+        instructions</a> returning 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("li")</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.  Append the result to
+        <var title="">sublist</var>.
+      </ol>
+    </ol>
+
+    <li>If <var title="">sublist</var>'s first member'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 an <a href=#html-element>HTML
+    element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">tag name</var>, or if every member
+    of <var title="">sublist</var> is 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>, continue this loop from the
+    beginning.
+    <!-- Already wrapped properly, nothing more to do. -->
+
+    <li>If <var title="">sublist</var>'s first member'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 an <a href=#html-element>HTML
+    element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">other tag name</var>:
+
+    <ol>
+      <li><a href=#record-the-values>Record the values</a> of <var title="">sublist</var>, and let
       <var title="">values</var> be the result.
 
-      <li>Remove <var title="">node</var>, <a href=#preserving-its-descendants>preserving its descendants</a>.
-
-      <li><a href=#wrap>Wrap</a> <var title="">children</var>, with <a href=#sibling-criteria>sibling
+      <li><a href=#split-the-parent>Split the parent</a> of <var title="">sublist</var>.
+
+      <li><a href=#wrap>Wrap</a> <var title="">sublist</var>, with <a href=#sibling-criteria>sibling
       criteria</a> matching any <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a>
-      <var title="">tag name</var> and <a href=#new-parent-instructions>new parent instructions</a> returning
+      <var title="">tag name</var>, and <a href=#new-parent-instructions>new parent instructions</a> returning
       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(<var title="">tag name</var>)</a></code> on the
-      <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.  Let <var title="">node</var> be the result.
+      <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.
 
       <li><a href=#restore-the-values>Restore the values</a> from <var title="">values</var>.
 
-      <li>Prepend the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendants</a> of <var title="">node</var> that are <a href=#html-element title="HTML element">HTML elements</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">other
-      tag name</var> (if any) to <var title="">node list</var>.
-
-      <li>Continue from the beginning of this loop.
-
-      <div class=XXX>
-      <p>This does the wrong thing for input like
-
-      <ul>
-        <li>foo</li>
-        <li>[bar</li>
-        <ul><li>baz</ul>
-        <li>quz]</li>
-      </ul>
-
-      <p>which becomes
-
-      <ul><li>foo</ul>
-      <ol><li>[bar</ol>
-      <ul><ol><li>baz</ol></ul>
-      <ol><li>quz]</ol>
-
-      <p>when we want
-
-      <ul><li>foo</ul>
-      <ol>
-        <li>[bar</li>
-        <ol><li>baz</ol>
-        <li>quz]</li>
-      </ol>
-      </div>
+      <li>Continue this loop from the beginning.
     </ol>
 
-    <li>If <var title="">node</var> is a <code class=external data-anolis-spec=html title="the p element"><a href=http://www.whatwg.org/html/#the-p-element>p</a></code> or <code class=external data-anolis-spec=html title="the div element"><a href=http://www.whatwg.org/html/#the-div-element>div</a></code>, <a href=#set-the-tag-name>set the tag name</a>
-    of <var title="">node</var> to "li", and let <var title="">node</var> be the result.
-
-    <li>If <var title="">node</var> is 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>child</a> of an <a href=#html-element>HTML element</a>
-    with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">other tag name</var>:
+    <li><a href=#wrap>Wrap</a> <var title="">sublist</var>, with the <a href=#sibling-criteria>sibling
+    criteria</a> matching any <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a>
+    <var title="">tag name</var>, and the <a href=#new-parent-instructions>new parent instructions</a> being the
+    following:
 
     <ol>
-      <li><a href=#record-the-values>Record the values</a> of 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>, and let <var title="">values</var> be the result.
-
-      <li><a href=#split-the-parent>Split the parent</a> of 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>.
-
-      <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 any
-      <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">tag name</var>,
-      and with <a href=#new-parent-instructions>new parent instructions</a> returning 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(<var title="">tag name</var>)</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.
-
-      <li><a href=#restore-the-values>Restore the values</a> from <var title="">values</var>.
-
-      <li>Prepend the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendants</a> of <var title="">node</var> that are <a href=#html-element title="HTML element">HTML elements</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">other
-      tag name</var> (if any) to <var title="">node list</var>.
-
-      <li>Continue from the beginning of this loop.
-    </ol>
-
-    <li>If <var title="">node</var> is equal to or 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>child</a> of an <a href=#html-element>HTML
-    element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">tag name</var>, prepend the
-    <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendants</a> of <var title="">node</var> that are <a href=#html-element title="HTML element">HTML
-    elements</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">other tag name</var> (if any) to
-    <var title="">node list</var> and continue from the beginning of this loop.
-
-    <li>If <var title="">node</var> is not 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>, <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 nothing and <a href=#new-parent-instructions>new parent instructions</a> returning
-    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("li")</a></code> on the
-    <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.  Set <var title="">node</var> to the result.
-
-    <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 the <a href=#sibling-criteria>sibling criteria</a> matching any <a href=#html-element>HTML
-    element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">tag name</var>, and the <a href=#new-parent-instructions>new
-    parent instructions</a> being the following:
-
-    <ol>
-      <li>If 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> is not an <a href=#editable>editable</a>
-      <a href=#simple-indentation-element>simple indentation element</a>, or 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> is not an <a href=#editable>editable</a>
+      <!--
+      Special case: something like
+        <ol><li>foo</ol><blockquote>[bar]</blockquote>
+      becomes
+        <ol><li>foo</li><ol><li>[bar]</ol></ol>
+      instead of
+        <ol><li>foo</ol><blockquote><ol><li>[bar]</ol></blockquote>.
+      We handle the special case in the new parent instructions instead of
+      outside because we'd prefer to wind up in a sibling if there is one.  We
+      handle only previousSibling, not nextSibling, because we really mean for
+      this to cover something like
+        [foo<blockquote>bar]</blockquote>
+      which we'll handle node-by-node.  TODO: Maybe we should do this
+      differently, like just special-case simple indentation elements in an
+      earlier part of the algorithm?  This way's a bit weird.
+      -->
+      <li>If <var title="">sublist</var>'s first member'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 not an
+      <a href=#editable>editable</a> <a href=#simple-indentation-element>simple indentation element</a>, or
+      <var title="">sublist</var>'s first member'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>'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> is
+      not an <a href=#editable>editable</a> <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a>
+      <var title="">tag name</var>, 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(<var title="">tag name</var>)</a></code> on the
+      <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a> and return the result.
+
+      <li>Let <var title="">list</var> be <var title="">sublist</var>'s first member'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>'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=#normalize-sublists>Normalize sublists</a> of <var title="">list</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-lastChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-lastchild>lastChild</a></code>.
+
+      <li>If <var title="">list</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-lastChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-lastchild>lastChild</a></code> is not an <a href=#editable>editable</a>
       <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">tag name</var>, 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(<var title="">tag name</var>)</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a> and return
-      the result.  Otherwise:
-
-      <li>Let <var title="">list</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
-      <var title="">node</var>.
-
-      <li><a href=#normalize-sublists>Normalize sublists</a> of <var title="">list</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>.
-
-      <li>If <var title="">list</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 an <a href=#editable>editable</a>
-      <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> <var title="">tag name</var>, 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(<var title="">tag
-      name</var>)</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>, 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="">list</var>.
+      <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(<var title="">tag name</var>)</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>, 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="">list</var>.
 
       <li>Return 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="">list</var>.
     </ol>
--- a/implementation.js	Tue Jul 12 11:51:47 2011 -0600
+++ b/implementation.js	Tue Jul 12 14:16:24 2011 -0600
@@ -1127,6 +1127,15 @@
 //@{
 
 function wrap(nodeList, siblingCriteria, newParentInstructions) {
+	// "If not provided, sibling criteria match nothing and new parent
+	// instructions return null."
+	if (typeof siblingCriteria == "undefined") {
+		siblingCriteria = function() { return false };
+	}
+	if (typeof newParentInstructions == "undefined") {
+		newParentInstructions = function() { return null };
+	}
+
 	// "If node list is empty, or the first member of node list is not
 	// editable, return null and abort these steps."
 	if (!nodeList.length
@@ -5026,6 +5035,42 @@
 	// "Block-extend the range, and let new range be the result."
 	var newRange = blockExtend(range);
 
+	// "If mode is "enable", then let lists to convert consist of every
+	// editable HTML element with local name other tag name that is contained
+	// in new range, and for every list in lists to convert:"
+	if (mode == "enable") {
+		getAllContainedNodes(newRange, function(node) {
+			return isEditable(node)
+				&& isHtmlElement(node, otherTagName);
+		}).forEach(function(list) {
+			// "If list's previousSibling or nextSibling is an editable HTML
+			// element with local name tag name:"
+			if ((isEditable(list.previousSibling) && isHtmlElement(list.previousSibling, tagName))
+			|| (isEditable(list.nextSibling) && isHtmlElement(list.nextSibling, tagName))) {
+				// "Let children be list's children."
+				var children = [].slice.call(list.childNodes);
+
+				// "Record the values of children, and let values be the
+				// result."
+				var values = recordValues(children);
+
+				// "Split the parent of children."
+				splitParent(children);
+
+				// "Wrap children, with sibling criteria matching any HTML
+				// element with local name tag name."
+				wrap(children, function(node) { return isHtmlElement(node, tagName) });
+
+				// "Restore the values from values."
+				restoreValues(values);
+
+			// "Otherwise, set the tag name of list to tag name."
+			} else {
+				setTagName(list, tagName);
+			}
+		});
+	}
+
 	// "Let node list be a list of nodes, initially empty."
 	//
 	// "For each node node contained in new range, if node is editable; the
@@ -5041,6 +5086,15 @@
 		|| isAllowedChild(node, "li"));
 	});
 
+	// "If mode is "enable", remove from node list any ol or ul whose parent is
+	// not also an ol or ul."
+	if (mode == "enable") {
+		nodeList = nodeList.filter(function(node) {
+			return !isHtmlElement(node, ["ol", "ul"])
+				|| isHtmlElement(node.parentNode, ["ol", "ul"]);
+		});
+	}
+
 	// "If mode is "disable", then while node list is not empty:"
 	if (mode == "disable") {
 		while (nodeList.length) {
@@ -5090,151 +5144,113 @@
 			// "Let sublist be an empty list of nodes."
 			var sublist = [];
 
-			// "Remove the first member from node list and append it to
-			// sublist."
-			sublist.push(nodeList.shift());
-
-			// "While node list is not empty, and the first member of node
-			// list is the nextSibling of the last member of sublist, and
-			// the last member of sublist and first member of node list are
-			// both inline nodes, and the last member of sublist is not a
-			// br, remove the first member from node list and append it to
-			// sublist."
-			while (nodeList.length
-			&& nodeList[0] == sublist[sublist.length - 1].nextSibling
-			&& isInlineNode(sublist[sublist.length - 1])
-			&& isInlineNode(nodeList[0])
-			&& !isHtmlElement(sublist[sublist.length - 1], "BR")) {
-				sublist.push(nodeList.shift());
+			// "While either sublist is empty, or node list is not empty and
+			// its first member is the nextSibling of sublist's last member:"
+			while (!sublist.length
+			|| (nodeList.length
+			&& nodeList[0] == sublist[sublist.length - 1].nextSibling)) {
+				// "If node list's first member is a p or div, set the tag name
+				// of node list's first member to "li", and append the result
+				// to sublist. Remove the first member from node list."
+				if (isHtmlElement(nodeList[0], ["p", "div"])) {
+					sublist.push(setTagName(nodeList[0], "li"));
+					nodeList.shift();
+
+				// "Otherwise, if the first member of node list is an li or ol
+				// or ul, remove it from node list and append it to sublist."
+				} else if (isHtmlElement(nodeList[0], ["li", "ol", "ul"])) {
+					sublist.push(nodeList.shift());
+
+				// "Otherwise:"
+				} else {
+					// "Let nodes to wrap be a list of nodes, initially empty."
+					var nodesToWrap = [];
+
+					// "While nodes to wrap is empty, or node list is not empty
+					// and its first member is the nextSibling of nodes to
+					// wrap's last member and the first member of node list is
+					// an inline node and the last member of nodes to wrap is
+					// an inline node other than a br, remove the first member
+					// from node list and append it to nodes to wrap."
+					while (!nodesToWrap.length
+					|| (nodeList.length
+					&& nodeList[0] == nodesToWrap[nodesToWrap.length - 1].nextSibling
+					&& isInlineNode(nodeList[0])
+					&& isInlineNode(nodesToWrap[nodesToWrap.length - 1])
+					&& !isHtmlElement(nodesToWrap[nodesToWrap.length - 1], "br"))) {
+						nodesToWrap.push(nodeList.shift());
+					}
+
+					// "Wrap nodes to wrap, with new parent instructions
+					// returning the result of calling createElement("li") on
+					// the context object.  Append the result to sublist."
+					sublist.push(wrap(nodesToWrap,
+						undefined,
+						function() { return document.createElement("li") }));
+				}
 			}
 
-			// "If sublist contains more than one member, wrap sublist, with
-			// sibling criteria matching nothing and new parent instructions
-			// returning the result of calling createElement("li") on the
-			// context object. Let node be the result."
-			var node;
-			if (sublist.length > 1) {
-				node = wrap(sublist,
-					function() { return false },
-					function() { return document.createElement("li") });
-
-			// "Otherwise, let node be the sole member of sublist."
-			} else {
-				node = sublist[0];
+			// "If sublist's first member's parent is an HTML element with
+			// local name tag name, or if every member of sublist is an ol or
+			// ul, continue this loop from the beginning."
+			if (isHtmlElement(sublist[0].parentNode, tagName)
+			|| sublist.every(function(node) { return isHtmlElement(node, ["ol", "ul"]) })) {
+				continue;
 			}
 
-			// "If node is an HTML element with local name other tag name:"
-			if (isHtmlElement(node, otherTagName)) {
-				// "Let children be the children of node."
-				var children = [].slice.call(node.childNodes);
-
-				// "Record the values of children, and let values be the
+			// "If sublist's first member's parent is an HTML element with
+			// local name other tag name:"
+			if (isHtmlElement(sublist[0].parentNode, otherTagName)) {
+				// "Record the values of sublist, and let values be the
 				// result."
-				var values = recordValues(children);
-
-				// "Remove node, preserving its descendants."
-				removePreservingDescendants(node);
-
-				// "Wrap children, with sibling criteria matching any HTML
-				// element with local name tag name and new parent instructions
-				// returning the result of calling createElement(tag name) on
-				// the context object. Let node be the result."
-				node = wrap(children,
+				var values = recordValues(sublist);
+
+				// "Split the parent of sublist."
+				splitParent(sublist);
+
+				// "Wrap sublist, with sibling criteria matching any HTML
+				// element with local name tag name, and new parent
+				// instructions returning the result of calling
+				// createElement(tag name) on the context object."
+				wrap(sublist,
 					function(node) { return isHtmlElement(node, tagName) },
 					function() { return document.createElement(tagName) });
 
 				// "Restore the values from values."
 				restoreValues(values);
 
-				// "Prepend the descendants of node that are HTML elements with
-				// local name other tag name (if any) to node list."
-				nodeList = [].slice.call(node.querySelectorAll(otherTagName)).concat(nodeList);
-
-				// "Continue from the beginning of this loop."
-				continue;
-			}
-
-			// "If node is a p or div, set the tag name of node to "li",
-			// and let node be the result."
-			if (isHtmlElement(node, ["P", "DIV"])) {
-				node = setTagName(node, "li");
-			}
-
-			// "If node is the child of an HTML element with local name other
-			// tag name:"
-			if (isHtmlElement(node.parentNode, otherTagName)) {
-				// "Record the values of the one-node list consisting of node,
-				// and let values be the result."
-				var values = recordValues([node]);
-
-				// "Split the parent of the one-node list consisting of
-				// node."
-				splitParent([node]);
-
-				// "Wrap the one-node list consisting of node, with sibling
-				// criteria matching any HTML element with local name tag name,
-				// and with new parent instructions returning the result of
-				// calling createElement(tag name) on the context object."
-				wrap([node],
-					function(node) { return isHtmlElement(node, tagName) },
-					function() { return document.createElement(tagName) });
-
-				// "Restore the values from values."
-				restoreValues(values);
-
-				// "Prepend the descendants of node that are HTML elements with
-				// local name other tag name (if any) to node list."
-				nodeList = [].slice.call(node.querySelectorAll(otherTagName)).concat(nodeList);
-
-				// "Continue from the beginning of this loop."
+				// "Continue this loop from the beginning."
 				continue;
 			}
 
-			// "If node is equal to or the child of an HTML element with local
-			// name tag name, prepend the descendants of node that are HTML
-			// elements with local name other tag name (if any) to node list
-			// and continue from the beginning of this loop."
-			if (isHtmlElement(node, tagName)
-			|| isHtmlElement(node.parentNode, tagName)) {
-				nodeList = [].slice.call(node.querySelectorAll(otherTagName)).concat(nodeList);
-				continue;
-			}
-
-			// "If node is not an li, wrap the one-node list consisting of
-			// node, with sibling criteria matching nothing and new parent
-			// instructions returning the result of calling createElement("li")
-			// on the context object. Set node to the result."
-			if (!isHtmlElement(node, "LI")) {
-				node = wrap([node],
-					function() { return false },
-					function() { return document.createElement("li") });
-			}
-
-			// "Wrap the one-node list consisting of node, with the sibling
-			// criteria matching any HTML element with local name tag name, and
-			// the new parent instructions being the following:"
-			var newParent = wrap([node],
+			// "Wrap sublist, with the sibling criteria matching any HTML
+			// element with local name tag name, and the new parent
+			// instructions being the following:"
+			// . . .
+			// "Fix disallowed ancestors of the previous step's result."
+			fixDisallowedAncestors(wrap(sublist,
 				function(node) { return isHtmlElement(node, tagName) },
 				function() {
-					// "If the parent of node is not an editable simple
-					// indentation element, or the previousSibling of the
-					// parent of node is not an editable HTML element with
-					// local name tag name, call createElement(tag name) on the
-					// context object and return the result. Otherwise:"
-					if (!isEditable(node.parentNode)
-					|| !isSimpleIndentationElement(node.parentNode)
-					|| !isEditable(node.parentNode.previousSibling)
-					|| !isHtmlElement(node.parentNode.previousSibling, tagName)) {
+					// "If sublist's first member's parent is not an editable
+					// simple indentation element, or sublist's first member's
+					// parent's previousSibling is not an editable HTML element
+					// with local name tag name, call createElement(tag name)
+					// on the context object and return the result."
+					if (!isEditable(sublist[0].parentNode)
+					|| !isSimpleIndentationElement(sublist[0].parentNode)
+					|| !isEditable(sublist[0].parentNode.previousSibling)
+					|| !isHtmlElement(sublist[0].parentNode.previousSibling, tagName)) {
 						return document.createElement(tagName);
 					}
 
-					// "Let list be the previousSibling of the parent of node."
-					var list = node.parentNode.previousSibling;
-
-					// "Normalize sublists of list's last child."
+					// "Let list be sublist's first member's parent's
+					// previousSibling."
+					var list = sublist[0].parentNode.previousSibling;
+
+					// "Normalize sublists of list's lastChild."
 					normalizeSublists(list.lastChild);
 
-					// "If list's last child is not an editable HTML element
+					// "If list's lastChild is not an editable HTML element
 					// with local name tag name, call createElement(tag name)
 					// on the context object, and append the result as the last
 					// child of list."
@@ -5245,10 +5261,8 @@
 
 					// "Return the last child of list."
 					return list.lastChild;
-				});
-
-			// "Fix disallowed ancestors of the previous step's result."
-			fixDisallowedAncestors(newParent);
+				}
+			));
 		}
 	}
 }
--- a/source.html	Tue Jul 12 11:51:47 2011 -0600
+++ b/source.html	Tue Jul 12 14:16:24 2011 -0600
@@ -846,7 +846,9 @@
 <!-- @{ -->
 <p>To <dfn>wrap</dfn> a list <var>node list</var> of consecutive [[sibling]]
 [[nodes]], given <dfn>sibling criteria</dfn> and <dfn>new parent
-instructions</dfn>:
+instructions</dfn>, run the following algorithm.  If not provided,
+<span>sibling criteria</span> match nothing and <span>new parent
+instructions</span> return null.
 
 <ol>
   <li>If <var>node list</var> is empty, or the first member of <var>node
@@ -4840,6 +4842,38 @@
   <li><span>Block-extend</span> the <span>active range</span>, and let <var>new
   range</var> be the result.
 
+  <li>If <var>mode</var> is "enable", then let <var>lists to convert</var>
+  consist of every <span>editable</span> <span>HTML element</span> with
+  [[localname]] <var>other tag name</var> that is [[contained]] in <var>new
+  range</var>, and for every <var>list</var> in <var>lists to convert</var>:
+
+  <ol>
+    <li>If <var>list</var>'s [[previoussibling]] or [[nextsibling]] is an
+    <span>editable</span> <span>HTML element</span> with [[localname]] <var>tag
+    name</var>:
+    <!-- Convert it to the right name.  If possible, we want to merge with a
+    neighboring list of the correct type.  Failing that, we set the tag name.
+    -->
+
+    <ol>
+      <li>Let <var>children</var> be <var>list</var>'s [[children]].
+
+      <li><span>Record the values</span> of <var>children</var>, and let
+      <var>values</var> be the result.
+
+      <li><span>Split the parent</span> of <var>children</var>.
+
+      <li><span>Wrap</span> <var>children</var>, with <span>sibling
+      criteria</span> matching any <span>HTML element</span> with [[localname]]
+      <var>tag name</var>.
+
+      <li><span>Restore the values</span> from <var>values</var>.
+    </ol>
+
+    <li>Otherwise, <span>set the tag name</span> of <var>list</var> to <var>tag
+    name</var>.
+  </ol>
+
   <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
 
   <li>For each [[node]] <var>node</var> [[contained]] in <var>new range</var>,
@@ -4865,6 +4899,19 @@
   case.
   -->
 
+  <li>If <var>mode</var> is "enable", remove from <var>node list</var> any
+  [[ol]] or [[ul]] whose [[parent]] is not also an [[ol]] or [[ul]].
+  <!--
+  We don't want to touch these.  E.g., assuming tag name is "ol",
+    [foo<ol><li>bar</ol>baz]
+    -> <ol><li>[foo<li>bar<li>baz]</ol>
+    not <ol><li>[foo</li><ol><li>bar</ol><li>baz]</ol>.
+  But
+    <ul><li>foo<li>[bar</li><ol><li>baz</ol><li>quz]</ul>
+    -> <ul><li>foo</ul><ol><li>[bar</li><ol><li>baz</ol><li>quz]</ol>
+    not <ul><li>foo</ul><ol><li>[bar</ol><ul><ol><li>baz</ol></ul><ol><li>quz]</ol>
+  -->
+
   <li>If <var>mode</var> is "disable", then while <var>node list</var> is not
   empty:
 
@@ -4900,144 +4947,110 @@
   <ol>
     <li>Let <var>sublist</var> be an empty list of [[nodes]].
 
-    <li>Remove the first member from <var>node list</var> and append it to
-    <var>sublist</var>.
-
-    <li>While <var>node list</var> is not empty, and the first member of
-    <var>node list</var> is the [[nextsibling]] of the last member of
-    <var>sublist</var>, and the last member of <var>sublist</var> and first
-    member of <var>node list</var> are both <span title="inline node">inline
-    nodes</span>, and the last member of <var>sublist</var> is not a [[br]],
-    remove the first member from <var>node list</var> and append it to
-    <var>sublist</var>.
-
-    <li>If <var>sublist</var> contains more than one member, <span>wrap</span>
-    <var>sublist</var>, with <span>sibling criteria</span> matching nothing and
-    <span>new parent instructions</span> returning the result of calling
-    [[createelement|"li"]] on the [[contextobject]].  Let <var>node</var> be
-    the result.
-
-    <li>Otherwise, let <var>node</var> be the sole member of
-    <var>sublist</var>.
-
-    <li>If <var>node</var> is an <span>HTML element</span> with [[localname]]
-    <var>other tag name</var>:
+    <li>While either <var>sublist</var> is empty, or <var>node list</var> is
+    not empty and its first member is the [[nextsibling]] of
+    <var>sublist</var>'s last member:
+    <!-- Accumulate consecutive sibling nodes in sublist, first converting them
+    all to li's (except if they're already lists). -->
 
     <ol>
-      <li>Let <var>children</var> be the [[children]] of <var>node</var>.
-
-      <li><span>Record the values</span> of <var>children</var>, and let
+      <li>If <var>node list</var>'s first member is a [[p]] or [[div]],
+      <span>set the tag name</span> of <var>node list</var>'s first member to
+      "li", and append the result to <var>sublist</var>.  Remove the first
+      member from <var>node list</var>.
+      <!-- Thus <p>foo</p> becomes <ol><li>foo</ol> instead of
+      <ol><li><p>foo</ol>, and likewise for div, but other things will be put
+      inside the <li>. -->
+
+      <li>Otherwise, if the first member of <var>node list</var> is an [[li]]
+      or [[ol]] or [[ul]], remove it from <var>node list</var> and append it to
+      <var>sublist</var>.
+
+      <li>Otherwise:
+
+      <ol>
+        <li>Let <var>nodes to wrap</var> be a list of [[nodes]], initially
+        empty.
+
+        <li>While <var>nodes to wrap</var> is empty, or <var>node list</var> is
+        not empty and its first member is the [[nextsibling]] of
+        <var>nodes to wrap</var>'s last member and the first member of
+        <var>node list</var> is an <span>inline node</span> and the last member
+        of <var>nodes to wrap</var> is an <span>inline node</span> other than a
+        [[br]], remove the first member from <var>node list</var> and append it
+        to <var>nodes to wrap</var>.
+
+        <li><span>Wrap</span> <var>nodes to wrap</var>, with <span>new parent
+        instructions</span> returning the result of calling
+        [[createelement|"li"]] on the [[contextobject]].  Append the result to
+        <var>sublist</var>.
+      </ol>
+    </ol>
+
+    <li>If <var>sublist</var>'s first member's [[parent]] is an <span>HTML
+    element</span> with [[localname]] <var>tag name</var>, or if every member
+    of <var>sublist</var> is an [[ol]] or [[ul]], continue this loop from the
+    beginning.
+    <!-- Already wrapped properly, nothing more to do. -->
+
+    <li>If <var>sublist</var>'s first member's [[parent]] is an <span>HTML
+    element</span> with [[localname]] <var>other tag name</var>:
+
+    <ol>
+      <li><span>Record the values</span> of <var>sublist</var>, and let
       <var>values</var> be the result.
 
-      <li>Remove <var>node</var>, <span>preserving its descendants</span>.
-
-      <li><span>Wrap</span> <var>children</var>, with <span>sibling
+      <li><span>Split the parent</span> of <var>sublist</var>.
+
+      <li><span>Wrap</span> <var>sublist</var>, with <span>sibling
       criteria</span> matching any <span>HTML element</span> with [[localname]]
-      <var>tag name</var> and <span>new parent instructions</span> returning
+      <var>tag name</var>, and <span>new parent instructions</span> returning
       the result of calling [[createelement|<var>tag name</var>]] on the
-      [[contextobject]].  Let <var>node</var> be the result.
+      [[contextobject]].
 
       <li><span>Restore the values</span> from <var>values</var>.
 
-      <li>Prepend the [[descendants]] of <var>node</var> that are <span
-      title="HTML element">HTML elements</span> with [[localname]] <var>other
-      tag name</var> (if any) to <var>node list</var>.
-
-      <li>Continue from the beginning of this loop.
-
-      <div class=XXX>
-      <p>This does the wrong thing for input like
-
-      <ul>
-        <li>foo</li>
-        <li>[bar</li>
-        <ul><li>baz</li></ul>
-        <li>quz]</li>
-      </ul>
-
-      <p>which becomes
-
-      <ul><li>foo</li></ul>
-      <ol><li>[bar</li></ol>
-      <ul><ol><li>baz</li></ol></ul>
-      <ol><li>quz]</li></ol>
-
-      <p>when we want
-
-      <ul><li>foo</li></ul>
-      <ol>
-        <li>[bar</li>
-        <ol><li>baz</li></ol>
-        <li>quz]</li>
-      </ol>
-      </div>
+      <li>Continue this loop from the beginning.
     </ol>
 
-    <li>If <var>node</var> is a [[p]] or [[div]], <span>set the tag name</span>
-    of <var>node</var> to "li", and let <var>node</var> be the result.
-
-    <li>If <var>node</var> is the [[child]] of an <span>HTML element</span>
-    with [[localname]] <var>other tag name</var>:
+    <li><span>Wrap</span> <var>sublist</var>, with the <span>sibling
+    criteria</span> matching any <span>HTML element</span> with [[localname]]
+    <var>tag name</var>, and the <span>new parent instructions</span> being the
+    following:
 
     <ol>
-      <li><span>Record the values</span> of the one-[[node]] list consisting of
-      <var>node</var>, and let <var>values</var> be the result.
-
-      <li><span>Split the parent</span> of the one-[[node]] list consisting of
-      <var>node</var>.
-
-      <li><span>Wrap</span> the one-[[node]] list consisting of
-      <var>node</var>, with <span>sibling criteria</span> matching any
-      <span>HTML element</span> with [[localname]] <var>tag name</var>,
-      and with <span>new parent instructions</span> returning the result of
-      calling [[createelement|<var>tag name</var>]] on the [[contextobject]].
-
-      <li><span>Restore the values</span> from <var>values</var>.
-
-      <li>Prepend the [[descendants]] of <var>node</var> that are <span
-      title="HTML element">HTML elements</span> with [[localname]] <var>other
-      tag name</var> (if any) to <var>node list</var>.
-
-      <li>Continue from the beginning of this loop.
-    </ol>
-
-    <li>If <var>node</var> is equal to or the [[child]] of an <span>HTML
-    element</span> with [[localname]] <var>tag name</var>, prepend the
-    [[descendants]] of <var>node</var> that are <span title="HTML element">HTML
-    elements</span> with [[localname]] <var>other tag name</var> (if any) to
-    <var>node list</var> and continue from the beginning of this loop.
-
-    <li>If <var>node</var> is not an [[li]], <span>wrap</span> the one-[[node]]
-    list consisting of <var>node</var>, with <span>sibling criteria</span>
-    matching nothing and <span>new parent instructions</span> returning
-    the result of calling <code data-anolis-spec=domcore
-    title=dom-Document-createElement>createElement("li")</code> on the
-    [[contextobject]].  Set <var>node</var> to the result.
-
-    <li><span>Wrap</span> the one-[[node]] list consisting of <var>node</var>,
-    with the <span>sibling criteria</span> matching any <span>HTML
-    element</span> with [[localname]] <var>tag name</var>, and the <span>new
-    parent instructions</span> being the following:
-
-    <ol>
-      <li>If the [[parent]] of <var>node</var> is not an <span>editable</span>
-      <span>simple indentation element</span>, or the [[previoussibling]] of
-      the [[parent]] of <var>node</var> is not an <span>editable</span>
+      <!--
+      Special case: something like
+        <ol><li>foo</ol><blockquote>[bar]</blockquote>
+      becomes
+        <ol><li>foo</li><ol><li>[bar]</ol></ol>
+      instead of
+        <ol><li>foo</ol><blockquote><ol><li>[bar]</ol></blockquote>.
+      We handle the special case in the new parent instructions instead of
+      outside because we'd prefer to wind up in a sibling if there is one.  We
+      handle only previousSibling, not nextSibling, because we really mean for
+      this to cover something like
+        [foo<blockquote>bar]</blockquote>
+      which we'll handle node-by-node.  TODO: Maybe we should do this
+      differently, like just special-case simple indentation elements in an
+      earlier part of the algorithm?  This way's a bit weird.
+      -->
+      <li>If <var>sublist</var>'s first member's [[parent]] is not an
+      <span>editable</span> <span>simple indentation element</span>, or
+      <var>sublist</var>'s first member's [[parent]]'s [[previoussibling]] is
+      not an <span>editable</span> <span>HTML element</span> with [[localname]]
+      <var>tag name</var>, call [[createelement|<var>tag name</var>]] on the
+      [[contextobject]] and return the result.
+
+      <li>Let <var>list</var> be <var>sublist</var>'s first member's
+      [[parent]]'s [[previoussibling]].
+
+      <li><span>Normalize sublists</span> of <var>list</var>'s [[lastchild]].
+
+      <li>If <var>list</var>'s [[lastchild]] is not an <span>editable</span>
       <span>HTML element</span> with [[localname]] <var>tag name</var>, call
-      [[createelement|<var>tag name</var>]] on the [[contextobject]] and return
-      the result.  Otherwise:
-
-      <li>Let <var>list</var> be the [[previoussibling]] of the [[parent]] of
-      <var>node</var>.
-
-      <li><span>Normalize sublists</span> of <var>list</var>'s last [[child]].
-
-      <li>If <var>list</var>'s last [[child]] is not an <span>editable</span>
-      <span>HTML element</span> with [[localname]] <var>tag name</var>, call
-      <code data-anolis-spec=domcore
-      title=dom-Document-createElement>createElement(<var>tag
-      name</var>)</code> on the [[contextobject]], and append the result as the
-      last [[child]] of <var>list</var>.
+      [[createelement|<var>tag name</var>]] on the [[contextobject]], and
+      append the result as the last [[child]] of <var>list</var>.
 
       <li>Return the last [[child]] of <var>list</var>.
     </ol>