Fix some more list indent bugs
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Thu, 05 May 2011 15:03:30 -0600
changeset 90 e4c38155e8b4
parent 89 7bcd2fc49ec1
child 91 930e3d99e27a
Fix some more list indent bugs
autoimplementation.html
editcommands.html
implementation.js
source.html
--- a/autoimplementation.html	Thu May 05 14:16:28 2011 -0600
+++ b/autoimplementation.html	Thu May 05 15:03:30 2011 -0600
@@ -535,6 +535,7 @@
 
 		// Lists!
 		'<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]',
 		'<ol><li>[foo]<br>bar<li>baz</ol>',
 		'<ol><li>foo<br>[bar]<li>baz</ol>',
@@ -543,12 +544,23 @@
 		'<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><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>',
+
+		// Try indenting 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>bar</ol><li>baz]</ol>',
+		'<ol><li>[foo</li><ol><li>bar</ol><li>baz]</ol>',
 	],
 	inserthorizontalrule: [
 		'foo[]bar',
--- a/editcommands.html	Thu May 05 14:16:28 2011 -0600
+++ b/editcommands.html	Thu May 05 15:03:30 2011 -0600
@@ -655,7 +655,7 @@
   <var title="">start offset</var> to the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> of the last such <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> in
   <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>, and set <var title="">start node</var> to that <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 <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
 
-  <li>Otherwise, repeat the following steps:
+  <li>Repeat the following steps:
 
   <ol>
     <li>If <var title="">start node</var> is a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> or <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment>Comment</a></code> node or
@@ -684,7 +684,7 @@
   <var title="">end offset</var> to one plus the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> of the last such <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> in
   <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>, and set <var title="">end node</var> to that <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 <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
 
-  <li>Otherwise, repeat the following steps:
+  <li>Repeat the following steps:
 
   <ol>
     <li>If <var title="">end offset</var> is 0, set <var title="">end offset</var> to the
@@ -1938,13 +1938,14 @@
 fragments, html/body, head or things in head . . .
 
 <ol>
-  <li>If the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>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> <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> has 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 class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#ancestor-container title="ancestor container">ancestor container</a>, <a href=#normalize-sublists>normalize sublists</a> of the last such
-  <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>.
-
-  <li>If the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a>'s <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> has 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 class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#ancestor-container title="ancestor container">ancestor container</a>, <a href=#normalize-sublists>normalize sublists</a> of the last such
-  <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>.
+  <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 class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>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 class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a>, and let <var title="">new range</var> be
   the result.
@@ -1991,7 +1992,7 @@
 <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 <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>:
+  <li>If <var title="">node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is 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
--- a/implementation.js	Thu May 05 14:16:28 2011 -0600
+++ b/implementation.js	Thu May 05 15:03:30 2011 -0600
@@ -1166,7 +1166,6 @@
 	// "If some ancestor container of start node is an li, set start offset to
 	// the index of the last such li in tree order, and set start node to that
 	// li's parent."
-	var inLi = false;
 	for (
 		var ancestorContainer = startNode;
 		ancestorContainer;
@@ -1175,55 +1174,51 @@
 		if (isHtmlElement(ancestorContainer, "LI")) {
 			startOffset = getNodeIndex(ancestorContainer);
 			startNode = ancestorContainer.parentNode;
-			inLi = true;
 			break;
 		}
 	}
 
-	// "Otherwise, repeat the following steps:"
-	if (!inLi) {
-		while (true) {
-			// "If start node is a Text or Comment node or start offset is 0,
-			// set start offset to the index of start node and then set start
-			// node to its parent."
-			if (startNode.nodeType == Node.TEXT_NODE
-			|| startNode.nodeType == Node.COMMENT_NODE
-			|| startOffset == 0) {
-				startOffset = getNodeIndex(startNode);
-				startNode = startNode.parentNode;
-
-			// "Otherwise, if start offset is equal to the length of start
-			// node, set start offset to one plus the index of start node and
-			// then set start node to its parent."
-			} else if (startOffset == getNodeLength(startNode)) {
-				startOffset = 1 + getNodeIndex(startNode);
-				startNode = startNode.parentNode;
-
-			// "Otherwise, if the child of start node with index start offset and
-			// its previousSibling are both inline nodes and neither is a br,
-			// subtract one from start offset."
-			} else if (isInlineNode(startNode.childNodes[startOffset])
-			&& isInlineNode(startNode.childNodes[startOffset].previousSibling)
-			&& (
-				!isHtmlElement(startNode.childNodes[startOffset])
-				|| startNode.childNodes[startOffset].tagName != "BR"
-			) && (
-				!isHtmlElement(startNode.childNodes[startOffset].previousSibling)
-				|| startNode.childNodes[startOffset].previousSibling.tagName != "BR"
-			)) {
-				startOffset--;
-
-			// "Otherwise, break from this loop."
-			} else {
-				break;
-			}
+	// "Repeat the following steps:"
+	while (true) {
+		// "If start node is a Text or Comment node or start offset is 0,
+		// set start offset to the index of start node and then set start
+		// node to its parent."
+		if (startNode.nodeType == Node.TEXT_NODE
+		|| startNode.nodeType == Node.COMMENT_NODE
+		|| startOffset == 0) {
+			startOffset = getNodeIndex(startNode);
+			startNode = startNode.parentNode;
+
+		// "Otherwise, if start offset is equal to the length of start
+		// node, set start offset to one plus the index of start node and
+		// then set start node to its parent."
+		} else if (startOffset == getNodeLength(startNode)) {
+			startOffset = 1 + getNodeIndex(startNode);
+			startNode = startNode.parentNode;
+
+		// "Otherwise, if the child of start node with index start offset and
+		// its previousSibling are both inline nodes and neither is a br,
+		// subtract one from start offset."
+		} else if (isInlineNode(startNode.childNodes[startOffset])
+		&& isInlineNode(startNode.childNodes[startOffset].previousSibling)
+		&& (
+			!isHtmlElement(startNode.childNodes[startOffset])
+			|| startNode.childNodes[startOffset].tagName != "BR"
+		) && (
+			!isHtmlElement(startNode.childNodes[startOffset].previousSibling)
+			|| startNode.childNodes[startOffset].previousSibling.tagName != "BR"
+		)) {
+			startOffset--;
+
+		// "Otherwise, break from this loop."
+		} else {
+			break;
 		}
 	}
 
 	// "If some ancestor container of end node is an li, set end offset to one
 	// plus the index of the last such li in tree order, and set end node to
 	// that li's parent."
-	var inLi = false;
 	for (
 		var ancestorContainer = endNode;
 		ancestorContainer;
@@ -1232,47 +1227,44 @@
 		if (isHtmlElement(ancestorContainer, "LI")) {
 			endOffset = 1 + getNodeIndex(ancestorContainer);
 			endNode = ancestorContainer.parentNode;
-			inLi = true;
 			break;
 		}
 	}
 
-	// "Otherwise, repeat the following steps:"
-	if (!inLi) {
-		while (true) {
-			// "If end offset is 0, set end offset to the index of end node and
-			// then set end node to its parent."
-			if (endOffset == 0) {
-				endOffset = getNodeIndex(endNode);
-				endNode = endNode.parentNode;
-
-			// "Otherwise, if end node is a Text or Comment node or end offset
-			// is equal to the length of end node, set end offset to one plus
-			// the index of end node and then set end node to its parent."
-			} else if (endNode.nodeType == Node.TEXT_NODE
-			|| endNode.nodeType == Node.COMMENT_NODE
-			|| endOffset == getNodeLength(endNode)) {
-				endOffset = 1 + getNodeIndex(endNode);
-				endNode = endNode.parentNode;
-
-			// "Otherwise, if the child of end node with index end offset and its
-			// previousSibling are both inline nodes and neither is a br, add one
-			// to end offset."
-			} else if (isInlineNode(endNode.childNodes[endOffset])
-			&& isInlineNode(endNode.childNodes[endOffset].previousSibling)
-			&& (
-				!isHtmlElement(endNode.childNodes[endOffset])
-				|| endNode.childNodes[endOffset].tagName != "BR"
-			) && (
-				!isHtmlElement(endNode.childNodes[endOffset].previousSibling)
-				|| endNode.childNodes[endOffset].previousSibling.tagName != "BR"
-			)) {
-				endOffset++;
-
-			// "Otherwise, break from this loop."
-			} else {
-				break;
-			}
+	// "Repeat the following steps:"
+	while (true) {
+		// "If end offset is 0, set end offset to the index of end node and
+		// then set end node to its parent."
+		if (endOffset == 0) {
+			endOffset = getNodeIndex(endNode);
+			endNode = endNode.parentNode;
+
+		// "Otherwise, if end node is a Text or Comment node or end offset
+		// is equal to the length of end node, set end offset to one plus
+		// the index of end node and then set end node to its parent."
+		} else if (endNode.nodeType == Node.TEXT_NODE
+		|| endNode.nodeType == Node.COMMENT_NODE
+		|| endOffset == getNodeLength(endNode)) {
+			endOffset = 1 + getNodeIndex(endNode);
+			endNode = endNode.parentNode;
+
+		// "Otherwise, if the child of end node with index end offset and its
+		// previousSibling are both inline nodes and neither is a br, add one
+		// to end offset."
+		} else if (isInlineNode(endNode.childNodes[endOffset])
+		&& isInlineNode(endNode.childNodes[endOffset].previousSibling)
+		&& (
+			!isHtmlElement(endNode.childNodes[endOffset])
+			|| endNode.childNodes[endOffset].tagName != "BR"
+		) && (
+			!isHtmlElement(endNode.childNodes[endOffset].previousSibling)
+			|| endNode.childNodes[endOffset].previousSibling.tagName != "BR"
+		)) {
+			endOffset++;
+
+		// "Otherwise, break from this loop."
+		} else {
+			break;
 		}
 	}
 
@@ -2191,31 +2183,31 @@
 		break;
 
 		case "indent":
-		// "If the range's start node has an li ancestor container, normalize
-		// sublists of the last such li in tree order."
-		for (
-			var ancestorContainer = range.startContainer;
-			ancestorContainer;
-			ancestorContainer = ancestorContainer.parentNode
-		) {
-			if (isHtmlElement(ancestorContainer, "LI")) {
-				normalizeSublists(ancestorContainer);
-				break;
+		// "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);
 			}
 		}
-
-		// "If the range's end node has an li ancestor container, normalize
-		// sublists of the last such li in tree order."
-		for (
-			var ancestorContainer = range.endContainer;
-			ancestorContainer;
-			ancestorContainer = ancestorContainer.parentNode
-		) {
-			if (isHtmlElement(ancestorContainer, "LI")) {
-				normalizeSublists(ancestorContainer);
-				break;
+		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);
@@ -2610,11 +2602,9 @@
 }
 
 function indentNode(node) {
-	// "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")) {
+	// "If node's parent is an ol or ul:"
+	if (isHtmlElement(node.parentNode, "OL")
+	|| isHtmlElement(node.parentNode, "UL")) {
 		// "Let tag be the local name of the parent of node."
 		var tag = node.parentNode.tagName;
 
@@ -2627,18 +2617,6 @@
 			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."
@@ -2648,18 +2626,6 @@
 			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);
--- a/source.html	Thu May 05 14:16:28 2011 -0600
+++ b/source.html	Thu May 05 15:03:30 2011 -0600
@@ -651,7 +651,7 @@
   <var>start offset</var> to the [[index]] of the last such [[li]] in
   [[treeorder]], and set <var>start node</var> to that [[li]]'s [[parent]].
 
-  <li>Otherwise, repeat the following steps:
+  <li>Repeat the following steps:
 
   <ol>
     <li>If <var>start node</var> is a [[text]] or [[comment]] node or
@@ -681,7 +681,7 @@
   <var>end offset</var> to one plus the [[index]] of the last such [[li]] in
   [[treeorder]], and set <var>end node</var> to that [[li]]'s [[parent]].
 
-  <li>Otherwise, repeat the following steps:
+  <li>Repeat the following steps:
 
   <ol>
     <li>If <var>end offset</var> is 0, set <var>end offset</var> to the
@@ -1957,13 +1957,14 @@
 fragments, html/body, head or things in head . . .
 
 <ol>
-  <li>If the [[range]]'s [[rangestart]] [[bpnode]] has an [[li]]
-  [[ancestorcontainer]], <span>normalize sublists</span> of the last such
-  [[li]] in [[treeorder]].
-
-  <li>If the [[range]]'s [[rangeend]] [[bpnode]] has an [[li]]
-  [[ancestorcontainer]], <span>normalize sublists</span> of the last such
-  [[li]] in [[treeorder]].
+  <li>Let <var>items</var> be a list of all [[li]]s that are
+  [[ancestorcontainers]] of the [[range]]'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 [[range]], and let <var>new range</var> be
   the result.
@@ -2010,7 +2011,7 @@
 <p>To <dfn>indent</dfn> a [[node]] <var>node</var>:
 
 <ol>
-  <li>If <var>node</var> is an [[li]] whose [[parent]] is an [[ol]] or [[ul]]:
+  <li>If <var>node</var>'s [[parent]] is an [[ol]] or [[ul]]:
 
   <ol>
     <li>Let <var>tag</var> be the [[localname]] of the [[parent]] of