Support insertUnorderedList
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Sun, 22 May 2011 15:37:45 -0600
changeset 162 14e80c71bb73
parent 161 b5e34f38f6ec
child 163 b8ce2db14e48
Support insertUnorderedList
autoimplementation.html
editcommands.html
implementation.js
source.html
--- a/autoimplementation.html	Sun May 22 15:08:59 2011 -0600
+++ b/autoimplementation.html	Sun May 22 15:37:45 2011 -0600
@@ -830,6 +830,191 @@
 		'<ul style=text-indent:1em><li>foo<li>bar<li>[baz]</ul>',
 	],
 	insertunorderedlist: [
+		'foo[]bar',
+		'<span>foo</span>{}<span>bar</span>',
+		'<span>foo[</span><span>]bar</span>',
+		'foo[bar]baz',
+		'foo]bar[baz',
+		'{<p><p> <p>foo</p>}',
+		'foo[bar<b>baz]qoz</b>quz',
+		'foo<br>[bar]',
+		'f[oo<br>b]ar<br>baz',
+		'<p>[foo]<br>bar</p>',
+		'[foo<ol><li>bar]</ol>baz',
+		'foo<ol><li>[bar</ol>baz]',
+		'[foo<ul><li>bar]</ul>baz',
+		'foo<ul><li>[bar</ul>baz]',
+		'foo<ul><li>[bar</ul><ol><li>baz]</ol>quz',
+		'foo<ol><li>[bar</ol><ul><li>baz]</ul>quz',
+
+		'<table><tbody><tr><td>foo<td>b[a]r<td>baz</table>',
+		'<table><tbody><tr data-start=1 data-end=2><td>foo<td>bar<td>baz</table>',
+		'<table><tbody><tr data-start=0 data-end=2><td>foo<td>bar<td>baz</table>',
+		'<table><tbody data-start=0 data-end=1><tr><td>foo<td>bar<td>baz</table>',
+		'<table data-start=0 data-end=1><tbody><tr><td>foo<td>bar<td>baz</table>',
+		'{<table><tr><td>foo<td>bar<td>baz</table>}',
+
+		'<p>foo<p>[bar]<p>baz',
+		'<p>foo<blockquote>[bar]</blockquote><p>baz',
+		'<dl><dt>foo<dd>[bar]<dt>baz<dd>quz</dl>',
+		'<dl><dt>foo<dd>bar<dt>[baz]<dd>quz</dl>',
+
+		'<p>foo<p>b[a]r<p>baz',
+		'<p>foo<blockquote>b[a]r</blockquote><p>baz',
+		'<dl><dt>foo<dd>b[a]r<dt>baz<dd>quz</dl>',
+		'<dl><dt>foo<dd>bar<dt>b[a]z<dd>quz</dl>',
+
+		'<p>[foo<p>bar]<p>baz',
+		'<p>[foo<blockquote>bar]</blockquote><p>baz',
+		'<dl><dt>[foo<dd>bar]<dt>baz<dd>quz</dl>',
+		'<dl><dt>foo<dd>[bar<dt>baz]<dd>quz</dl>',
+
+		'<p>[foo<blockquote><p>bar]<p>baz</blockquote>',
+
+
+		// Various <ol> stuff
+		'<ol><li>foo<li>[bar]<li>baz</ol>',
+		'<ol data-start=1 data-end=2><li>foo<li>bar<li>baz</ol>',
+		'<ol><li>foo</ol>[bar]',
+		'[foo]<ol><li>bar</ol>',
+		'<ol><li>foo</ol>[bar]<ol><li>baz</ol>',
+		'<ol><ol><li>[foo]</ol></ol>',
+		'<ol><li>[foo]<br>bar<li>baz</ol>',
+		'<ol><li>foo<br>[bar]<li>baz</ol>',
+		'<ol><li><div>[foo]</div>bar<li>baz</ol>',
+		'<ol><li>foo<ol><li>[bar]<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<ol><li>bar<li>[baz]</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol><li>[bar]<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol data-start=0 data-end=1><li>bar<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol><li>bar<li>[baz]</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol data-start=1 data-end=2><li>bar<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<ol><li>b[a]r</ol><li>baz</ol>',
+		'<ol><li>foo</li><ol><li>b[a]r</ol><li>baz</ol>',
+		'<ol><li>foo{<ol><li>bar</ol>}<li>baz</ol>',
+		'<ol><li>foo</li>{<ol><li>bar</ol>}<li>baz</ol>',
+		'<ol><li>[foo]<ol><li>bar</ol><li>baz</ol>',
+		'<ol><li>[foo]</li><ol><li>bar</ol><li>baz</ol>',
+		'<ol><li>foo<li>[bar]<ol><li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<li>[bar]</li><ol><li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<ol><li>bar<li>baz</ol><li>[quz]</ol>',
+		'<ol><li>foo</li><ol><li>bar<li>baz</ol><li>[quz]</ol>',
+
+		// Multiple items at once.
+		'<ol><li>foo<li>b[ar<li>baz]</ol>',
+		'<ol><li>[foo<ol><li>bar]</ol><li>baz</ol>',
+		'<ol><li>[foo</li><ol><li>bar]</ol><li>baz</ol>',
+		'<ol><li>foo<ol><li>b[ar</ol><li>b]az</ol>',
+		'<ol><li>foo</li><ol><li>b[ar</ol><li>b]az</ol>',
+		'<ol><li>[foo<ol><li>bar</ol><li>baz]</ol><p>extra',
+		'<ol><li>[foo</li><ol><li>bar</ol><li>baz]</ol><p>extra',
+		'<ol><li>foo<li>[bar</li><ol><li>baz</ol><li>quz]</ol>',
+
+		// We probably can't actually get this DOM . . .
+		'<ol><li>[foo]<ol><li>bar</ol>baz</ol>',
+		'<ol><li>foo<ol><li>[bar]</ol>baz</ol>',
+		'<ol><li>foo<ol><li>bar</ol>[baz]</ol>',
+		'<ol><li>[foo<ol><li>bar]</ol>baz</ol>',
+
+
+		// Same stuff but with <ul>
+		'<ul><li>foo<li>[bar]<li>baz</ul>',
+		'<ol data-start=1 data-end=2><li>foo<li>bar<li>baz</ul>',
+		'<ul><li>foo</ul>[bar]',
+		'[foo]<ul><li>bar</ul>',
+		'<ul><li>foo</ul>[bar]<ul><li>baz</ul>',
+		'<ul><ul><li>[foo]</ul></ul>',
+		'<ul><li>[foo]<br>bar<li>baz</ul>',
+		'<ul><li>foo<br>[bar]<li>baz</ul>',
+		'<ul><li><div>[foo]</div>bar<li>baz</ul>',
+		'<ul><li>foo<ul><li>[bar]<li>baz</ul><li>quz</ul>',
+		'<ul><li>foo<ul><li>bar<li>[baz]</ul><li>quz</ul>',
+		'<ul><li>foo</li><ul><li>[bar]<li>baz</ul><li>quz</ul>',
+		'<ul><li>foo</li><ul data-start=0 data-end=1><li>bar<li>baz</ul><li>quz</ul>',
+		'<ul><li>foo</li><ul><li>bar<li>[baz]</ul><li>quz</ul>',
+		'<ul><li>foo</li><ul data-start=1 data-end=2><li>bar<li>baz</ul><li>quz</ul>',
+		'<ul><li>foo<ul><li>b[a]r</ul><li>baz</ul>',
+		'<ul><li>foo</li><ul><li>b[a]r</ul><li>baz</ul>',
+		'<ul><li>foo{<ul><li>bar</ul>}<li>baz</ul>',
+		'<ul><li>foo</li>{<ul><li>bar</ul>}<li>baz</ul>',
+		'<ul><li>[foo]<ul><li>bar</ul><li>baz</ul>',
+		'<ul><li>[foo]</li><ul><li>bar</ul><li>baz</ul>',
+		'<ul><li>foo<li>[bar]<ul><li>baz</ul><li>quz</ul>',
+		'<ul><li>foo<li>[bar]</li><ul><li>baz</ul><li>quz</ul>',
+		'<ul><li>foo<ul><li>bar<li>baz</ul><li>[quz]</ul>',
+		'<ul><li>foo</li><ul><li>bar<li>baz</ul><li>[quz]</ul>',
+
+		// Multiple items at once.
+		'<ul><li>foo<li>b[ar<li>baz]</ul>',
+		'<ul><li>[foo<ul><li>bar]</ul><li>baz</ul>',
+		'<ul><li>[foo</li><ul><li>bar]</ul><li>baz</ul>',
+		'<ul><li>foo<ul><li>b[ar</ul><li>b]az</ul>',
+		'<ul><li>foo</li><ul><li>b[ar</ul><li>b]az</ul>',
+		'<ul><li>[foo<ul><li>bar</ul><li>baz]</ul><p>extra',
+		'<ul><li>[foo</li><ul><li>bar</ul><li>baz]</ul><p>extra',
+		'<ul><li>foo<li>[bar</li><ul><li>baz</ul><li>quz]</ul>',
+
+		// We probably can't actually get this DOM . . .
+		'<ul><li>[foo]<ul><li>bar</ul>baz</ul>',
+		'<ul><li>foo<ul><li>[bar]</ul>baz</ul>',
+		'<ul><li>foo<ul><li>bar</ul>[baz]</ul>',
+		'<ul><li>[foo<ul><li>bar]</ul>baz</ul>',
+
+
+		// Mix of <ol> and <ul>
+		'foo<ol><li>bar</ol><ul><li>[baz]</ul>quz',
+		'foo<ol><li>bar</ol><ul><li>[baz</ul>quz]',
+		'foo<ul><li>[bar]</ul><ol><li>baz</ol>quz',
+		'[foo<ul><li>bar]</ul><ol><li>baz</ol>quz',
+		'<ol><li>foo</li><ul><li>[bar]</ul><li>baz</ol>',
+		'<ul><li>foo</li><ol><li>[bar]</ol><li>baz</ul>',
+
+		// Interaction with indentation
+		'[foo]<blockquote>bar</blockquote>baz',
+		'foo<blockquote>[bar]</blockquote>baz',
+		'[foo<blockquote>bar]</blockquote>baz',
+		'<ol><li>foo</ol><blockquote>[bar]</blockquote>baz',
+		'[foo]<blockquote><ol><li>bar</ol></blockquote>baz',
+		'foo<blockquote>[bar]<br>baz</blockquote>',
+		'[foo<blockquote>bar]<br>baz</blockquote>',
+		'<ol><li>foo</ol><blockquote>[bar]<br>baz</blockquote>',
+
+		'<p>[foo]<blockquote><p>bar</blockquote><p>baz',
+		'<p>foo<blockquote><p>[bar]</blockquote><p>baz',
+		'<p>[foo<blockquote><p>bar]</blockquote><p>baz',
+		'<ol><li>foo</ol><blockquote><p>[bar]</blockquote><p>baz',
+		'<p>[foo]<blockquote><ol><li><p>bar</ol></blockquote><p>baz',
+		'<p>foo<blockquote><p>[bar]<p>baz</blockquote>',
+		'<p>[foo<blockquote><p>bar]<p>baz</blockquote>',
+		'<ol><li>foo</ol><blockquote><p>[bar]<p>baz</blockquote>',
+
+		'[foo]<div style="margin: 0 40px">bar</div>baz',
+		'foo<div style="margin: 0 40px">[bar]</div>baz',
+		'[foo<div style="margin: 0 40px">bar]</div>baz',
+		'<ol><li>foo</ol><div style="margin: 0 40px">[bar]</div>baz',
+		'[foo]<div style="margin: 0 40px"><ol><li>bar</ol></div>baz',
+		'foo<div style="margin: 0 40px">[bar]<br>baz</div>',
+		'[foo<div style="margin: 0 40px">bar]<br>baz</div>',
+		'<ol><li>foo</ol><div style="margin: 0 40px">[bar]<br>baz</div>',
+
+		'<p>[foo]<div style="margin: 0 40px"><p>bar</div><p>baz',
+		'<p>foo<div style="margin: 0 40px"><p>[bar]</div><p>baz',
+		'<p>[foo<div style="margin: 0 40px"><p>bar]</div><p>baz',
+		'<ol><li>foo</ol><div style="margin: 0 40px"><p>[bar]</div><p>baz',
+		'<p>[foo]<div style="margin: 0 40px"><ol><li><p>bar</ol></div><p>baz',
+		'<p>foo<div style="margin: 0 40px"><p>[bar]<p>baz</div>',
+		'<p>[foo<div style="margin: 0 40px"><p>bar]<p>baz</div>',
+		'<ol><li>foo</ol><div style="margin: 0 40px"><p>[bar]<p>baz</div>',
+
+		// Attributes
+		'<ul id=abc><li>foo<li>[bar]<li>baz</ul>',
+		'<ul style=color:red><li>foo<li>[bar]<li>baz</ul>',
+		'<ul style=text-indent:1em><li>foo<li>[bar]<li>baz</ul>',
+		'<ul id=abc><li>[foo]<li>bar<li>baz</ul>',
+		'<ul style=color:red><li>[foo]<li>bar<li>baz</ul>',
+		'<ul style=text-indent:1em><li>[foo]<li>bar<li>baz</ul>',
+		'<ul id=abc><li>foo<li>bar<li>[baz]</ul>',
+		'<ul style=color:red><li>foo<li>bar<li>[baz]</ul>',
+		'<ul style=text-indent:1em><li>foo<li>bar<li>[baz]</ul>',
 	],
 	italic: [
 		'foo[]bar',
--- a/editcommands.html	Sun May 22 15:08:59 2011 -0600
+++ b/editcommands.html	Sun May 22 15:37:45 2011 -0600
@@ -104,9 +104,11 @@
    <li><a href=#assorted-block-formatting-command-algorithms><span class=secno>7.2 </span>Assorted block formatting command algorithms</a></li>
    <li><a href=#outdenting-a-node><span class=secno>7.3 </span>Outdenting a node</a></li>
    <li><a href=#block-extending-a-range><span class=secno>7.4 </span>Block-extending a range</a></li>
-   <li><a href=#the-indent-command><span class=secno>7.5 </span>The <code title="">indent</code> command</a></li>
-   <li><a href=#the-insertorderedlist-command><span class=secno>7.6 </span>The <code title="">insertOrderedList</code> command</a></li>
-   <li><a href=#the-outdent-command><span class=secno>7.7 </span>The <code title="">outdent</code> command</a></ol></li>
+   <li><a href=#toggling-lists><span class=secno>7.5 </span>Toggling lists</a></li>
+   <li><a href=#the-indent-command><span class=secno>7.6 </span>The <code title="">indent</code> command</a></li>
+   <li><a href=#the-insertorderedlist-command><span class=secno>7.7 </span>The <code title="">insertOrderedList</code> command</a></li>
+   <li><a href=#the-insertunorderedlist-command><span class=secno>7.8 </span>The <code title="">insertUnorderedList</code> command</a></li>
+   <li><a href=#the-outdent-command><span class=secno>7.9 </span>The <code title="">outdent</code> command</a></ol></li>
  <li><a href=#miscellaneous-commands><span class=secno>8 </span>Miscellaneous commands</a>
   <ol>
    <li><a href=#the-stylewithcss-command><span class=secno>8.1 </span>The <code title="">styleWithCSS</code> command</a></li>
@@ -2904,103 +2906,7 @@
   <li>Return <var title="">new range</var>.
 </ol>
 
-
-<h3 id=the-indent-command><span class=secno>7.5 </span><dfn>The <code title="">indent</code> command</dfn></h3>
-<!--
-IE9: Outputs <blockquote style="margin-right: 0px" dir="ltr">, or when
-  surrounding RTL blocks, <blockquote style="margin-left: 0px" dir="rtl">.  The
-  direction seems to go by the end of the selection.  The presence of the dir
-  attribute means that any contents that were inheriting a different dir from
-  an ancestor get their direction changed as a side effect, but if they
-  actually have the opposite dir specified, they won't appear to be indented.
-  It doesn't reset top or bottom margins on the blockquote, so it adds them.
-  If it's not wrapping a block element, like if it's only wrapping up until a
-  <br>, it adds a <p>.
-Firefox 4.0: In styleWithCSS mode, adds style="margin-left: 40px" to the
-  appropriate block container (or margin-right if it's RTL).  If there's no
-  appropriate block container, adds a div.  If multiple blocks are affected, it
-  goes by the direction of the block whose style it's changing, which winds up
-  being wrong for descendants with different direction.  In non-styleWithCSS
-  mode, uses <blockquote>, so it indents on both sides and also adds top/bottom
-  margins.
-Chrome 12 dev: Outputs <blockquote class="webkit-indent-blockquote"
-  style="margin: 0 0 0 40px; border: none; padding: 0px"> in both modes for
-  both LTR and RTL (which is broken for RTL, since it indents only on the
-  left).
-Opera 11.00: Outputs <blockquote>, so it indents on both sides and on the
-  top/bottom.
-
-For repeated indentation, everyone except Opera that outputs <blockquote>s just
-puts them at the outermost possible location, which works well.  Opera puts
-them in the innermost position, which is broken, because it will even put them
-inside <p> (which will not round-trip through text/html serialization).
-
-Gecko in CSS mode messes up by adding margins even to things like <blockquote>
-that already have margins from CSS rules, instead of nesting a div, so it
-doesn't actually increase the indentation.  However, if an element has an
-explicit left margin (assuming LTR), it will increase the margin to 80px, so it
-works with WebKit's blockquotes.
-
-
-We have two strategies for handling directionality: always indent on both sides
-(Firefox non-CSS, Opera) or try to figure out heuristically which side we want
-(IE, Firefox CSS).  The latter approach is only possible by adding extra markup
-and complexity, so for now we'll take the easy way out and go with just
-indenting on both sides.
-
-
-This reasoning doesn't discuss lists.  For research on lists, see the comment
-for insertOrderedList.  List handling is more complicated and I wound up
-differing from all browsers in lots of ways.
--->
-
-<p><a href=#action>Action</a>:
-
-<p class=XXX>Handle corner cases: endpoints are detached, documents, document
-fragments, html/body, head or things in head . . .
-
-<ol>
-  <li>Let <var title="">items</var> be a list of all <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>s that are
-  <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#ancestor-container title="ancestor container">ancestor containers</a> of the <a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>
-  and/or <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
-
-  <li>For each <var title="">item</var> in <var title="">items</var>, <a href=#normalize-sublists>normalize
-  sublists</a> of <var title="">item</var>.
-  <!-- This overnormalizes, but it seems like the simplest solution for now.
-  -->
-
-  <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>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>,
-  if <var title="">node</var> is <a href=#editable>editable</a> and can 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>child</a> of a
-  <code class=external data-anolis-spec=html title="the div element"><a href=http://www.whatwg.org/html/#the-div-element>div</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> and if no <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of <var title="">node</var> is in
-  <var title="">node list</var>, append <var title="">node</var> to <var title="">node list</var>.
-
-  <li>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> 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 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>, 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> 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> as well,
-  <a href=#normalize-sublists>normalize sublists</a> of 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>.
-  <!-- Otherwise the last child of the previous sibling might be a list, which
-  the li wouldn't get appended to. -->
-
-  <li>While <var title="">node list</var> is not empty:
-
-  <ol>
-    <li>Let <var title="">sublist</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>Remove the first member of <var title="">node list</var> and append it to
-    <var title="">sublist</var>.
-
-    <li>While 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>, remove the first member of
-    <var title="">node list</var> and append it to <var title="">sublist</var>.
-
-    <li><a href=#indent>Indent</a> <var title="">sublist</var>.
-  </ol>
-</ol>
-
+<h3 id=toggling-lists><span class=secno>7.5 </span>Toggling lists</h3>
 
 <!--
 Research for insertOrderedList/insertUnorderedList: tested the following
@@ -3314,11 +3220,13 @@
 
 Sheesh, lists are complicated.
 -->
-<h3 id=the-insertorderedlist-command><span class=secno>7.6 </span><dfn>The <code title="">insertOrderedList</code> command</dfn></h3>
-
-<p><a href=#action>Action</a>:
+<p>To <dfn id=toggle-lists>toggle lists</dfn>, given a string <var title="">tag name</var> (either "ol"
+or "ul"):
 
 <ol>
+  <li>Let <var title="">other tag name</var> be "ol" if <var title="">tag name</var> is "ul", and
+  "ul" if <var title="">tag name</var> is "ol".
+
   <li>Let <var title="">items</var> be a list of all <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>s that are
   <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#ancestor-container title="ancestor container">ancestor containers</a> of the <a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>
   and/or <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
@@ -3363,9 +3271,11 @@
   child" is not well-defined, and it's not clear what the right definition
   should be.
 
-  <li>If every member of <var title="">node list</var> is either 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 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 <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 no member of <var title="">node list</var> is a <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code> or
-  the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of a <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, then while <var title="">node list</var> is not empty:
+  <li>If every member of <var title="">node list</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>, and no
+  member of <var title="">node list</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-ancestor title=concept-tree-ancestor>ancestor</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>, then
+  while <var title="">node list</var> is not empty:
 
   <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>.
@@ -3373,13 +3283,15 @@
     <li>Remove the first member from <var title="">node list</var> and append it to
     <var title="">sublist</var>.
 
-    <li>If the first 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>,
-    <a href=#outdent>outdent</a> it and continue this loop from the beginning.
+    <li>If the first member of <var title="">sublist</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="">tag name</var>, <a href=#outdent>outdent</a>
+    it and continue this loop from the beginning.
 
     <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 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>, remove the first member from
-    <var title="">node list</var> and append it to <var title="">sublist</var>.
+    <var title="">sublist</var> and is not 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>, remove the first member from <var title="">node
+    list</var> and append it to <var title="">sublist</var>.
 
     <li><a href=#split-the-parent>Split the parent</a> of <var title="">sublist</var>.
 
@@ -3410,7 +3322,8 @@
     <li>Otherwise, let <var title="">node</var> be the sole member of
     <var title="">sublist</var>.
 
-    <li>If <var title="">node</var> is a <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>:
+    <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>:
 
     <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>.
@@ -3418,12 +3331,14 @@
       <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
-      criteria</a> matching 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> 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("ol")</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>Prepend the <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 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> (if any) to
-      <var title="">node list</var>.
+      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 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.
+
+      <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.
 
@@ -3458,27 +3373,31 @@
     <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 a <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>:
+    <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>:
 
     <ol>
       <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 <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>,
+      <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("ol")</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>Prepend the <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 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> (if any) to
-      <var title="">node list</var>.
+      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>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 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 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 <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>, prepend
-    the <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 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> (if any) to <var title="">node
-    list</var> and continue from the beginning of this loop.
+    <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 the <a href=#sibling-criteria>sibling criteria</a>
@@ -3487,33 +3406,145 @@
     <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><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 <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
-    <a href=#new-parent-instructions>new parent instructions</a> being the following:
+    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=#indentation-element>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> <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</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("ol")</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="">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
+      <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=#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="">ol</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="">ol</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>
-      <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</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("ol")</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="">ol</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="">ol</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>.
+
+      <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>
   </ol>
 </ol>
 
 
-<h3 id=the-outdent-command><span class=secno>7.7 </span><dfn>The <code title="">outdent</code> command</dfn></h3>
+<h3 id=the-indent-command><span class=secno>7.6 </span><dfn>The <code title="">indent</code> command</dfn></h3>
+<!--
+IE9: Outputs <blockquote style="margin-right: 0px" dir="ltr">, or when
+  surrounding RTL blocks, <blockquote style="margin-left: 0px" dir="rtl">.  The
+  direction seems to go by the end of the selection.  The presence of the dir
+  attribute means that any contents that were inheriting a different dir from
+  an ancestor get their direction changed as a side effect, but if they
+  actually have the opposite dir specified, they won't appear to be indented.
+  It doesn't reset top or bottom margins on the blockquote, so it adds them.
+  If it's not wrapping a block element, like if it's only wrapping up until a
+  <br>, it adds a <p>.
+Firefox 4.0: In styleWithCSS mode, adds style="margin-left: 40px" to the
+  appropriate block container (or margin-right if it's RTL).  If there's no
+  appropriate block container, adds a div.  If multiple blocks are affected, it
+  goes by the direction of the block whose style it's changing, which winds up
+  being wrong for descendants with different direction.  In non-styleWithCSS
+  mode, uses <blockquote>, so it indents on both sides and also adds top/bottom
+  margins.
+Chrome 12 dev: Outputs <blockquote class="webkit-indent-blockquote"
+  style="margin: 0 0 0 40px; border: none; padding: 0px"> in both modes for
+  both LTR and RTL (which is broken for RTL, since it indents only on the
+  left).
+Opera 11.00: Outputs <blockquote>, so it indents on both sides and on the
+  top/bottom.
+
+For repeated indentation, everyone except Opera that outputs <blockquote>s just
+puts them at the outermost possible location, which works well.  Opera puts
+them in the innermost position, which is broken, because it will even put them
+inside <p> (which will not round-trip through text/html serialization).
+
+Gecko in CSS mode messes up by adding margins even to things like <blockquote>
+that already have margins from CSS rules, instead of nesting a div, so it
+doesn't actually increase the indentation.  However, if an element has an
+explicit left margin (assuming LTR), it will increase the margin to 80px, so it
+works with WebKit's blockquotes.
+
+
+We have two strategies for handling directionality: always indent on both sides
+(Firefox non-CSS, Opera) or try to figure out heuristically which side we want
+(IE, Firefox CSS).  The latter approach is only possible by adding extra markup
+and complexity, so for now we'll take the easy way out and go with just
+indenting on both sides.
+
+
+This reasoning doesn't discuss lists.  For research on lists, see the comment
+for insertOrderedList.  List handling is more complicated and I wound up
+differing from all browsers in lots of ways.
+-->
+
+<p><a href=#action>Action</a>:
+
+<p class=XXX>Handle corner cases: endpoints are detached, documents, document
+fragments, html/body, head or things in head . . .
+
+<ol>
+  <li>Let <var title="">items</var> be a list of all <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>s that are
+  <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#ancestor-container title="ancestor container">ancestor containers</a> of the <a href=#active-range>active range</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>
+  and/or <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
+
+  <li>For each <var title="">item</var> in <var title="">items</var>, <a href=#normalize-sublists>normalize
+  sublists</a> of <var title="">item</var>.
+  <!-- This overnormalizes, but it seems like the simplest solution for now.
+  -->
+
+  <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>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>,
+  if <var title="">node</var> is <a href=#editable>editable</a> and can 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>child</a> of a
+  <code class=external data-anolis-spec=html title="the div element"><a href=http://www.whatwg.org/html/#the-div-element>div</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> and if no <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of <var title="">node</var> is in
+  <var title="">node list</var>, append <var title="">node</var> to <var title="">node list</var>.
+
+  <li>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> 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 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>, 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> 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> as well,
+  <a href=#normalize-sublists>normalize sublists</a> of 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>.
+  <!-- Otherwise the last child of the previous sibling might be a list, which
+  the li wouldn't get appended to. -->
+
+  <li>While <var title="">node list</var> is not empty:
+
+  <ol>
+    <li>Let <var title="">sublist</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>Remove the first member of <var title="">node list</var> and append it to
+    <var title="">sublist</var>.
+
+    <li>While 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>, remove the first member of
+    <var title="">node list</var> and append it to <var title="">sublist</var>.
+
+    <li><a href=#indent>Indent</a> <var title="">sublist</var>.
+  </ol>
+</ol>
+
+
+<h3 id=the-insertorderedlist-command><span class=secno>7.7 </span><dfn>The <code title="">insertOrderedList</code> command</dfn></h3>
+
+<p><a href=#action>Action</a>: <a href=#toggle-lists>Toggle lists</a> with <var title="">tag name</var>
+"ol".
+
+
+<h3 id=the-insertunorderedlist-command><span class=secno>7.8 </span><dfn>The <code title="">insertUnorderedList</code> command</dfn></h3>
+
+<p><a href=#action>Action</a>: <a href=#toggle-lists>Toggle lists</a> with <var title="">tag name</var>
+"ul".
+
+
+<h3 id=the-outdent-command><span class=secno>7.9 </span><dfn>The <code title="">outdent</code> command</dfn></h3>
 
 <p><a href=#action>Action</a>:
 
--- a/implementation.js	Sun May 22 15:08:59 2011 -0600
+++ b/implementation.js	Sun May 22 15:37:45 2011 -0600
@@ -2560,249 +2560,13 @@
 		break;
 
 		case "insertorderedlist":
-		// "Let items be a list of all lis that are ancestor containers of the
-		// range's start and/or end node."
-		//
-		// Has to be in tree order, remember!
-		var items = [];
-		for (var node = range.endContainer; node != range.commonAncestorContainer; node = node.parentNode) {
-			if (isHtmlElement(node, "LI")) {
-				items.unshift(node);
-			}
-		}
-		for (var node = range.startContainer; node != range.commonAncestorContainer; node = node.parentNode) {
-			if (isHtmlElement(node, "LI")) {
-				items.unshift(node);
-			}
-		}
-		for (var node = range.commonAncestorContainer; node; node = node.parentNode) {
-			if (isHtmlElement(node, "LI")) {
-				items.unshift(node);
-			}
-		}
-
-		// "For each item in items, normalize sublists of item."
-		for (var i = 0; i < items.length; i++) {
-			normalizeSublists(items[i]);
-		}
-
-		// "Block-extend the range, and let new range be the result."
-		var newRange = blockExtendRange(range);
-
-		// "Let node list be a list of nodes, initially empty."
-		var nodeList = [];
-
-		// "For each node node contained in new range, if node is editable; the
-		// last member of node list (if any) is not an ancestor of node; node
-		// is not a potential indentation element; and either node is an ol or
-		// ul, or its parent is an ol or ul, or it can be the child of an li;
-		// then append node to node list."
-		for (
-			var node = newRange.startContainer;
-			node != nextNodeDescendants(newRange.endContainer);
-			node = nextNode(node)
-		) {
-			if (isEditable(node)
-			&& isContained(node, newRange)
-			&& (!nodeList.length || !isAncestor(nodeList[nodeList.length - 1], node))
-			&& !isPotentialIndentationElement(node)
-			&& (isHtmlElement(node, ["OL", "UL"])
-			|| isHtmlElement(node.parentNode, ["OL", "UL"])
-			// As usual with content restrictions, we fake it for testing
-			// purposes.
-			|| !isHtmlElement(node)
-			|| ["THEAD", "TBODY", "TR", "TH", "TD", "DT", "DD"].indexOf(node.tagName) == -1)) {
-				nodeList.push(node);
-			}
-		}
-
-		// "If every member of node list is either an ol or the child of an ol,
-		// and no member of node list is a ul or the ancestor of a ul, then
-		// while node list is not empty:"
-		if (nodeList.every(function(node) { return isHtmlElement(node, "OL") || isHtmlElement(node.parentNode, "OL") })
-		&& !nodeList.some(function(node) { return isHtmlElement(node, "UL") || node.querySelector("ul") })) {
-			while (nodeList.length) {
-				// "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());
-
-				// "If the first member of sublist is an ol, outdent it and
-				// continue this loop from the beginning."
-				if (isHtmlElement(sublist[0], "OL")) {
-					outdentNode(sublist[0]);
-					continue;
-				}
-
-				// "While node list is not empty, and the first member of node
-				// list is the nextSibling of the last member of sublist and is
-				// not an ol, remove the first member from node list and append
-				// it to sublist."
-				while (nodeList.length
-				&& nodeList[0] == sublist[sublist.length - 1].nextSibling
-				&& !isHtmlElement(nodeList[0], "OL")) {
-					sublist.push(nodeList.shift());
-				}
-
-				// "Split the parent of sublist."
-				splitParent(sublist);
-
-				// "Fix orphaned list items in sublist."
-				fixOrphanedListItems(sublist);
-			}
-
-		// "Otherwise, while node list is not empty:"
-		} else {
-			while (nodeList.length) {
-				// "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());
-				}
-
-				// "If sublist contains more than one member, wrap it, with
-				// sibling criteria matching nothing and with 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 node is a ul:"
-				if (isHtmlElement(node, "UL")) {
-					// "Let children be the children of node."
-					var children = [].slice.call(node.childNodes);
-
-					// "Remove node, preserving its descendants."
-					removePreservingDescendants(node);
-
-					// "Wrap children, with sibling criteria matching any ol
-					// and new parent instructions returning the result of
-					// calling createElement("ol") on the context object. Let
-					// node be the result."
-					node = wrap(children,
-						function(node) { return isHtmlElement(node, "OL") },
-						function() { return document.createElement("ol") });
-
-					// "Prepend the ul descendants of node (if any) to node
-					// list."
-					nodeList = [].slice.call(node.querySelectorAll("ul")).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 a ul:"
-				if (isHtmlElement(node.parentNode, "UL")) {
-					// "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 ol, and with new parent
-					// instructions returning the result of calling
-					// createElement("ol") on the context object."
-					wrap([node],
-						function(node) { return isHtmlElement(node, "OL") },
-						function() { return document.createElement("ol") });
-
-					// "Prepend the ul descendants of node (if any) to node
-					// list."
-					nodeList = [].slice.call(node.querySelectorAll("ul")).concat(nodeList);
-
-					// "Continue from the beginning of this loop."
-					continue;
-				}
-
-				// "If node is an ol or the child of an ol, prepend the
-				// ul descendants of node (if any) to node list and continue
-				// from the beginning of this loop."
-				if (isHtmlElement(node, "OL")
-				|| isHtmlElement(node.parentNode, "OL")) {
-					nodeList = [].slice.call(node.querySelectorAll("ul")).concat(nodeList);
-					continue;
-				}
-
-				// "If node is not an li, wrap the one-node list consisting of
-				// node, with the sibling criteria matching nothing, and the
-				// new parent instructions returning the result of calling
-				// createElement("li") on the context object. Let node be 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 ol, and the new parent instructions
-				// being the following:"
-				wrap([node],
-					function(node) { return isHtmlElement(node, "OL") },
-					function() {
-						// "If the parent of node is not an editable
-						// indentation element, or the previousSibling of the
-						// parent of node is not an editable ol, call
-						// createElement("ol") on the context object and return
-						// the result. Otherwise:"
-						if (!isEditable(node.parentNode)
-						|| !isIndentationElement(node.parentNode)
-						|| !isEditable(node.parentNode.previousSibling)
-						|| !isHtmlElement(node.parentNode.previousSibling, "OL")) {
-							return document.createElement("ol");
-						}
-
-						// "Let ol be the previousSibling of the parent of
-						// node."
-						var ol = node.parentNode.previousSibling;
-
-						// "Normalize sublists of ol's last child."
-						normalizeSublists(ol.lastChild);
-
-						// "If ol's last child is not an editable ol, call
-						// createElement("ol") on the context object, and
-						// append the result as the last child of ol."
-						if (!isEditable(ol.lastChild)
-						|| !isHtmlElement(ol.lastChild, "OL")) {
-							ol.appendChild(document.createElement("ol"));
-						}
-
-						// "Return the last child of ol."
-						return ol.lastChild;
-					});
-			}
-		}
+		// "Toggle lists with tag name "ol"."
+		toggleLists(range, "ol");
+		break;
+
+		case "insertunorderedlist":
+		// "Toggle lists with tag name "ul"."
+		toggleLists(range, "ul");
 		break;
 
 		case "italic":
@@ -3297,6 +3061,262 @@
 	outdentNode(originalAncestor);
 }
 
+function toggleLists(range, tagName) {
+	tagName = tagName.toUpperCase();
+
+	// "Let other tag name be "ol" if tag name is "ul", and "ul" if tag name is
+	// "ol"."
+	var otherTagName = tagName == "OL" ? "UL" : "OL";
+
+	// "Let items be a list of all lis that are ancestor containers of the
+	// range's start and/or end node."
+	//
+	// Has to be in tree order, remember!
+	var items = [];
+	for (var node = range.endContainer; node != range.commonAncestorContainer; node = node.parentNode) {
+		if (isHtmlElement(node, "LI")) {
+			items.unshift(node);
+		}
+	}
+	for (var node = range.startContainer; node != range.commonAncestorContainer; node = node.parentNode) {
+		if (isHtmlElement(node, "LI")) {
+			items.unshift(node);
+		}
+	}
+	for (var node = range.commonAncestorContainer; node; node = node.parentNode) {
+		if (isHtmlElement(node, "LI")) {
+			items.unshift(node);
+		}
+	}
+
+	// "For each item in items, normalize sublists of item."
+	for (var i = 0; i < items.length; i++) {
+		normalizeSublists(items[i]);
+	}
+
+	// "Block-extend the range, and let new range be the result."
+	var newRange = blockExtendRange(range);
+
+	// "Let node list be a list of nodes, initially empty."
+	var nodeList = [];
+
+	// "For each node node contained in new range, if node is editable; the
+	// last member of node list (if any) is not an ancestor of node; node
+	// is not a potential indentation element; and either node is an ol or
+	// ul, or its parent is an ol or ul, or it can be the child of an li;
+	// then append node to node list."
+	for (
+		var node = newRange.startContainer;
+		node != nextNodeDescendants(newRange.endContainer);
+		node = nextNode(node)
+	) {
+		if (isEditable(node)
+		&& isContained(node, newRange)
+		&& (!nodeList.length || !isAncestor(nodeList[nodeList.length - 1], node))
+		&& !isPotentialIndentationElement(node)
+		&& (isHtmlElement(node, ["OL", "UL"])
+		|| isHtmlElement(node.parentNode, ["OL", "UL"])
+		// As usual with content restrictions, we fake it for testing
+		// purposes.
+		|| !isHtmlElement(node)
+		|| ["THEAD", "TBODY", "TR", "TH", "TD", "DT", "DD"].indexOf(node.tagName) == -1)) {
+			nodeList.push(node);
+		}
+	}
+
+	// "If every member of node list is equal to or the child of an HTML
+	// element with local name tag name, and no member of node list is equal to
+	// or the ancestor of an HTML element with local name other tag name, then
+	// while node list is not empty:"
+	if (nodeList.every(function(node) { return isHtmlElement(node, tagName) || isHtmlElement(node.parentNode, tagName) })
+	&& !nodeList.some(function(node) { return isHtmlElement(node, otherTagName) || node.querySelector(otherTagName) })) {
+		while (nodeList.length) {
+			// "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());
+
+			// "If the first member of sublist is an HTML element with local
+			// name tag name, outdent it and continue this loop from the
+			// beginning."
+			if (isHtmlElement(sublist[0], tagName)) {
+				outdentNode(sublist[0]);
+				continue;
+			}
+
+			// "While node list is not empty, and the first member of node list
+			// is the nextSibling of the last member of sublist and is not an
+			// HTML element with local name tag name, remove the first member
+			// from node list and append it to sublist."
+			while (nodeList.length
+			&& nodeList[0] == sublist[sublist.length - 1].nextSibling
+			&& !isHtmlElement(nodeList[0], tagName)) {
+				sublist.push(nodeList.shift());
+			}
+
+			// "Split the parent of sublist."
+			splitParent(sublist);
+
+			// "Fix orphaned list items in sublist."
+			fixOrphanedListItems(sublist);
+		}
+
+	// "Otherwise, while node list is not empty:"
+	} else {
+		while (nodeList.length) {
+			// "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());
+			}
+
+			// "If sublist contains more than one member, wrap it, with
+			// sibling criteria matching nothing and with 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 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);
+
+				// "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,
+					function(node) { return isHtmlElement(node, tagName) },
+					function() { return document.createElement(tagName) });
+
+				// "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)) {
+				// "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) });
+
+				// "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 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 the sibling criteria matching nothing, and the
+			// new parent instructions returning the result of calling
+			// createElement("li") on the context object. Let node be 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:"
+			wrap([node],
+				function(node) { return isHtmlElement(node, tagName) },
+				function() {
+					// "If the parent of node is not an editable 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)
+					|| !isIndentationElement(node.parentNode)
+					|| !isEditable(node.parentNode.previousSibling)
+					|| !isHtmlElement(node.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."
+					normalizeSublists(list.lastChild);
+
+					// "If list's last child 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."
+					if (!isEditable(list.lastChild)
+					|| !isHtmlElement(list.lastChild, tagName)) {
+						list.appendChild(document.createElement(tagName));
+					}
+
+					// "Return the last child of list."
+					return list.lastChild;
+				});
+		}
+	}
+}
+
 function fixOrphanedListItems(nodeList) {
 	// "For each li item in node list:"
 	for (var i = 0; i < nodeList.length; i++) {
--- a/source.html	Sun May 22 15:08:59 2011 -0600
+++ b/source.html	Sun May 22 15:37:45 2011 -0600
@@ -2922,103 +2922,7 @@
   <li>Return <var>new range</var>.
 </ol>
 
-
-<h3><dfn>The <code title>indent</code> command</dfn></h3>
-<!--
-IE9: Outputs <blockquote style="margin-right: 0px" dir="ltr">, or when
-  surrounding RTL blocks, <blockquote style="margin-left: 0px" dir="rtl">.  The
-  direction seems to go by the end of the selection.  The presence of the dir
-  attribute means that any contents that were inheriting a different dir from
-  an ancestor get their direction changed as a side effect, but if they
-  actually have the opposite dir specified, they won't appear to be indented.
-  It doesn't reset top or bottom margins on the blockquote, so it adds them.
-  If it's not wrapping a block element, like if it's only wrapping up until a
-  <br>, it adds a <p>.
-Firefox 4.0: In styleWithCSS mode, adds style="margin-left: 40px" to the
-  appropriate block container (or margin-right if it's RTL).  If there's no
-  appropriate block container, adds a div.  If multiple blocks are affected, it
-  goes by the direction of the block whose style it's changing, which winds up
-  being wrong for descendants with different direction.  In non-styleWithCSS
-  mode, uses <blockquote>, so it indents on both sides and also adds top/bottom
-  margins.
-Chrome 12 dev: Outputs <blockquote class="webkit-indent-blockquote"
-  style="margin: 0 0 0 40px; border: none; padding: 0px"> in both modes for
-  both LTR and RTL (which is broken for RTL, since it indents only on the
-  left).
-Opera 11.00: Outputs <blockquote>, so it indents on both sides and on the
-  top/bottom.
-
-For repeated indentation, everyone except Opera that outputs <blockquote>s just
-puts them at the outermost possible location, which works well.  Opera puts
-them in the innermost position, which is broken, because it will even put them
-inside <p> (which will not round-trip through text/html serialization).
-
-Gecko in CSS mode messes up by adding margins even to things like <blockquote>
-that already have margins from CSS rules, instead of nesting a div, so it
-doesn't actually increase the indentation.  However, if an element has an
-explicit left margin (assuming LTR), it will increase the margin to 80px, so it
-works with WebKit's blockquotes.
-
-
-We have two strategies for handling directionality: always indent on both sides
-(Firefox non-CSS, Opera) or try to figure out heuristically which side we want
-(IE, Firefox CSS).  The latter approach is only possible by adding extra markup
-and complexity, so for now we'll take the easy way out and go with just
-indenting on both sides.
-
-
-This reasoning doesn't discuss lists.  For research on lists, see the comment
-for insertOrderedList.  List handling is more complicated and I wound up
-differing from all browsers in lots of ways.
--->
-
-<p><span>Action</span>:
-
-<p class=XXX>Handle corner cases: endpoints are detached, documents, document
-fragments, html/body, head or things in head . . .
-
-<ol>
-  <li>Let <var>items</var> be a list of all [[li]]s that are
-  [[ancestorcontainers]] of the <span>active range</span>'s [[rangestart]]
-  and/or [[rangeend]] [[bpnode]].
-
-  <li>For each <var>item</var> in <var>items</var>, <span>normalize
-  sublists</span> of <var>item</var>.
-  <!-- This overnormalizes, but it seems like the simplest solution for now.
-  -->
-
-  <li><span>Block-extend</span> the <span>active range</span>, and let <var>new
-  range</var> be the result.
-
-  <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>,
-  if <var>node</var> is <span>editable</span> and can be the [[child]] of a
-  [[div]] or [[ol]] or [[ul]] and if no [[ancestor]] of <var>node</var> is in
-  <var>node list</var>, append <var>node</var> to <var>node list</var>.
-
-  <li>If the first member of <var>node list</var> is an [[li]] whose [[parent]]
-  is an [[ol]] or [[ul]], and its [[previoussibling]] is an [[li]] as well,
-  <span>normalize sublists</span> of its [[previoussibling]].
-  <!-- Otherwise the last child of the previous sibling might be a list, which
-  the li wouldn't get appended to. -->
-
-  <li>While <var>node list</var> is not empty:
-
-  <ol>
-    <li>Let <var>sublist</var> be a list of [[nodes]], initially empty.
-
-    <li>Remove the first member of <var>node list</var> and append it to
-    <var>sublist</var>.
-
-    <li>While the first member of <var>node list</var> is the [[nextsibling]]
-    of the last member of <var>sublist</var>, remove the first member of
-    <var>node list</var> and append it to <var>sublist</var>.
-
-    <li><span>Indent</span> <var>sublist</var>.
-  </ol>
-</ol>
-
+<h3>Toggling lists</h3>
 
 <!--
 Research for insertOrderedList/insertUnorderedList: tested the following
@@ -3332,11 +3236,13 @@
 
 Sheesh, lists are complicated.
 -->
-<h3><dfn>The <code title>insertOrderedList</code> command</dfn></h3>
-
-<p><span>Action</span>:
+<p>To <dfn>toggle lists</dfn>, given a string <var>tag name</var> (either "ol"
+or "ul"):
 
 <ol>
+  <li>Let <var>other tag name</var> be "ol" if <var>tag name</var> is "ul", and
+  "ul" if <var>tag name</var> is "ol".
+
   <li>Let <var>items</var> be a list of all [[li]]s that are
   [[ancestorcontainers]] of the <span>active range</span>'s [[rangestart]]
   and/or [[rangeend]] [[bpnode]].
@@ -3381,9 +3287,11 @@
   child" is not well-defined, and it's not clear what the right definition
   should be.
 
-  <li>If every member of <var>node list</var> is either an [[ol]] or the
-  [[child]] of an [[ol]], and no member of <var>node list</var> is a [[ul]] or
-  the [[ancestor]] of a [[ul]], then while <var>node list</var> is not empty:
+  <li>If every member of <var>node list</var> is equal to or the [[child]] of
+  an <span>HTML element</span> with [[localname]] <var>tag name</var>, and no
+  member of <var>node list</var> is equal to or the [[ancestor]] of an
+  <span>HTML element</span> with [[localname]] <var>other tag name</var>, then
+  while <var>node list</var> is not empty:
 
   <ol>
     <li>Let <var>sublist</var> be an empty list of [[nodes]].
@@ -3391,13 +3299,15 @@
     <li>Remove the first member from <var>node list</var> and append it to
     <var>sublist</var>.
 
-    <li>If the first member of <var>sublist</var> is an [[ol]],
-    <span>outdent</span> it and continue this loop from the beginning.
+    <li>If the first member of <var>sublist</var> is an <span>HTML
+    element</span> with [[localname]] <var>tag name</var>, <span>outdent</span>
+    it and continue this loop from the beginning.
 
     <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 is not an [[ol]], remove the first member from
-    <var>node list</var> and append it to <var>sublist</var>.
+    <var>sublist</var> and is not an <span>HTML element</span> with
+    [[localname]] <var>tag name</var>, remove the first member from <var>node
+    list</var> and append it to <var>sublist</var>.
 
     <li><span>Split the parent</span> of <var>sublist</var>.
 
@@ -3430,7 +3340,8 @@
     <li>Otherwise, let <var>node</var> be the sole member of
     <var>sublist</var>.
 
-    <li>If <var>node</var> is a [[ul]]:
+    <li>If <var>node</var> is an <span>HTML element</span> with [[localname]]
+    <var>other tag name</var>:
 
     <ol>
       <li>Let <var>children</var> be the [[children]] of <var>node</var>.
@@ -3438,14 +3349,17 @@
       <li>Remove <var>node</var>, <span>preserving its descendants</span>.
 
       <li><span>Wrap</span> <var>children</var>, with <span>sibling
-      criteria</span> matching any [[ol]] and <span>new parent
+      criteria</span> matching any <span>HTML element</span> with [[localname]]
+      <var>tag name</var> and <span>new parent
       instructions</span> returning the result of calling <code
       data-anolis-spec=domcore
-      title=dom-Document-createElement>createElement("ol")</code> on the
-      [[contextobject]].  Let <var>node</var> be the result.
-
-      <li>Prepend the [[ul]] [[descendants]] of <var>node</var> (if any) to
-      <var>node list</var>.
+      title=dom-Document-createElement>createElement(<var>tag
+      name</var>)</code> on the [[contextobject]].  Let <var>node</var> be the
+      result.
+
+      <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.
 
@@ -3480,28 +3394,33 @@
     <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 a [[ul]]:
+    <li>If <var>node</var> is the [[child]] of an <span>HTML element</span>
+    with [[localname]] <var>other tag name</var>:
 
     <ol>
       <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 [[ol]],
+      <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 <code data-anolis-spec=domcore
-      title=dom-Document-createElement>createElement("ol")</code> on the
-      [[contextobject]].
-
-      <li>Prepend the [[ul]] [[descendants]] of <var>node</var> (if any) to
-      <var>node list</var>.
+      title=dom-Document-createElement>createElement(<var>tag
+      name</var>)</code> on the [[contextobject]].
+
+      <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 an [[ol]] or the [[child]] of an [[ol]], prepend
-    the [[ul]] [[descendants]] of <var>node</var> (if any) to <var>node
-    list</var> and continue from the beginning of this loop.
+    <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 the <span>sibling criteria</span>
@@ -3511,34 +3430,147 @@
     [[contextobject]].  Let <var>node</var> be the result.
 
     <li><span>Wrap</span> the one-[[node]] list consisting of <var>node</var>,
-    with the <span>sibling criteria</span> matching any [[ol]], and the
-    <span>new parent instructions</span> being the following:
+    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>indentation element</span>, or the [[previoussibling]] of the
-      [[parent]] of <var>node</var> is not an <span>editable</span> [[ol]],
-      call <code data-anolis-spec=domcore
-      title=dom-Document-createElement>createElement("ol")</code> on the
-      [[contextobject]] and return the result.  Otherwise:
-
-      <li>Let <var>ol</var> be the [[previoussibling]] of the [[parent]] of
+      [[parent]] of <var>node</var> 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 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>ol</var>'s last [[child]].
-
-      <li>If <var>ol</var>'s last [[child]] is not an <span>editable</span>
-      [[ol]], call <code data-anolis-spec=domcore
-      title=dom-Document-createElement>createElement("ol")</code> on the
-      [[contextobject]], and append the result as the last [[child]] of
-      <var>ol</var>.
-
-      <li>Return the last [[child]] of <var>ol</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>.
+
+      <li>Return the last [[child]] of <var>list</var>.
     </ol>
   </ol>
 </ol>
 
 
+<h3><dfn>The <code title>indent</code> command</dfn></h3>
+<!--
+IE9: Outputs <blockquote style="margin-right: 0px" dir="ltr">, or when
+  surrounding RTL blocks, <blockquote style="margin-left: 0px" dir="rtl">.  The
+  direction seems to go by the end of the selection.  The presence of the dir
+  attribute means that any contents that were inheriting a different dir from
+  an ancestor get their direction changed as a side effect, but if they
+  actually have the opposite dir specified, they won't appear to be indented.
+  It doesn't reset top or bottom margins on the blockquote, so it adds them.
+  If it's not wrapping a block element, like if it's only wrapping up until a
+  <br>, it adds a <p>.
+Firefox 4.0: In styleWithCSS mode, adds style="margin-left: 40px" to the
+  appropriate block container (or margin-right if it's RTL).  If there's no
+  appropriate block container, adds a div.  If multiple blocks are affected, it
+  goes by the direction of the block whose style it's changing, which winds up
+  being wrong for descendants with different direction.  In non-styleWithCSS
+  mode, uses <blockquote>, so it indents on both sides and also adds top/bottom
+  margins.
+Chrome 12 dev: Outputs <blockquote class="webkit-indent-blockquote"
+  style="margin: 0 0 0 40px; border: none; padding: 0px"> in both modes for
+  both LTR and RTL (which is broken for RTL, since it indents only on the
+  left).
+Opera 11.00: Outputs <blockquote>, so it indents on both sides and on the
+  top/bottom.
+
+For repeated indentation, everyone except Opera that outputs <blockquote>s just
+puts them at the outermost possible location, which works well.  Opera puts
+them in the innermost position, which is broken, because it will even put them
+inside <p> (which will not round-trip through text/html serialization).
+
+Gecko in CSS mode messes up by adding margins even to things like <blockquote>
+that already have margins from CSS rules, instead of nesting a div, so it
+doesn't actually increase the indentation.  However, if an element has an
+explicit left margin (assuming LTR), it will increase the margin to 80px, so it
+works with WebKit's blockquotes.
+
+
+We have two strategies for handling directionality: always indent on both sides
+(Firefox non-CSS, Opera) or try to figure out heuristically which side we want
+(IE, Firefox CSS).  The latter approach is only possible by adding extra markup
+and complexity, so for now we'll take the easy way out and go with just
+indenting on both sides.
+
+
+This reasoning doesn't discuss lists.  For research on lists, see the comment
+for insertOrderedList.  List handling is more complicated and I wound up
+differing from all browsers in lots of ways.
+-->
+
+<p><span>Action</span>:
+
+<p class=XXX>Handle corner cases: endpoints are detached, documents, document
+fragments, html/body, head or things in head . . .
+
+<ol>
+  <li>Let <var>items</var> be a list of all [[li]]s that are
+  [[ancestorcontainers]] of the <span>active range</span>'s [[rangestart]]
+  and/or [[rangeend]] [[bpnode]].
+
+  <li>For each <var>item</var> in <var>items</var>, <span>normalize
+  sublists</span> of <var>item</var>.
+  <!-- This overnormalizes, but it seems like the simplest solution for now.
+  -->
+
+  <li><span>Block-extend</span> the <span>active range</span>, and let <var>new
+  range</var> be the result.
+
+  <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>,
+  if <var>node</var> is <span>editable</span> and can be the [[child]] of a
+  [[div]] or [[ol]] or [[ul]] and if no [[ancestor]] of <var>node</var> is in
+  <var>node list</var>, append <var>node</var> to <var>node list</var>.
+
+  <li>If the first member of <var>node list</var> is an [[li]] whose [[parent]]
+  is an [[ol]] or [[ul]], and its [[previoussibling]] is an [[li]] as well,
+  <span>normalize sublists</span> of its [[previoussibling]].
+  <!-- Otherwise the last child of the previous sibling might be a list, which
+  the li wouldn't get appended to. -->
+
+  <li>While <var>node list</var> is not empty:
+
+  <ol>
+    <li>Let <var>sublist</var> be a list of [[nodes]], initially empty.
+
+    <li>Remove the first member of <var>node list</var> and append it to
+    <var>sublist</var>.
+
+    <li>While the first member of <var>node list</var> is the [[nextsibling]]
+    of the last member of <var>sublist</var>, remove the first member of
+    <var>node list</var> and append it to <var>sublist</var>.
+
+    <li><span>Indent</span> <var>sublist</var>.
+  </ol>
+</ol>
+
+
+<h3><dfn>The <code title>insertOrderedList</code> command</dfn></h3>
+
+<p><span>Action</span>: <span>Toggle lists</span> with <var>tag name</var>
+"ol".
+
+
+<h3><dfn>The <code title>insertUnorderedList</code> command</dfn></h3>
+
+<p><span>Action</span>: <span>Toggle lists</span> with <var>tag name</var>
+"ul".
+
+
 <h3><dfn>The <code title>outdent</code> command</dfn></h3>
 
 <p><span>Action</span>: