More list stuff, but I'm far from done
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Tue, 03 May 2011 15:56:36 -0600
changeset 85 d94c0062e53c
parent 84 e034dbb5e973
child 86 667696ef2073
More list stuff, but I'm far from done
autoimplementation.html
editcommands.html
implementation.js
notes.txt
preprocess
source.html
--- a/autoimplementation.html	Tue May 03 12:28:26 2011 -0600
+++ b/autoimplementation.html	Tue May 03 15:56:36 2011 -0600
@@ -532,6 +532,17 @@
 		// different levels of indentation, only the least indented lines in
 		// the selection will be indented."  Let's test that.
 		'<blockquote>f[oo<blockquote>b]ar</blockquote></blockquote><p>extra',
+
+		// Lists!
+		'<ol><li>foo<li>[bar]<li>baz</ol>',
+		'<ol><li>foo</ol>[bar]',
+		'<ol><li>[foo]<br>bar<li>baz</ol>',
+		'<ol><li>foo<br>[bar]<li>baz</ol>',
+		'<ol><li>foo<ol><li>[bar]<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<ul><li>[bar]<li>baz</ul><li>quz</ol>',
+		'<ol><li>foo</li><ol><li>[bar]<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo</li><ul><li>[bar]<li>baz</ul><li>quz</ol>',
+		'<ol><li>foo<li>[bar]<ol><li>baz</ol><li>quz</ol>',
 	],
 	inserthorizontalrule: [
 		'foo[]bar',
--- a/editcommands.html	Tue May 03 12:28:26 2011 -0600
+++ b/editcommands.html	Tue May 03 15:56:36 2011 -0600
@@ -1881,7 +1881,7 @@
 
 <dd><strong>Action</strong>:
 
-<p class=XXX>Does not handle lists at all (this is item #1 on my to-do list).
+<p class=XXX>List support is preliminary &ndash; I'm working on it right now.
 
 <p class=XXX>Handle corner cases: endpoints are detached, documents, document
 fragments, html/body, head or things in head . . .
@@ -1917,8 +1917,8 @@
 
   <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 blockquote element"><a href=http://www.whatwg.org/html/#the-blockquote-element>blockquote</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>.
+  <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><a href=#indent>Indent</a> each member of <var title="">node list</var>.
 </ol>
@@ -1926,7 +1926,55 @@
 <p>To <dfn id=indent>indent</dfn> a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <var title="">node</var>:
 
 <ol>
-  <li>If the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">node</var> is an <a href=#html-element>HTML
+  <li>If <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> 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>:
+
+  <ol>
+    <li>Let <var title="">tag</var> be the <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> 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>If the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">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="">tag</var>, append <var title="">node</var> as
+    the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of 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>, <a href=#preserving-ranges>preserving
+    ranges</a>.  Then abort these steps.
+
+    <li>If the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>, and the
+    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 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 <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</var>, append <var title="">node</var> as the last
+    <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of
+    <var title="">node</var>, <a href=#preserving-ranges>preserving ranges</a>.  Then abort these steps.
+
+    <li>If the <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code> of <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="">tag</var>, insert <var title="">node</var> as
+    the first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of its <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>, <a href=#preserving-ranges>preserving ranges</a>.
+    Then abort these steps.
+
+    <li>If the <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code> of <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>, and the first
+    <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of its <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=#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</var>, insert <var title="">node</var> as the first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>
+    of the first <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of the <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code> of <var title="">node</var>,
+    <a href=#preserving-ranges>preserving ranges</a>.  Then abort these steps.
+
+    <li>Let <var title="">new parent</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement(<var title="">tag</var>)</a></code> on
+    the <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">node</var>.
+
+    <li>If the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">node</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>, append
+    <var title="">new parent</var> as the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of
+    <var title="">node</var>.
+    <!-- This matches Opera 11.10.  IE9, Firefox 4.0, and Chrome 12 dev all add
+    the new list element as a child of the parent list unconditionally.
+    There's no visible difference, but Opera's version is conforming (and makes
+    more semantic sense). -->
+
+    <li>Otherwise, insert <var title="">new parent</var> into the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of
+    <var title="">node</var> immediately before <var title="">node</var>.
+
+    <li>Append <var title="">node</var> as the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">new parent</var>,
+    <a href=#preserving-ranges>preserving ranges</a>.
+
+    <li>Abort these steps.
+  </ol>
+
+  <li>If the <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> of <var title="">node</var> is an <a href=#indentation-element>indentation
   element</a>; its "display" property computes to "block"; its
   "margin-left" and "margin-right" properties compute to "40px"; and its
   "margin-top" and "margin-bottom" properties compute to "0"; then append
@@ -2117,53 +2165,106 @@
 
 * In an existing ordered list equivalent to <ol><li>foo<li>bar<li>baz</ol>quz:
   * Select "bar", do "ol":
-    * Word/OO: Remove indent, change "3" to "2".
-    * Browsers: Remove indent, change "3" to "1".
-    * Correct behavior: Unclear.
+    * Word/OO: Remove indent and number "2", change "3" to "2".
+    * Browsers: Remove indent and number "2", change "3" to "1".
+    * Spec: Same as browsers.
   * Select "bar", do "ul":
     * Word: Leave indent the same, change "2" to a bullet, change "3" to "2".
     * OO: Increase indent, change "2" to a bullet, change "3" to "2".
     * IE: Change all numbers to bullets.
     * Firefox/Chrome/Opera: Leave indent the same, change "2" to a bullet, change "3" to "1".
-    * Correct behavior: Either Word, or Firefox/Chrome/Opera.  Unclear.
+    * Spec: Same as Firefox/Chrome/Opera.
   * Select "bar", do "indent":
     * Word/OO'/Browsers: Increase indent, change "2" to "a", change "3" to "2".
     * OO: Increase indent, do not change any numbers.
-    * Correct behavior: OO'/Word/Browsers.
+    * Spec: Same as Word/OO'/Browsers.
   * Select "bar", do "outdent":
     * Word: Do nothing.
     * OO: Leave indent the same, de-indent "2" so it goes past the left margin (?!), do not change any numbers.
     * OO': Option grayed out.
     * Browsers: Remove indent and the number "2", change "3" to "1".
-    * Correct behavior: Probably should be the same as "ol".
+    * Spec: Same as browsers.
   * Select "quz", do "ol":
     * Word/OO/IE/Chrome: Add as fourth item to existing list, numbered "4".
     * Firefox/Opera: Create new list, number the item "1".
-    * Correct behavior: OO/Word/IE/Chrome.
+    * Spec: Same as OO/Word/IE/Chrome.
+* In an existing ordered list equivalent to <ol><li>foo<br>bar<li>baz</ol>:
+  * Select "foo", do "ol":
+    * Word/OO/IE/Chrome/Opera: Remove indent from both "foo" and "bar", change "2" -> "1".
+    * Firefox: Increase indent for "foo" only, add additional "a" marker after "1" and before "foo".
+    * Spec: Same as Word/OO/IE/Chrome/Opera.
+  * Select "foo", do "ul":
+    * Word/Opera: Change "1" -> bullet, "2" -> "1".
+    * OO: Increase indent for both "foo" and "bar", change "1" -> bullet, "2" -> "1".
+    * IE: Change all numbers to bullets.
+    * Firefox: Increase indent for "foo" only, add additional bullet marker after "1" and before "foo".
+    * Chrome: Remove indent from "bar", change "1" -> bullet, "2" -> "1".
+    * Spec: Same as Word/Opera.
+  * Select "foo", do "indent":
+    * Word: Increase indent for whole list.
+    * OO: Increase indent for both "foo" and "bar".
+    * OO': Increase indent for "foo", change "1" -> "a".
+    * IE/Firefox non-CSS/Opera: Increase indent for both "foo" and "bar", change "1" -> "a", "2" -> "1".
+    * Firefox CSS: Increase indent for "foo" only (<div style="margin-left: 40px">).
+    * Chrome: Increase indent for "foo" only, add "a" before "foo", move "1" to be before "bar".
+    * Spec: Same as IE/Firefox non-CSS/Opera.
+  * Select "foo", do "outdent":
+    * Word: Decrease indent for whole list, so it goes past the left margin.
+    * OO: Decrease indent for "bar" and "1." (so "1." goes past the left margin), but not "foo".
+    * OO': Option grayed out.
+    * IE/Chrome/Opera: Remove indent from both "foo" and "bar", remove "1", change "2" -> "1".
+    * Firefox: Do nothing.
+    * Spec: Same as IE/Chrome/Opera.
+  * Select "bar", do "ol":
+    * Word/OO/IE/Chrome/Opera: Remove indent from both "foo" and "bar", change "2" -> "1".
+    * Firefox: Increase indent for "bar" only, add "a" marker before it.
+    * Spec: Same as Word/OO/IE/Chrome/Opera.
+  * Select "bar", do "ul":
+    * Word/Opera: Change "1" -> bullet, "2" -> "1".
+    * OO: Increase indent for both "foo" and "bar", change "1" -> bullet, "2" -> "1".
+    * IE: Change all numbers to bullets.
+    * Firefox: Increase indent for "bar" only, add bullet marker before it.
+    * Chrome: Remove indent from "foo", change "1" -> bullet and move it before "bar", change "2" -> "1".
+    * Spec: Same as Word/Opera.
+  * Select "bar", do "indent":
+    * Word: Increase indent for whole list.
+    * OO: Increase indent for both "foo" and "bar".
+    * OO': Increase indent for "foo", change "1" -> "a".
+    * IE/Firefox non-CSS/Opera: Increase indent for both "foo" and "bar", change "1" -> "a", "2" -> "1".
+    * Firefox CSS: Increase indent for "bar" only (<div style="margin-left: 40px">).
+    * Chrome: Increase indent for "bar" only, add "a" before "bar", move "bar" above "foo" (?!).
+    * Spec: Same as IE/Firefox non-CSS/Opera.
+  * Select "bar", do "outdent":
+    * Word: Decrease indent for whole list, so it goes past the left margin.
+    * OO: Decrease indent for "bar" and "1." (so "1." goes past the left margin), but not "foo".
+    * OO': Option grayed out.
+    * IE/Chrome/Opera: Remove indent from both "foo" and "bar", remove "1", change "2" -> "1".
+    * Firefox: Do nothing.
+    * Spec: Same as IE/Chrome/Opera.
 * In an existing nested ordered list equivalent to <ol><li>foo<ol><li>bar<li>baz</ol><li>quz</ol>:
   * Select "bar", do "ol":
     * Word/IE/Firefox: Decrease indent, remove "a" ("bar" is aligned with "foo" with no marker of its own), change "b" -> "a".
     * OO: Remove all indent, change "b" -> "a".
     * Chrome: Decrease indent, change "a" -> "2", "b" -> "a", "2" -> "3".
     * Opera: Decrease indent, change "a" -> "2", "b" -> "a", "2" -> "4", insert extra "3" list marker before new "a".
-    * Correct behavior: Either Word/IE/Firefox or Chrome.  Unclear.
+    * Spec: Same as Chrome.
   * Select "bar", do "ul":
     * Word/Firefox/Chrome: Change "a" -> bullet, "b" -> "a".
     * OO: Increase indent, change "a" -> bullet, "b" -> "a".
     * IE: Change "a" and "b" to bullets.
     * Opera: Change "a" -> bullet, "b" -> "a", "2" -> "4", insert extra list markers "2" and "3" before new bullet and "a".
-    * Correct behavior: Presumably Word/Firefox/Chrome.
+    * Spec: Same as Word/Firefox/Chrome.
   * Select "bar", do "indent":
     * Word/OO'/IE: Increase indent, change "a" -> "i", leave "b" alone.
     * OO: Increase indent, do not change numbers.
     * Firefox/Chrome/Opera: Increase indent, change "a" -> "i", "b" -> "a".
-    * Correct behavior: Either OO'/Word/IE, or Firefox/Chrome/Opera.  Unclear.
+    * Spec: Same as Firefox/Chrome/Opera.
   * Select "bar", do "outdent":
     * Word/OO'/IE/Chrome: Decrease indent, change "a" -> "2", "b" -> "a", "2" -> "3".
     * OO: Leave indent the same, de-indent "a" so it goes past the left margin (?!).
     * Firefox: Decrease indent, remove "a" ("bar" is aligned with "foo" with no marker of its own), change "b" -> "a".
     * Opera: Decrease indent, change "a" -> "2", "b" -> "a", "2" -> "4", insert extra list marker "3" before new "a".
-    * Correct behavior: Probably should be the same as "ol".
+    * Spec: Same as Word/OO'/IE/Chrome.
 * In existing nested lists equivalent to <ol><li>foo<ul><li>bar<li>baz</ul><li>quz</ol>:
   * Select "bar", do "ol":
     * Word: Change all bullets to numbers.  (Not letters, even though indented!)
@@ -2171,32 +2272,65 @@
     * IE: Change all bullets to letters.
     * Firefox/Chrome: Change first bullet to "a".
     * Opera: Change first bullet -> "a", "2" -> "4", insert extra list markers "2" and "3" before new "a" and bullet.
-    * Correct behavior: Presumably Firefox/Chrome.
+    * Spec: Same as Firefox/Chrome.
   * Select "bar", do "ul":
     * Word/IE/Firefox: Decrease indent, remove first bullet ("bar" is aligned with "foo" with no marker of its own).
     * OO: Remove all indent, remove first bullet, leave all else the same.
     * Chrome: Decrease indent, change first bullet -> "2", "2" -> "3".
     * Opera: Decrease indent, change first bullet -> "2", "2" -> "4", insert extra list marker "3" before old bullet.
-    * Correct behavior: Either Word/IE/Firefox or Chrome.  Unclear.
+    * Spec: Same as Chrome.
   * Select "bar", do "indent":
     * Word: Increase indent, change first bullet to "i" (?!).
     * OO/OO'/Firefox/Chrome/Opera: Increase indent.
     * IE: Increase indent, change "2" -> "3" (?!?!).  (I don't see from the markup why the 2 actually changes to a 3.  The markup seems to be as other browsers.)
-    * Correct behavior: OO/OO'/Firefox/Chrome/Opera.
+    * Spec: Same as OO/OO'/Firefox/Chrome/Opera.
   * Select "bar", do "outdent":
     * Word/IE/Chrome: Decrease indent, change first bullet -> "2", "2" -> "3".
     * OO: Usual crazy stuff, move bullet left but leave text alone.
     * OO': Option grayed out.  (Interesting.)
     * Firefox: Decrease indent, remove first bullet ("bar" is aligned with "foo" with no marker of its own).
     * Opera: Decrease indent, change first bullet -> "2", "2" -> "4", insert extra list marker "3" before old bullet.
-    * Correct behavior: Either Word/IE/Chrome or Firefox.  Unclear.
+    * Spec: Same as Word/IE/Chrome.
+* In an existing nested ordered list equivalent to <ol><li>foo<li>bar<ol><li>baz</ol><li>quz</ol>:
+  * Select "bar", do "ol":
+    * Word/OO: Remove indent and "2", change "3" -> "2".
+    * IE/Chrome/Opera: Remove indent and "2", decrease indent of "baz", change "2" and "3" -> "1".
+    * Firefox: Increase indent, add extra "a" marker between "2" and "bar".
+    * Spec: Different from all of them: remove indent and "2", change "3" -> "1".
+  * Select "bar", do "ul":
+    * Word: Change "2" -> bullet.
+    * OO: Increase indent, change "2" -> bullet, "3" -> "2".
+    * IE: Change "1", "2", "3" -> bullets (and "a" to "1").
+    * Firefox: Increase indent, add extra bullet marker between "2" and "bar".
+    * Chrome: Decrease indent of "baz", change "2" -> bullet, "a" and "3" -> "1".
+    * Opera: Change "2" -> bullet, "a" and "3" -> "1".
+    * Spec: Different from all of them: change "2" -> bullet, "3" -> "1".
+  * Select "bar", do "indent":
+    * Word/OO': Increase indent, change "2" -> "a", "a" -> "b", "3" -> "2".
+    * OO: Increase indent (double amount, past "baz").
+    * Firefox non-CSS/Opera: Increase indent of both "bar" and "baz", change "2" -> "a", "a" -> "i", "3" -> "2".
+    * Firefox CSS: Increase indent.
+    * Chrome: Increase indent, add "a" marker before "bar", move "2" marker to before the "a" marker of "baz".
+    * Spec: Same as Word/OO'.
+  * Select "bar", do "outdent":
+    * Word/Firefox: Do nothing.
+    * OO: Decrease indent on "2", leave "bar" alone.
+    * OO': Option grayed out.
+    * IE: Decrease indent of "baz", change "2" and "3" -> "1", "a" -> "2".
+    * Chrome/Opera: Decrease indent of "bar" and "baz", remove "2", change "a" and "3" -> "1".
+    * Spec: Different from all of them: remove indent and "2", change "3" -> "1".
+* In an existing nested ordered list equivalent to <ol><li>foo<li>bar<ol><li>baz</ol>quz<li>qoz</ol>:
+  * Does not appear to be possible in Word or OO.
+  * Also might be impossible to actually make such a list using execCommand() in browsers.
+  * Suffice it to say that there's a lot of variation.
 
 Ignoring the conceptual model of HTML, which users won't understand, here's the
 conceptual model I've developed for lists: text is divided up into blocks.
 Each block has an indentation level and a list marker type.  The list marker
 type can be either nothing, ordered, or unordered.  A list block cannot have
 indentation level less than one.  Any given piece of text is part of only one
-block.
+block.  A block may be visually non-contiguous, such as if a single list block
+is interrupted by a further-indented block.
 
 To find the right number (or letter) for an ordered-list block, look at the
 immediately preceding block, but skip over any blocks of higher indentation
@@ -2214,35 +2348,41 @@
 
 What this means from an HTML perspective, roughly:
 
-* A block is basically a line of text, like a CSS line box.
+* A list block is the entire contents of an <li> element, ignoring any nested
+  list elements or indentation elements.  A non-list block is a line box.
 * Indentation level is equal to the number of ancestor elements that are either
   <li>s or indentation elements (blockquotes or indenting divs).
 * To find the list marker type, go to the first ancestor that's either an <li>
   or indentation element.
 * Correct numbering should automatically follow from the way <ol> works in HTML
   (which is one of the reasons I use this model).
-* An ol command in an ordered-list block decreases the indentation level by
-  one, and either merges with the previous block or adopts its list marker
-  type.  In an unordered-list block, it breaks up the parent <ul> and creates a
-  new one-element <ol>, or merges with the next or previous <ol> if any.  In a
-  non-list block, it creates a new <ol>, or merges with the next or previous
-  <ol> if any.  The ul command works similarly.
+* An ol command in an ordered-list block removes the surrounding <li>,
+  migrating its contents into the parent of the <ol>.  This splits up the <ol> if
+  it's not the first or last child, and wraps the contents in a new <li> if
+  necessary.  If there's another list or indentation element nested in the <li>
+  we're removing, it will get re-wrapped in a new <ol>, outside the
+  newly-created <li>, so that it maintains its indentation.  This might cause
+  the new <li> to wind up in multiple pieces, if the original block was not
+  contiguous, which means the non-contiguous block is split into several blocks
+  (with different numbers).
+* An ol command in an unordered-list block breaks up the parent <ul> and puts a
+  new <ol> in between the two pieces, moving the parent <li> into it.  If the
+  <li> was the first or last child, we merge with an existing adjacent <ol> if
+  possible.  All children stay as they are.
+* An ol command in a non-list block with indentation zero wraps it in a new
+  <ol><li>, or merges with an adjacent <ol> if possible.
+* An ol command in a non-list block with nonzero indentation converts the
+  parent to an <ol><li>, breaking it up if necessary.
+* The ul command works similarly to ol.
 * indent in a non-list block wraps in an indentation element.  In a list block,
-  it wraps the <li> in an extra <ol> or <ul> as appropriate.  (This often
-  creates non-conforming markup, like
-  <ol><li>foo</li><ol><li>bar</li></ol></ol>.)
+  it wraps the <li> in an extra <ol> or <ul> as appropriate.  With merging.
+  Whatever.  Let me just write the spec.
 * outdent in a non-list block strips an indentation element, if one is present.
   In a list block, it breaks apart the parent <ol> or <ul> and makes the
-  affected block a sibling in between the newly-split list elements.
-
-Problem: a block needs to be able to have multiple lines.  If it's a list
-block, this means it gets no extra markers, just one for the whole block.  This
-means it has to be possible to have non-contiguous blocks, for cases like
-<ol><li>foo<ol><li>bar</ol>baz</ol>.  We cannot simply consider "foo" and "baz"
-to be in separate blocks, because then baz has to have a list marker type of
-none, which will mess up subsequent list numbering and be indistinguishable
-from <ol><li>foo<ol><li>bar</ol></ol><blockquote>baz</blockquote>.  What's the
-expected behavior here?  Needs testing.
+  affected block a sibling in between the newly-split list elements.  Will
+  create new <li>s, etc. etc.
+
+Sheesh, lists are complicated.
 -->
 
 
--- a/implementation.js	Tue May 03 12:28:26 2011 -0600
+++ b/implementation.js	Tue May 03 15:56:36 2011 -0600
@@ -2127,8 +2127,8 @@
 		var nodeList = [];
 
 		// "For each node node contained in new range, if node is editable and
-		// can be the child of a blockquote and if no ancestor of node is in
-		// node list, append node to node list."
+		// can be the child of a div or ol or ul and if no ancestor of node is
+		// in node list, append node to node list."
 		for (var node = newRange.startContainer; node != nextNodeDescendants(newRange.endContainer); node = nextNode(node)) {
 			if (!isContained(node, newRange) || !isEditable(node)) {
 				continue;
@@ -2498,13 +2498,85 @@
 }
 
 function indentNode(node) {
-	// "If the previousSibling of node is an HTML element; its
-	// "display" property computes to "block"; its "margin-left" and
-	// "margin-right" properties compute to "40px"; and its
-	// "margin-top" and "margin-bottom" properties compute to "0"; then
-	// append node as the last child of its previousSibling, preserving
-	// ranges, then abort these steps."
-	if (isHtmlElement(node.previousSibling)) {
+	// "If node is an li whose parent is an ol or ul:"
+	if (isHtmlElement(node)
+	&& node.tagName == "LI"
+	&& isHtmlElement(node.parentNode)
+	&& (node.parentNode.tagName == "OL" || node.parentNode.tagName == "UL")) {
+		// "Let tag be the local name of the parent of node."
+		var tag = node.parentNode.tagName;
+
+		// "If the previousSibling of node is an HTML element with local name
+		// tag, append node as the last child of its previousSibling,
+		// preserving ranges. Then abort these steps."
+		if (isHtmlElement(node.previousSibling)
+		&& node.previousSibling.tagName == tag) {
+			movePreservingRanges(node, node.previousSibling, getNodeLength(node.previousSibling));
+			return;
+		}
+
+		// "If the previousSibling of node is an li, and the last child of its
+		// previousSibling is an HTML element with local name tag, append node
+		// as the last child of the last child of the previousSibling of node,
+		// preserving ranges. Then abort these steps."
+		if (isHtmlElement(node.previousSibling)
+		&& node.previousSibling.tagName == "LI"
+		&& isHtmlElement(node.previousSibling.lastChild)
+		&& node.previousSibling.lastChild.tagName == tag) {
+			movePreservingRanges(node, node.previousSibling.lastChild, getNodeLength(node.previousSibling.lastChild));
+			return;
+		}
+
+		// "If the nextSibling of node is an HTML element with local name tag,
+		// insert node as the first child of its nextSibling, preserving
+		// ranges. Then abort these steps."
+		if (isHtmlElement(node.nextSibling)
+		&& node.nextSibling.tagName == tag) {
+			movePreservingRanges(node, node.nextSibling, 0);
+			return;
+		}
+
+		// "If the nextSibling of node is an li, and the first child of its
+		// nextSibling is an HTML element with local name tag, insert node as
+		// the first child of the first child of the nextSibling of node,
+		// preserving ranges. Then abort these steps."
+		if (isHtmlElement(node.nextSibling)
+		&& node.nextSibling.tagName == "LI"
+		&& isHtmlElement(node.nextSibling.firstChild)
+		&& node.nextSibling.firstChild.tagName == tag) {
+			movePreservingRanges(node, node.nextSibling.firstChild, 0);
+			return;
+		}
+
+		// "Let new parent be the result of calling createElement(tag) on the
+		// ownerDocument of node."
+		var newParent = node.ownerDocument.createElement(tag);
+
+		// "If the previousSibling of node is an li, append new parent as the
+		// last child of the previousSibling of node."
+		if (isHtmlElement(node.previousSibling)
+		&& node.previousSibling.tagName == "LI") {
+			node.previousSibling.appendChild(newParent);
+
+		// "Otherwise, insert new parent into the parent of node immediately
+		// before node."
+		} else {
+			node.parentNode.insertBefore(newParent, node);
+		}
+
+		// "Append node as the last child of new parent, preserving ranges."
+		movePreservingRanges(node, newParent, 0);
+
+		// "Abort these steps."
+		return;
+	}
+
+	// "If the previousSibling of node is an indentation element; its "display"
+	// property computes to "block"; its "margin-left" and "margin-right"
+	// properties compute to "40px"; and its "margin-top" and "margin-bottom"
+	// properties compute to "0"; then append node as the last child of its
+	// previousSibling, preserving ranges, then abort these steps."
+	if (isIndentationElement(node.previousSibling)) {
 		var style = getComputedStyle(node.previousSibling);
 		if (style.display == "block"
 		&& style.marginLeft == "40px"
--- a/notes.txt	Tue May 03 12:28:26 2011 -0600
+++ b/notes.txt	Tue May 03 15:56:36 2011 -0600
@@ -1,3 +1,5 @@
+== Research on execCommand() users ==
+
 vBulletin (http://www.vbulletin.com/forum/clientscript/vbulletin_textedit.js):
 
 * Lots and lots and lots of browser sniffing.  Only appears to support IE,
@@ -66,3 +68,34 @@
   was build to replace the browsers default formatting logic for execCommand
   due to it's inconsistant and buggy behavior."  Not much more to see here, it
   seems.
+
+== List requirements ==
+* <ol><li>foo<li>[bar]<li>baz</ol>
+  * insertOrderedList: <ol><li>foo</ol>bar<ol><li>baz</ol>
+  * insertUnorderedList: <ol><li>foo</ol><ul><li>bar</ul><ol><li>baz</ol>
+  * indent: <ol><li>foo<ol><li>bar</ol><li>baz</ol>
+  * outdent: <ol><li>foo</ol>bar<ol><li>baz</ol>
+* <ol><li>foo</ol>[bar]
+  * insertOrderedList: <ol><li>foo<li>bar</ol>
+* <ol><li>[foo]<br>bar<li>baz</ol>
+  * insertOrderedList: foo<br>bar<ol><li>baz</ol>
+  * insertUnorderedList: <ul><li>foo<br>bar</ul><ol><li>baz</ol>
+  * indent: <ol><ol><li>foo<br>bar</ol><li>baz</ol>
+  * outdent: foo<br>bar<ol><li>baz</ol>
+* <ol><li>foo<br>[bar]<li>baz</ol>
+  * Same behavior as last case.
+* <ol><li>foo<ol><li>[bar]<li>baz</ol><li>quz</ol>
+  * insertOrderedList: <ol><li>foo<li>bar<ol><li>baz</ol><li>quz</ol>
+  * insertUnorderedList: <ol><li>foo<ul><li>bar</ul><ol><li>baz</ol><li>quz</ol>
+  * indent: <ol><li>foo<ol><ol><li>bar</ol><li>baz</ol><li>quz</ol>
+  * outdent: <ol><li>foo<li>bar<ol><li>baz</ol><li>quz</ol>
+* <ol><li>foo<ul><li>[bar]<li>baz</ul><li>quz</ol>
+  * insertOrderedList: <ol><li>foo<ol><li>bar</ol><ul><li>baz</ul><li>quz</ol>
+  * insertUnorderedList: <ol><li>foo<li>bar<ul><li>baz</ul><li>quz</ol>
+  * indent: <ol><li>foo<ul><ul><li>bar</ul><li>baz</ul><li>quz</ol>
+  * outdent: <ol><li>foo<li>bar<ul><li>baz</ul><li>quz</ol>
+* <ol><li>foo<li>[bar]<ol><li>baz</ol><li>quz</ol>
+  * insertOrderedList: <ol><li>foo</ol>bar<ol><ol><li>baz</ol><li>quz</ol>
+  * insertUnorderedList: <ol><li>foo</ol><ul><li>bar</ul><ol><ol><li>baz</ol><li>quz</ol>
+  * indent: <ol><li>foo<ol><li>bar<ol><li>baz</ol><li>quz</ol>
+  * outdent: <ol><li>foo</ol>bar<ol><ol><li>baz</ol><li>quz</ol>
--- a/preprocess	Tue May 03 12:28:26 2011 -0600
+++ b/preprocess	Tue May 03 15:56:36 2011 -0600
@@ -39,11 +39,13 @@
     'href': '<code data-anolis-spec=html title=attr-hyperlink-href>href</code>',
     'i': '<code data-anolis-spec=html title="the i element">i</code>',
     'index': '<span data-anolis-spec=domrange title=concept-indexof>index</span>',
+    'li': '<code data-anolis-spec=html title="the li element">li</code>',
     'localname': '<span data-anolis-spec=domcore title=concept-element-local-name>local name</span>',
     'namespace': '<span data-anolis-spec=domcore title=concept-element-namespace>namespace</span>',
     'nextsibling': '<code data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code>',
     'node': '<span data-anolis-spec=domcore title=concept-node>node</span>',
     'nodelength': '<span data-anolis-spec=domrange title=concept-node-length>length</span>',
+    'ol': '<code data-anolis-spec=html title="the ol element">ol</code>',
     'ownerdocument': '<code data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code>',
     'parent': '<span data-anolis-spec=domcore title=concept-tree-parent>parent</span>',
     'partiallycontained': '<span data-anolis-spec=domrange>partially contained</span>',
@@ -68,6 +70,7 @@
     'text': '<code data-anolis-spec=domcore>Text</code>',
     'treeorder': '<span data-anolis-spec=domcore>tree order</span>',
     'u': '<code data-anolis-spec=html title="the u element">u</code>',
+    'ul': '<code data-anolis-spec=html title="the ul element">ul</code>',
 }
 
 s = open("source.html", "r").read()
--- a/source.html	Tue May 03 12:28:26 2011 -0600
+++ b/source.html	Tue May 03 15:56:36 2011 -0600
@@ -1899,7 +1899,7 @@
 
 <dd><strong>Action</strong>:
 
-<p class=XXX>Does not handle lists at all (this is item #1 on my to-do list).
+<p class=XXX>List support is preliminary &ndash; I'm working on it right now.
 
 <p class=XXX>Handle corner cases: endpoints are detached, documents, document
 fragments, html/body, head or things in head . . .
@@ -1935,8 +1935,8 @@
 
   <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
-  [[blockquote]] and if no [[ancestor]] of <var>node</var> is in <var>node
-  list</var>, append <var>node</var> to <var>node list</var>.
+  [[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><span>Indent</span> each member of <var>node list</var>.
 </ol>
@@ -1944,7 +1944,57 @@
 <p>To <dfn>indent</dfn> a [[node]] <var>node</var>:
 
 <ol>
-  <li>If the [[previoussibling]] of <var>node</var> is an <span>HTML
+  <li>If <var>node</var> is an [[li]] whose [[parent]] is an [[ol]] or [[ul]]:
+
+  <ol>
+    <li>Let <var>tag</var> be the [[localname]] of the [[parent]] of
+    <var>node</var>.
+
+    <li>If the [[previoussibling]] of <var>node</var> is an <span>HTML
+    element</span> with [[localname]] <var>tag</var>, append <var>node</var> as
+    the last [[child]] of its [[previoussibling]], <span>preserving
+    ranges</span>.  Then abort these steps.
+
+    <li>If the [[previoussibling]] of <var>node</var> is an [[li]], and the
+    last [[child]] of its [[previoussibling]] is an <span>HTML element</span>
+    with [[localname]] <var>tag</var>, append <var>node</var> as the last
+    [[child]] of the last [[child]] of the [[previoussibling]] of
+    <var>node</var>, <span>preserving ranges</span>.  Then abort these steps.
+
+    <li>If the [[nextsibling]] of <var>node</var> is an <span>HTML
+    element</span> with [[localname]] <var>tag</var>, insert <var>node</var> as
+    the first [[child]] of its [[nextsibling]], <span>preserving ranges</span>.
+    Then abort these steps.
+
+    <li>If the [[nextsibling]] of <var>node</var> is an [[li]], and the first
+    [[child]] of its [[nextsibling]] is an <span>HTML element</span> with
+    [[localname]] <var>tag</var>, insert <var>node</var> as the first [[child]]
+    of the first [[child]] of the [[nextsibling]] of <var>node</var>,
+    <span>preserving ranges</span>.  Then abort these steps.
+
+    <li>Let <var>new parent</var> be the result of calling <code
+    data-anolis-spec=domcore
+    title=dom-Document-createElement>createElement(<var>tag</var>)</code> on
+    the [[ownerdocument]] of <var>node</var>.
+
+    <li>If the [[previoussibling]] of <var>node</var> is an [[li]], append
+    <var>new parent</var> as the last [[child]] of the [[previoussibling]] of
+    <var>node</var>.
+    <!-- This matches Opera 11.10.  IE9, Firefox 4.0, and Chrome 12 dev all add
+    the new list element as a child of the parent list unconditionally.
+    There's no visible difference, but Opera's version is conforming (and makes
+    more semantic sense). -->
+
+    <li>Otherwise, insert <var>new parent</var> into the [[parent]] of
+    <var>node</var> immediately before <var>node</var>.
+
+    <li>Append <var>node</var> as the last [[child]] of <var>new parent</var>,
+    <span>preserving ranges</span>.
+
+    <li>Abort these steps.
+  </ol>
+
+  <li>If the [[previoussibling]] of <var>node</var> is an <span>indentation
   element</span>; its "display" property computes to "block"; its
   "margin-left" and "margin-right" properties compute to "40px"; and its
   "margin-top" and "margin-bottom" properties compute to "0"; then append
@@ -2156,53 +2206,106 @@
 
 * In an existing ordered list equivalent to <ol><li>foo<li>bar<li>baz</ol>quz:
   * Select "bar", do "ol":
-    * Word/OO: Remove indent, change "3" to "2".
-    * Browsers: Remove indent, change "3" to "1".
-    * Correct behavior: Unclear.
+    * Word/OO: Remove indent and number "2", change "3" to "2".
+    * Browsers: Remove indent and number "2", change "3" to "1".
+    * Spec: Same as browsers.
   * Select "bar", do "ul":
     * Word: Leave indent the same, change "2" to a bullet, change "3" to "2".
     * OO: Increase indent, change "2" to a bullet, change "3" to "2".
     * IE: Change all numbers to bullets.
     * Firefox/Chrome/Opera: Leave indent the same, change "2" to a bullet, change "3" to "1".
-    * Correct behavior: Either Word, or Firefox/Chrome/Opera.  Unclear.
+    * Spec: Same as Firefox/Chrome/Opera.
   * Select "bar", do "indent":
     * Word/OO'/Browsers: Increase indent, change "2" to "a", change "3" to "2".
     * OO: Increase indent, do not change any numbers.
-    * Correct behavior: OO'/Word/Browsers.
+    * Spec: Same as Word/OO'/Browsers.
   * Select "bar", do "outdent":
     * Word: Do nothing.
     * OO: Leave indent the same, de-indent "2" so it goes past the left margin (?!), do not change any numbers.
     * OO': Option grayed out.
     * Browsers: Remove indent and the number "2", change "3" to "1".
-    * Correct behavior: Probably should be the same as "ol".
+    * Spec: Same as browsers.
   * Select "quz", do "ol":
     * Word/OO/IE/Chrome: Add as fourth item to existing list, numbered "4".
     * Firefox/Opera: Create new list, number the item "1".
-    * Correct behavior: OO/Word/IE/Chrome.
+    * Spec: Same as OO/Word/IE/Chrome.
+* In an existing ordered list equivalent to <ol><li>foo<br>bar<li>baz</ol>:
+  * Select "foo", do "ol":
+    * Word/OO/IE/Chrome/Opera: Remove indent from both "foo" and "bar", change "2" -> "1".
+    * Firefox: Increase indent for "foo" only, add additional "a" marker after "1" and before "foo".
+    * Spec: Same as Word/OO/IE/Chrome/Opera.
+  * Select "foo", do "ul":
+    * Word/Opera: Change "1" -> bullet, "2" -> "1".
+    * OO: Increase indent for both "foo" and "bar", change "1" -> bullet, "2" -> "1".
+    * IE: Change all numbers to bullets.
+    * Firefox: Increase indent for "foo" only, add additional bullet marker after "1" and before "foo".
+    * Chrome: Remove indent from "bar", change "1" -> bullet, "2" -> "1".
+    * Spec: Same as Word/Opera.
+  * Select "foo", do "indent":
+    * Word: Increase indent for whole list.
+    * OO: Increase indent for both "foo" and "bar".
+    * OO': Increase indent for "foo", change "1" -> "a".
+    * IE/Firefox non-CSS/Opera: Increase indent for both "foo" and "bar", change "1" -> "a", "2" -> "1".
+    * Firefox CSS: Increase indent for "foo" only (<div style="margin-left: 40px">).
+    * Chrome: Increase indent for "foo" only, add "a" before "foo", move "1" to be before "bar".
+    * Spec: Same as IE/Firefox non-CSS/Opera.
+  * Select "foo", do "outdent":
+    * Word: Decrease indent for whole list, so it goes past the left margin.
+    * OO: Decrease indent for "bar" and "1." (so "1." goes past the left margin), but not "foo".
+    * OO': Option grayed out.
+    * IE/Chrome/Opera: Remove indent from both "foo" and "bar", remove "1", change "2" -> "1".
+    * Firefox: Do nothing.
+    * Spec: Same as IE/Chrome/Opera.
+  * Select "bar", do "ol":
+    * Word/OO/IE/Chrome/Opera: Remove indent from both "foo" and "bar", change "2" -> "1".
+    * Firefox: Increase indent for "bar" only, add "a" marker before it.
+    * Spec: Same as Word/OO/IE/Chrome/Opera.
+  * Select "bar", do "ul":
+    * Word/Opera: Change "1" -> bullet, "2" -> "1".
+    * OO: Increase indent for both "foo" and "bar", change "1" -> bullet, "2" -> "1".
+    * IE: Change all numbers to bullets.
+    * Firefox: Increase indent for "bar" only, add bullet marker before it.
+    * Chrome: Remove indent from "foo", change "1" -> bullet and move it before "bar", change "2" -> "1".
+    * Spec: Same as Word/Opera.
+  * Select "bar", do "indent":
+    * Word: Increase indent for whole list.
+    * OO: Increase indent for both "foo" and "bar".
+    * OO': Increase indent for "foo", change "1" -> "a".
+    * IE/Firefox non-CSS/Opera: Increase indent for both "foo" and "bar", change "1" -> "a", "2" -> "1".
+    * Firefox CSS: Increase indent for "bar" only (<div style="margin-left: 40px">).
+    * Chrome: Increase indent for "bar" only, add "a" before "bar", move "bar" above "foo" (?!).
+    * Spec: Same as IE/Firefox non-CSS/Opera.
+  * Select "bar", do "outdent":
+    * Word: Decrease indent for whole list, so it goes past the left margin.
+    * OO: Decrease indent for "bar" and "1." (so "1." goes past the left margin), but not "foo".
+    * OO': Option grayed out.
+    * IE/Chrome/Opera: Remove indent from both "foo" and "bar", remove "1", change "2" -> "1".
+    * Firefox: Do nothing.
+    * Spec: Same as IE/Chrome/Opera.
 * In an existing nested ordered list equivalent to <ol><li>foo<ol><li>bar<li>baz</ol><li>quz</ol>:
   * Select "bar", do "ol":
     * Word/IE/Firefox: Decrease indent, remove "a" ("bar" is aligned with "foo" with no marker of its own), change "b" -> "a".
     * OO: Remove all indent, change "b" -> "a".
     * Chrome: Decrease indent, change "a" -> "2", "b" -> "a", "2" -> "3".
     * Opera: Decrease indent, change "a" -> "2", "b" -> "a", "2" -> "4", insert extra "3" list marker before new "a".
-    * Correct behavior: Either Word/IE/Firefox or Chrome.  Unclear.
+    * Spec: Same as Chrome.
   * Select "bar", do "ul":
     * Word/Firefox/Chrome: Change "a" -> bullet, "b" -> "a".
     * OO: Increase indent, change "a" -> bullet, "b" -> "a".
     * IE: Change "a" and "b" to bullets.
     * Opera: Change "a" -> bullet, "b" -> "a", "2" -> "4", insert extra list markers "2" and "3" before new bullet and "a".
-    * Correct behavior: Presumably Word/Firefox/Chrome.
+    * Spec: Same as Word/Firefox/Chrome.
   * Select "bar", do "indent":
     * Word/OO'/IE: Increase indent, change "a" -> "i", leave "b" alone.
     * OO: Increase indent, do not change numbers.
     * Firefox/Chrome/Opera: Increase indent, change "a" -> "i", "b" -> "a".
-    * Correct behavior: Either OO'/Word/IE, or Firefox/Chrome/Opera.  Unclear.
+    * Spec: Same as Firefox/Chrome/Opera.
   * Select "bar", do "outdent":
     * Word/OO'/IE/Chrome: Decrease indent, change "a" -> "2", "b" -> "a", "2" -> "3".
     * OO: Leave indent the same, de-indent "a" so it goes past the left margin (?!).
     * Firefox: Decrease indent, remove "a" ("bar" is aligned with "foo" with no marker of its own), change "b" -> "a".
     * Opera: Decrease indent, change "a" -> "2", "b" -> "a", "2" -> "4", insert extra list marker "3" before new "a".
-    * Correct behavior: Probably should be the same as "ol".
+    * Spec: Same as Word/OO'/IE/Chrome.
 * In existing nested lists equivalent to <ol><li>foo<ul><li>bar<li>baz</ul><li>quz</ol>:
   * Select "bar", do "ol":
     * Word: Change all bullets to numbers.  (Not letters, even though indented!)
@@ -2210,32 +2313,65 @@
     * IE: Change all bullets to letters.
     * Firefox/Chrome: Change first bullet to "a".
     * Opera: Change first bullet -> "a", "2" -> "4", insert extra list markers "2" and "3" before new "a" and bullet.
-    * Correct behavior: Presumably Firefox/Chrome.
+    * Spec: Same as Firefox/Chrome.
   * Select "bar", do "ul":
     * Word/IE/Firefox: Decrease indent, remove first bullet ("bar" is aligned with "foo" with no marker of its own).
     * OO: Remove all indent, remove first bullet, leave all else the same.
     * Chrome: Decrease indent, change first bullet -> "2", "2" -> "3".
     * Opera: Decrease indent, change first bullet -> "2", "2" -> "4", insert extra list marker "3" before old bullet.
-    * Correct behavior: Either Word/IE/Firefox or Chrome.  Unclear.
+    * Spec: Same as Chrome.
   * Select "bar", do "indent":
     * Word: Increase indent, change first bullet to "i" (?!).
     * OO/OO'/Firefox/Chrome/Opera: Increase indent.
     * IE: Increase indent, change "2" -> "3" (?!?!).  (I don't see from the markup why the 2 actually changes to a 3.  The markup seems to be as other browsers.)
-    * Correct behavior: OO/OO'/Firefox/Chrome/Opera.
+    * Spec: Same as OO/OO'/Firefox/Chrome/Opera.
   * Select "bar", do "outdent":
     * Word/IE/Chrome: Decrease indent, change first bullet -> "2", "2" -> "3".
     * OO: Usual crazy stuff, move bullet left but leave text alone.
     * OO': Option grayed out.  (Interesting.)
     * Firefox: Decrease indent, remove first bullet ("bar" is aligned with "foo" with no marker of its own).
     * Opera: Decrease indent, change first bullet -> "2", "2" -> "4", insert extra list marker "3" before old bullet.
-    * Correct behavior: Either Word/IE/Chrome or Firefox.  Unclear.
+    * Spec: Same as Word/IE/Chrome.
+* In an existing nested ordered list equivalent to <ol><li>foo<li>bar<ol><li>baz</ol><li>quz</ol>:
+  * Select "bar", do "ol":
+    * Word/OO: Remove indent and "2", change "3" -> "2".
+    * IE/Chrome/Opera: Remove indent and "2", decrease indent of "baz", change "2" and "3" -> "1".
+    * Firefox: Increase indent, add extra "a" marker between "2" and "bar".
+    * Spec: Different from all of them: remove indent and "2", change "3" -> "1".
+  * Select "bar", do "ul":
+    * Word: Change "2" -> bullet.
+    * OO: Increase indent, change "2" -> bullet, "3" -> "2".
+    * IE: Change "1", "2", "3" -> bullets (and "a" to "1").
+    * Firefox: Increase indent, add extra bullet marker between "2" and "bar".
+    * Chrome: Decrease indent of "baz", change "2" -> bullet, "a" and "3" -> "1".
+    * Opera: Change "2" -> bullet, "a" and "3" -> "1".
+    * Spec: Different from all of them: change "2" -> bullet, "3" -> "1".
+  * Select "bar", do "indent":
+    * Word/OO': Increase indent, change "2" -> "a", "a" -> "b", "3" -> "2".
+    * OO: Increase indent (double amount, past "baz").
+    * Firefox non-CSS/Opera: Increase indent of both "bar" and "baz", change "2" -> "a", "a" -> "i", "3" -> "2".
+    * Firefox CSS: Increase indent.
+    * Chrome: Increase indent, add "a" marker before "bar", move "2" marker to before the "a" marker of "baz".
+    * Spec: Same as Word/OO'.
+  * Select "bar", do "outdent":
+    * Word/Firefox: Do nothing.
+    * OO: Decrease indent on "2", leave "bar" alone.
+    * OO': Option grayed out.
+    * IE: Decrease indent of "baz", change "2" and "3" -> "1", "a" -> "2".
+    * Chrome/Opera: Decrease indent of "bar" and "baz", remove "2", change "a" and "3" -> "1".
+    * Spec: Different from all of them: remove indent and "2", change "3" -> "1".
+* In an existing nested ordered list equivalent to <ol><li>foo<li>bar<ol><li>baz</ol>quz<li>qoz</ol>:
+  * Does not appear to be possible in Word or OO.
+  * Also might be impossible to actually make such a list using execCommand() in browsers.
+  * Suffice it to say that there's a lot of variation.
 
 Ignoring the conceptual model of HTML, which users won't understand, here's the
 conceptual model I've developed for lists: text is divided up into blocks.
 Each block has an indentation level and a list marker type.  The list marker
 type can be either nothing, ordered, or unordered.  A list block cannot have
 indentation level less than one.  Any given piece of text is part of only one
-block.
+block.  A block may be visually non-contiguous, such as if a single list block
+is interrupted by a further-indented block.
 
 To find the right number (or letter) for an ordered-list block, look at the
 immediately preceding block, but skip over any blocks of higher indentation
@@ -2253,35 +2389,41 @@
 
 What this means from an HTML perspective, roughly:
 
-* A block is basically a line of text, like a CSS line box.
+* A list block is the entire contents of an <li> element, ignoring any nested
+  list elements or indentation elements.  A non-list block is a line box.
 * Indentation level is equal to the number of ancestor elements that are either
   <li>s or indentation elements (blockquotes or indenting divs).
 * To find the list marker type, go to the first ancestor that's either an <li>
   or indentation element.
 * Correct numbering should automatically follow from the way <ol> works in HTML
   (which is one of the reasons I use this model).
-* An ol command in an ordered-list block decreases the indentation level by
-  one, and either merges with the previous block or adopts its list marker
-  type.  In an unordered-list block, it breaks up the parent <ul> and creates a
-  new one-element <ol>, or merges with the next or previous <ol> if any.  In a
-  non-list block, it creates a new <ol>, or merges with the next or previous
-  <ol> if any.  The ul command works similarly.
+* An ol command in an ordered-list block removes the surrounding <li>,
+  migrating its contents into the parent of the <ol>.  This splits up the <ol> if
+  it's not the first or last child, and wraps the contents in a new <li> if
+  necessary.  If there's another list or indentation element nested in the <li>
+  we're removing, it will get re-wrapped in a new <ol>, outside the
+  newly-created <li>, so that it maintains its indentation.  This might cause
+  the new <li> to wind up in multiple pieces, if the original block was not
+  contiguous, which means the non-contiguous block is split into several blocks
+  (with different numbers).
+* An ol command in an unordered-list block breaks up the parent <ul> and puts a
+  new <ol> in between the two pieces, moving the parent <li> into it.  If the
+  <li> was the first or last child, we merge with an existing adjacent <ol> if
+  possible.  All children stay as they are.
+* An ol command in a non-list block with indentation zero wraps it in a new
+  <ol><li>, or merges with an adjacent <ol> if possible.
+* An ol command in a non-list block with nonzero indentation converts the
+  parent to an <ol><li>, breaking it up if necessary.
+* The ul command works similarly to ol.
 * indent in a non-list block wraps in an indentation element.  In a list block,
-  it wraps the <li> in an extra <ol> or <ul> as appropriate.  (This often
-  creates non-conforming markup, like
-  <ol><li>foo</li><ol><li>bar</li></ol></ol>.)
+  it wraps the <li> in an extra <ol> or <ul> as appropriate.  With merging.
+  Whatever.  Let me just write the spec.
 * outdent in a non-list block strips an indentation element, if one is present.
   In a list block, it breaks apart the parent <ol> or <ul> and makes the
-  affected block a sibling in between the newly-split list elements.
-
-Problem: a block needs to be able to have multiple lines.  If it's a list
-block, this means it gets no extra markers, just one for the whole block.  This
-means it has to be possible to have non-contiguous blocks, for cases like
-<ol><li>foo<ol><li>bar</ol>baz</ol>.  We cannot simply consider "foo" and "baz"
-to be in separate blocks, because then baz has to have a list marker type of
-none, which will mess up subsequent list numbering and be indistinguishable
-from <ol><li>foo<ol><li>bar</ol></ol><blockquote>baz</blockquote>.  What's the
-expected behavior here?  Needs testing.
+  affected block a sibling in between the newly-split list elements.  Will
+  create new <li>s, etc. etc.
+
+Sheesh, lists are complicated.
 -->