Handle backspacing to an adjacent list item
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Sun, 12 Jun 2011 13:57:32 -0600
changeset 257 0fa57bc91eea
parent 256 8fb704c6f76d
child 258 e9814a4d057b
Handle backspacing to an adjacent list item
editcommands.html
implementation.js
source.html
tests.js
--- a/editcommands.html	Sun Jun 12 13:21:09 2011 -0600
+++ b/editcommands.html	Sun Jun 12 13:57:32 2011 -0600
@@ -2551,9 +2551,9 @@
   (<var title="">node</var>, <var title="">offset</var> &minus; 1) and <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a>
   (<var title="">node</var>, <var title="">offset</var>) and abort these steps.
 
+  <!-- At the time of this writing, this should be impossible. -->
   <li>If <var title="">node</var> is not a <a href=#prohibited-paragraph-child>prohibited paragraph child</a>,
   abort these steps.
-  <!-- At the time of this writing, this should be impossible. -->
 
   <li>If <var title="">node</var> has a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">offset</var>
   &minus; 1 and that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code> or <code class=external data-anolis-spec=html title="the hr element"><a href=http://www.whatwg.org/html/#the-hr-element>hr</a></code> or <code class=external data-anolis-spec=html title="the img element"><a href=http://www.whatwg.org/html/#the-img-element>img</a></code>, call
@@ -2571,6 +2571,9 @@
   <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> of <var title="">start node</var> and then set <var title="">start node</var> to its
   <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
 
+  <p class=XXX>The node at index start offset &minus; 1 might be an invisible
+  node.
+
   <!--
   This is to avoid stripping a line break from
 
@@ -2581,12 +2584,14 @@
   <li>If 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 <var title="">start node</var> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start
   offset</var> is a <code class=external data-anolis-spec=html title="the table element"><a href=http://www.whatwg.org/html/#the-table-element>table</a></code>, abort these steps.
 
+  <!--
+  If you try backspacing into a table, select it.  This doesn't match any
+  browser; it matches the recommendation of the "behavior when typing in
+  contentEditable elements" document.  The idea is that then you can delete it
+  with a second backspace.
+  -->
   <li>If <var title="">start node</var> has a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start
   offset</var> &minus; 1, and that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is a <code class=external data-anolis-spec=html title="the table element"><a href=http://www.whatwg.org/html/#the-table-element>table</a></code>:
-  <!-- If you try backspacing into a table, select it.  This doesn't match any
-  browser; it matches the recommendation of the "behavior when typing in
-  contentEditable elements" document.  The idea is that then you can delete it
-  with a second backspace. -->
 
   <ol>
     <li>Call <code class=external data-anolis-spec=domrange title=dom-Selection-collapse><a href=http://html5.org/specs/dom-range.html#dom-selection-collapse>collapse(<var title="">start node</var>, <var title="">start offset</var>
@@ -2598,11 +2603,6 @@
     <li>Abort these steps.
   </ol>
 
-  <li>If <var title="">offset</var> is zero; and either 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 <var title="">start
-  node</var> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start offset</var> minus one is an <code class=external data-anolis-spec=html title="the hr element"><a href=http://www.whatwg.org/html/#the-hr-element>hr</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> is a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code> whose <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 either a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code> or not
-  an <a href=#inline-node>inline node</a>:
-
   <!--
   Special case:
 
@@ -2617,6 +2617,11 @@
   Browsers don't do this consistently.  Firefox 5.0a2 doesn't seem to do it at
   all.
   -->
+  <li>If <var title="">offset</var> is zero; and either 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 <var title="">start
+  node</var> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start offset</var> minus one is an <code class=external data-anolis-spec=html title="the hr element"><a href=http://www.whatwg.org/html/#the-hr-element>hr</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> is a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code> whose <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 either a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code> or not
+  an <a href=#inline-node>inline node</a>:
+
   <ol>
     <li>Call <code class=external data-anolis-spec=domrange title=dom-Selection-collapse><a href=http://html5.org/specs/dom-range.html#dom-selection-collapse>collapse(<var title="">node</var>, <var title="">offset</var>)</a></code> on the
     <code class=external data-anolis-spec=domrange><a href=http://html5.org/specs/dom-range.html#selection>Selection</a></code>.
@@ -2628,16 +2633,62 @@
     <li>Abort these steps.
   </ol>
 
+  <!--
+  If you try backspacing out of a list item, merge it with the previous item,
+  but add a line break.  Then you have to backspace again if you really want
+  them to be on the same line.  This matches Word 2007 and OpenOffice.org 3.2.1
+  Ubuntu, and also matches "behavior when typing in contentEditable elements",
+  but does not match any browser.
+
+  Note that this behavior is quite different from what happens if you actually
+  select the linebreak in between the two lines.  In that case, the blocks are
+  merged as normal.
+  -->
+  <li>If 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 <var title="">start node</var> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start
+  offset</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> or <code class=external data-anolis-spec=html title="the dt element"><a href=http://www.whatwg.org/html/#the-dt-element>dt</a></code> or <code class=external data-anolis-spec=html title="the dd element"><a href=http://www.whatwg.org/html/#the-dd-element>dd</a></code>, and that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>'s
+  <code class=external data-anolis-spec=domcore title=dom-Node-firstChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-firstchild>firstChild</a></code> is an <a href=#inline-node>inline node</a>, and <var title="">start offset</var> is
+  not zero:
+
+  <ol>
+    <li>Let <var title="">previous item</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>child</a> of <var title="">start node</var>
+    with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start offset</var> minus one.
+
+    <!-- If the last child is already a br, we only need to append one extra
+    br.  Otherwise we need to append two, since the first will do nothing. -->
+    <li>If <var title="">previous item</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-lastChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-lastchild>lastChild</a></code> is an <a href=#inline-node>inline
+    node</a> other than a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the
+    <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="">previous item</var>.
+
+    <li>If <var title="">previous item</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-lastChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-lastchild>lastChild</a></code> is an <a href=#inline-node>inline
+    node</a>, call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the <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="">previous item</var>.
+  </ol>
+
+  <!--
+  When merging adjacent list items, make sure we only merge the items
+  themselves, not any block children.  We want <li><p>foo<li><p>bar to become
+  <li><p>foo<p>bar, not <li><p>foo<br>bar or <li><p>foobar.
+  -->
+  <li>If 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 <var title="">start node</var> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start
+  offset</var> is an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> or <code class=external data-anolis-spec=html title="the dt element"><a href=http://www.whatwg.org/html/#the-dt-element>dt</a></code> or <code class=external data-anolis-spec=html title="the dd element"><a href=http://www.whatwg.org/html/#the-dd-element>dd</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
+  also an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> or <code class=external data-anolis-spec=html title="the dt element"><a href=http://www.whatwg.org/html/#the-dt-element>dt</a></code> or <code class=external data-anolis-spec=html title="the dd element"><a href=http://www.whatwg.org/html/#the-dd-element>dd</a></code>, set <var title="">start node</var> to its
+  <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start offset</var> &minus; 1, then set
+  <var title="">start offset</var> to <var title="">start node</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a>, then set
+  <var title="">node</var> to <var title="">start node</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code>, then set
+  <var title="">offset</var> to 0.
+
   <!-- General block-merging case. -->
-  <li>While <var title="">start node</var> has a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start
-  offset</var> minus one, set <var title="">start node</var> to that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, then set
-  <var title="">start offset</var> to the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of <var title="">start node</var>.
+  <li>Otherwise, while <var title="">start node</var> has a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a>
+  <var title="">start offset</var> minus one, set <var title="">start node</var> to that
+  <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, then set <var title="">start offset</var> to the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of
+  <var title="">start node</var>.
 
   <li><a href=#delete-the-contents>Delete the contents</a> of the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>
   (<var title="">start node</var>, <var title="">start offset</var>) and <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a>
   (<var title="">node</var>, <var title="">offset</var>).
 
-  <li class=XXX>Lots more cases to handle.
+  <li class=XXX>Still more cases to handle.
 </ol>
 
 
--- a/implementation.js	Sun Jun 12 13:21:09 2011 -0600
+++ b/implementation.js	Sun Jun 12 13:57:32 2011 -0600
@@ -3339,13 +3339,53 @@
 			return;
 		}
 
-		// "While start node has a child with index start offset minus one, set
-		// start node to that child, then set start offset to the length of
-		// start node."
-		while (0 <= startOffset - 1
-		&& startOffset - 1 < startNode.childNodes.length) {
+		// "If the child of start node with index start offset is an li or dt
+		// or dd, and that child's firstChild is an inline node, and start
+		// offset is not zero:"
+		if (isHtmlElement(startNode.childNodes[startOffset], ["li", "dt", "dd"])
+		&& isInlineNode(startNode.childNodes[startOffset].firstChild)
+		&& startOffset != 0) {
+			// "Let previous item be the child of start node with index start
+			// offset minus one."
+			var previousItem = startNode.childNodes[startOffset - 1];
+
+			// "If previous item's lastChild is an inline node other than a br,
+			// call createElement("br") on the context object and append the
+			// result as the last child of previous item."
+			if (isInlineNode(previousItem.lastChild)
+			&& !isHtmlElement(previousItem.lastChild, "br")) {
+				previousItem.appendChild(document.createElement("br"));
+			}
+
+			// "If previous item's lastChild is an inline node, call
+			// createElement("br") on the context object and append the result
+			// as the last child of previous item."
+			if (isInlineNode(previousItem.lastChild)) {
+				previousItem.appendChild(document.createElement("br"));
+			}
+		}
+
+		// "If the child of start node with index start offset is an li or dt
+		// or dd, and its previousSibling is also an li or dt or dd, set start
+		// node to its child with index start offset − 1, then set start offset
+		// to start node's length, then set node to start node's nextSibling,
+		// then set offset to 0."
+		if (isHtmlElement(startNode.childNodes[startOffset], ["li", "dt", "dd"])
+		&& isHtmlElement(startNode.childNodes[startOffset - 1], ["li", "dt", "dd"])) {
 			startNode = startNode.childNodes[startOffset - 1];
 			startOffset = getNodeLength(startNode);
+			node = startNode.nextSibling;
+			offset = 0;
+
+		// "Otherwise, while start node has a child with index start offset
+		// minus one, set start node to that child, then set start offset to
+		// the length of start node."
+		} else {
+			while (0 <= startOffset - 1
+			&& startOffset - 1 < startNode.childNodes.length) {
+				startNode = startNode.childNodes[startOffset - 1];
+				startOffset = getNodeLength(startNode);
+			}
 		}
 
 		// "Delete the contents of the range with start (start node, start
--- a/source.html	Sun Jun 12 13:21:09 2011 -0600
+++ b/source.html	Sun Jun 12 13:57:32 2011 -0600
@@ -2531,9 +2531,9 @@
   (<var>node</var>, <var>offset</var> &minus; 1) and [[rangeend]]
   (<var>node</var>, <var>offset</var>) and abort these steps.
 
+  <!-- At the time of this writing, this should be impossible. -->
   <li>If <var>node</var> is not a <span>prohibited paragraph child</span>,
   abort these steps.
-  <!-- At the time of this writing, this should be impossible. -->
 
   <li>If <var>node</var> has a [[child]] with [[index]] <var>offset</var>
   &minus; 1 and that [[child]] is a [[br]] or [[hr]] or [[img]], call
@@ -2551,6 +2551,9 @@
   [[index]] of <var>start node</var> and then set <var>start node</var> to its
   [[parent]].
 
+  <p class=XXX>The node at index start offset &minus; 1 might be an invisible
+  node.
+
   <!--
   This is to avoid stripping a line break from
 
@@ -2561,12 +2564,14 @@
   <li>If the [[child]] of <var>start node</var> with [[index]] <var>start
   offset</var> is a [[table]], abort these steps.
 
+  <!--
+  If you try backspacing into a table, select it.  This doesn't match any
+  browser; it matches the recommendation of the "behavior when typing in
+  contentEditable elements" document.  The idea is that then you can delete it
+  with a second backspace.
+  -->
   <li>If <var>start node</var> has a [[child]] with [[index]] <var>start
   offset</var> &minus; 1, and that [[child]] is a [[table]]:
-  <!-- If you try backspacing into a table, select it.  This doesn't match any
-  browser; it matches the recommendation of the "behavior when typing in
-  contentEditable elements" document.  The idea is that then you can delete it
-  with a second backspace. -->
 
   <ol>
     <li>Call [[selcollapse|<var>start node</var>, <var>start offset</var>
@@ -2578,11 +2583,6 @@
     <li>Abort these steps.
   </ol>
 
-  <li>If <var>offset</var> is zero; and either the [[child]] of <var>start
-  node</var> with [[index]] <var>start offset</var> minus one is an [[hr]], or
-  the [[child]] is a [[br]] whose [[previoussibling]] is either a [[br]] or not
-  an <span>inline node</span>:
-
   <!--
   Special case:
 
@@ -2597,6 +2597,11 @@
   Browsers don't do this consistently.  Firefox 5.0a2 doesn't seem to do it at
   all.
   -->
+  <li>If <var>offset</var> is zero; and either the [[child]] of <var>start
+  node</var> with [[index]] <var>start offset</var> minus one is an [[hr]], or
+  the [[child]] is a [[br]] whose [[previoussibling]] is either a [[br]] or not
+  an <span>inline node</span>:
+
   <ol>
     <li>Call [[selcollapse|<var>node</var>, <var>offset</var>]] on the
     [[selection]].
@@ -2608,16 +2613,62 @@
     <li>Abort these steps.
   </ol>
 
+  <!--
+  If you try backspacing out of a list item, merge it with the previous item,
+  but add a line break.  Then you have to backspace again if you really want
+  them to be on the same line.  This matches Word 2007 and OpenOffice.org 3.2.1
+  Ubuntu, and also matches "behavior when typing in contentEditable elements",
+  but does not match any browser.
+
+  Note that this behavior is quite different from what happens if you actually
+  select the linebreak in between the two lines.  In that case, the blocks are
+  merged as normal.
+  -->
+  <li>If the [[child]] of <var>start node</var> with [[index]] <var>start
+  offset</var> is an [[li]] or [[dt]] or [[dd]], and that [[child]]'s
+  [[firstchild]] is an <span>inline node</span>, and <var>start offset</var> is
+  not zero:
+
+  <ol>
+    <li>Let <var>previous item</var> be the [[child]] of <var>start node</var>
+    with [[index]] <var>start offset</var> minus one.
+
+    <!-- If the last child is already a br, we only need to append one extra
+    br.  Otherwise we need to append two, since the first will do nothing. -->
+    <li>If <var>previous item</var>'s [[lastchild]] is an <span>inline
+    node</span> other than a [[br]], call [[createelement|"br"]] on the
+    [[contextobject]] and append the result as the last [[child]] of
+    <var>previous item</var>.
+
+    <li>If <var>previous item</var>'s [[lastchild]] is an <span>inline
+    node</span>, call [[createelement|"br"]] on the [[contextobject]] and
+    append the result as the last [[child]] of <var>previous item</var>.
+  </ol>
+
+  <!--
+  When merging adjacent list items, make sure we only merge the items
+  themselves, not any block children.  We want <li><p>foo<li><p>bar to become
+  <li><p>foo<p>bar, not <li><p>foo<br>bar or <li><p>foobar.
+  -->
+  <li>If the [[child]] of <var>start node</var> with [[index]] <var>start
+  offset</var> is an [[li]] or [[dt]] or [[dd]], and its [[previoussibling]] is
+  also an [[li]] or [[dt]] or [[dd]], set <var>start node</var> to its
+  [[child]] with [[index]] <var>start offset</var> &minus; 1, then set
+  <var>start offset</var> to <var>start node</var>'s [[nodelength]], then set
+  <var>node</var> to <var>start node</var>'s [[nextsibling]], then set
+  <var>offset</var> to 0.
+
   <!-- General block-merging case. -->
-  <li>While <var>start node</var> has a [[child]] with [[index]] <var>start
-  offset</var> minus one, set <var>start node</var> to that [[child]], then set
-  <var>start offset</var> to the [[nodelength]] of <var>start node</var>.
+  <li>Otherwise, while <var>start node</var> has a [[child]] with [[index]]
+  <var>start offset</var> minus one, set <var>start node</var> to that
+  [[child]], then set <var>start offset</var> to the [[nodelength]] of
+  <var>start node</var>.
 
   <li><span>Delete the contents</span> of the [[range]] with [[rangestart]]
   (<var>start node</var>, <var>start offset</var>) and [[rangeend]]
   (<var>node</var>, <var>offset</var>).
 
-  <li class=XXX>Lots more cases to handle.
+  <li class=XXX>Still more cases to handle.
 </ol>
 
 
--- a/tests.js	Sun Jun 12 13:21:09 2011 -0600
+++ b/tests.js	Sun Jun 12 13:57:32 2011 -0600
@@ -226,6 +226,9 @@
 	// IdentifierName to include ReservedWord; Identifier excludes it.
 	"delete": [
 		// Collapsed selection
+		'[]foo',
+		'<span>[]foo</span>',
+		'<p>[]foo</p>',
 		'foo[]bar',
 		'<span>foo</span>{}<span>bar</span>',
 		'<span>foo[</span><span>]bar</span>',
@@ -263,6 +266,7 @@
 		'<a href=/>foo</a>[]bar',
 		'foo<a href=/>[]bar</a>',
 
+		// Tables
 		'foo<table><tr><td>[]bar</table>baz',
 		'foo<table><tr><td>bar</table>[]baz',
 		'<p>foo<table><tr><td>[]bar</table><p>baz',
@@ -289,6 +293,25 @@
 		'<table><tr><td>foo<hr><td>[]bar</table>',
 		'<table><tr><td>foo<hr><tr><td>[]bar</table>',
 
+		// Lists
+		'foo<ol><li>[]bar<li>baz</ol>',
+		'foo<br><ol><li>[]bar<li>baz</ol>',
+		'<ol><li>foo<li>[]bar</ol>',
+		'<ol><li>foo<br><li>[]bar</ol>',
+		'<ol><li>foo<br><br><li>[]bar</ol>',
+		'<ol><li>foo<li>[]bar<br>baz</ol>',
+		'<ol><li>foo<br>bar<li>[]baz</ol>',
+
+		'<ol><li><p>foo<li>[]bar</ol>',
+		'<ol><li>foo<li><p>[]bar</ol>',
+		'<ol><li><p>foo<li><p>[]bar</ol>',
+
+		'foo<dl><dt>[]bar<dd>baz</dl>',
+		'foo<dl><dd>[]bar</dl>',
+		'<dl><dt>foo<dd>[]bar</dl>',
+		'<dl><dt>foo<dt>[]bar<dd>baz</dl>',
+		'<dl><dt>foo<dd>bar<dd>[]baz</dl>',
+
 		// Invisible stuff
 		'foo<span></span>[]bar',
 		'foo<span><span></span></span>[]bar',
@@ -376,6 +399,14 @@
 
 		'<ol><li>fo[o</ol><ol><li>b]ar</ol>',
 		'<ol><li>fo[o</ol><ul><li>b]ar</ul>',
+
+		'foo[<ol><li>]bar</ol>',
+		'<ol><li>foo[<li>]bar</ol>',
+		'foo[<dl><dt>]bar<dd>baz</dl>',
+		'foo[<dl><dd>]bar</dl>',
+		'<dl><dt>foo[<dd>]bar</dl>',
+		'<dl><dt>foo[<dt>]bar<dd>baz</dl>',
+		'<dl><dt>foo<dd>bar[<dd>]baz</dl>',
 	],
 	fontname: [
 		'foo[]bar',