Making list outdenting basically work
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Sun, 08 May 2011 13:54:16 -0600
changeset 97 32d1bf688781
parent 96 bfd5189f4d1c
child 98 5ff17073b64e
Making list outdenting basically work

Bunches more refinement to come.
autoimplementation.html
editcommands.html
implementation.js
source.html
--- a/autoimplementation.html	Sun May 08 13:30:40 2011 -0600
+++ b/autoimplementation.html	Sun May 08 13:54:16 2011 -0600
@@ -784,6 +784,45 @@
 		'<blockquote><p><span>foo[bar]</span><p>baz</blockquote>',
 		'<blockquote><blockquote style="color: red"><p>foo[bar]</blockquote><p>baz</blockquote>',
 		'<blockquote style="color: red"><blockquote><p>foo[bar]</blockquote><p>baz</blockquote>',
+
+		// 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>',
+		'<ol><li><div>[foo]</div>bar<li>baz</ol>',
+		'<ol><li>foo<ol><li>[bar]<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<ol><li>bar<li>[baz]</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol><li>[bar]<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol data-start=0 data-end=1><li>bar<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol><li>bar<li>[baz]</ol><li>quz</ol>',
+		'<ol><li>foo</li><ol data-start=1 data-end=2><li>bar<li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<ol><li>b[a]r</ol><li>baz</ol>',
+		'<ol><li>foo</li><ol><li>b[a]r</ol><li>baz</ol>',
+		'<ol><li>foo{<ol><li>bar</ol>}<li>baz</ol>',
+		'<ol><li>foo</li>{<ol><li>bar</ol>}<li>baz</ol>',
+		'<ol><li>[foo]<ol><li>bar</ol><li>baz</ol>',
+		'<ol><li>[foo]</li><ol><li>bar</ol><li>baz</ol>',
+		'<ol><li>foo<li>[bar]<ol><li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<li>[bar]</li><ol><li>baz</ol><li>quz</ol>',
+		'<ol><li>foo<ol><li>bar<li>baz</ol><li>[quz]</ol>',
+		'<ol><li>foo</li><ol><li>bar<li>baz</ol><li>[quz]</ol>',
+
+		// 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>b[ar</ol><li>b]az</ol>',
+		'<ol><li>foo</li><ol><li>b[ar</ol><li>b]az</ol>',
+		'<ol><li>[foo<ol><li>bar</ol><li>baz]</ol><p>extra',
+		'<ol><li>[foo</li><ol><li>bar</ol><li>baz]</ol><p>extra',
+
+		// We probably can't actually get this DOM . . .
+		'<ol><li>[foo]<ol><li>bar</ol>baz</ol>',
+		'<ol><li>foo<ol><li>[bar]</ol>baz</ol>',
+		'<ol><li>foo<ol><li>bar</ol>[baz]</ol>',
+		'<ol><li>[foo<ol><li>bar]</ol>baz</ol>',
 	],
 	removeformat: [
 		'foo[]bar',
--- a/editcommands.html	Sun May 08 13:30:40 2011 -0600
+++ b/editcommands.html	Sun May 08 13:54:16 2011 -0600
@@ -2568,8 +2568,18 @@
   <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.
 
-  <li>Let <var title="">node list</var> be all <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">new
-  range</var> that have no <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>.
+  <li>Let <var title="">node list</var> be a list of <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a>, initially empty.
+
+  <li>For each <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <var title="">node</var> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">node list</var>:
+
+  <ol>
+    <li>If some <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>,
+    continue with the next <var title="">node</var>.
+
+    <li>If <var title="">node</var> has no <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>, or 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>, or
+    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>, append it to
+    <var title="">node list</var>.
+  </ol>
 
   <li><a href=#outdent>Outdent</a> each member of <var title="">node list</var>.
 </ol>
@@ -2626,7 +2636,7 @@
 
       <li>If <var title="">child</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 <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of
       <var title="">node</var> is not an <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>, <a href=#set-the-tag-name>set the tag name</a>
-      of <var title="">child</var> to "div".
+      of <var title="">child</var> to "div", and set <var title="">child</var> to the result.
 
       <li>Insert <var title="">child</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>, <a href=#preserving-ranges>preserving ranges</a>.
@@ -2645,7 +2655,8 @@
     <li>Unset the <code class=external data-anolis-spec=html title=attr-ol-reversed><a href=http://www.whatwg.org/html/#attr-ol-reversed>reversed</a></code>, <code class=external data-anolis-spec=html title=attr-ol-start><a href=http://www.whatwg.org/html/#attr-ol-start>start</a></code>, and <code class=external data-anolis-spec=html title=attr-ol-type><a href=http://www.whatwg.org/html/#attr-ol-type>type</a></code> attributes of <var title="">node</var>, if any are
     set.
 
-    <li><a href=#set-the-tag-name>Set the tag name</a> of <var title="">node</var> to "div".
+    <li><a href=#set-the-tag-name>Set the tag name</a> of <var title="">node</var> to "div", and set
+    <var title="">node</var> to the result.
 
     <li>For each <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=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> <var title="">child</var> of <var title="">node</var>, unset
     the <code class=external data-anolis-spec=html title=attr-li-value><a href=http://www.whatwg.org/html/#attr-li-value>value</a></code> attribute
@@ -2663,7 +2674,7 @@
     <li>If <var title="">parent</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 not an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> 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>, unset the
     <code class=external data-anolis-spec=html title=attr-li-value><a href=http://www.whatwg.org/html/#attr-li-value>value</a></code> attribute of
     <var title="">node</var> if set, then <a href=#set-the-tag-name>set the tag name</a> of
-    <var title="">node</var> to "div".
+    <var title="">node</var> to "div" and set <var title="">node</var> to the result.
 
     <li>If <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-previousSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling>previousSibling</a></code> is null, insert
     <var title="">node</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="">parent</var> immediately before
@@ -2686,7 +2697,7 @@
     exclude other things like itemid or accesskey or . . .
 
     <li>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="">parent</var>
-    immediately after <var title="">parent</var>.
+    immediately after <var title="">parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
 
     <li>While <var title="">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> is not null, insert 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="">parent</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 <var title="">new
@@ -2730,7 +2741,8 @@
   Firefox in CSS mode, for instance (color, font-family, etc.). -->
 
   <ol>
-    <li><a href=#set-the-tag-name>Set the tag name</a> of <var title="">node</var> to "div".
+    <li><a href=#set-the-tag-name>Set the tag name</a> of <var title="">node</var> to "div", and set
+    <var title="">node</var> to the result.
 
     <li>Unset the <code class=external data-anolis-spec=html title=classes><a href=http://www.whatwg.org/html/#classes>class</a></code> and
     <code class=external data-anolis-spec=html title="the dir attribute"><a href=http://www.whatwg.org/html/#the-dir-attribute>dir</a></code>
@@ -2813,7 +2825,7 @@
     <li>Let <var title="">current ancestor</var> be the last member of <var title="">ancestor
     list</var>.
 
-    <li>Remove the last member of <var title="">ancestor list</var>.
+    <li>Remove the last member from <var title="">ancestor list</var>.
 
     <li>Let <var title="">target</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="">current ancestor</var>
     that is equal to either <var title="">node</var> or the last member of <var title="">ancestor
--- a/implementation.js	Sun May 08 13:30:40 2011 -0600
+++ b/implementation.js	Sun May 08 13:54:16 2011 -0600
@@ -2467,16 +2467,36 @@
 		// "Block-extend the range, and let new range be the result."
 		var newRange = blockExtendRange(range);
 
-		// "Let node list be all nodes contained in new range that have no
-		// children."
+		// "Let node list be a list of nodes, initially empty."
 		var nodeList = [];
+
+		// "For each node node contained in node list:"
 		for (
 			var node = newRange.startContainer;
 			node != nextNodeDescendants(newRange.endContainer);
 			node = nextNode(node)
 		) {
-			if (isContained(node, newRange)
-			&& !node.hasChildNodes()) {
+			if (!isContained(node, newRange)) {
+				continue;
+			}
+
+			// "If some ancestor of node is in node list, continue with the
+			// next node."
+			//
+			// We only need to check the last node on the list, if you think
+			// about it.
+			if (isAncestor(nodeList[nodeList.length - 1], node)) {
+				continue;
+			}
+
+			// "If node has no children, or is an ol or ul, or is an li whose
+			// parent is an ol or ul, append it to node list."
+			if (!node.hasChildNodes()
+			|| isHtmlElement(node, "OL")
+			|| isHtmlElement(node, "UL")
+			|| (isHtmlElement(node, "LI")
+			&& (isHtmlElement(node.parentNode, "OL")
+			|| isHtmlElement(node.parentNode, "UL")))) {
 				nodeList.push(node);
 			}
 		}
@@ -2789,11 +2809,12 @@
 			var child = node.firstChild;
 
 			// "If child is an li and the parent of node is not an ol or ul,
-			// set the tag name of child to "div"."
+			// set the tag name of child to "div", and set child to the
+			// result."
 			if (isHtmlElement(child, "LI")
 			&& !isHtmlElement(node.parentNode, "OL")
 			&& !isHtmlElement(node.parentNode, "UL")) {
-				setTagName(child, "div");
+				child = setTagName(child, "div");
 			}
 
 			// "Insert child into the parent of node immediately before node,
@@ -2817,8 +2838,8 @@
 		node.removeAttribute("start");
 		node.removeAttribute("type");
 
-		// "Set the tag name of node to "div"."
-		setTagName(node, "div");
+		// "Set the tag name of node to "div", and set node to the result."
+		node = setTagName(node, "div");
 
 		// "For each li child child of node, unset the value attribute of child
 		// if set, then set the tag name of child to "div"."
@@ -2843,11 +2864,12 @@
 		var parent_ = node.parentNode;
 
 		// "If parent's parent is not an ol or ul, unset the value attribute of
-		// node if set, then set the tag name of node to "div"."
+		// node if set, then set the tag name of node to "div" and set node to
+		// the result."
 		if (!isHtmlElement(parent_.parentNode, "OL")
 		&& !isHtmlElement(parent_.parentNode, "UL")) {
 			node.removeAttribute("value");
-			setTagName(node, "div");
+			node = setTagName(node, "div");
 		}
 
 		// "If node's previousSibling is null, insert node into the parent of
@@ -2880,8 +2902,9 @@
 			movePreservingRanges(parent_.lastChild, newParent, 0);
 		}
 
-		// "Insert node into the parent of parent immediately after parent."
-		parent_.parentNode.insertBefore(node, parent_.nextSibling);
+		// "Insert node into the parent of parent immediately after parent,
+		// preserving ranges."
+		movePreservingRanges(node, parent_.parentNode, 1+ getNodeIndex(parent_));
 
 		// "Abort these steps."
 		return;
@@ -2911,8 +2934,8 @@
 
 	// "If node is a potential indentation element:"
 	if (isPotentialIndentationElement(node)) {
-		// "Set the tag name of node to "div"."
-		setTagName(node, "div");
+		// "Set the tag name of node to "div", and set node to the result."
+		node = setTagName(node, "div");
 
 		// "Unset the class and dir attributes of node, if any."
 		node.removeAttribute("class");
--- a/source.html	Sun May 08 13:30:40 2011 -0600
+++ b/source.html	Sun May 08 13:54:16 2011 -0600
@@ -2610,8 +2610,18 @@
   <li><span>Block-extend</span> the [[range]], and let <var>new range</var> be
   the result.
 
-  <li>Let <var>node list</var> be all [[nodes]] [[contained]] in <var>new
-  range</var> that have no [[children]].
+  <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
+
+  <li>For each [[node]] <var>node</var> [[contained]] in <var>node list</var>:
+
+  <ol>
+    <li>If some [[ancestor]] of <var>node</var> is in <var>node list</var>,
+    continue with the next <var>node</var>.
+
+    <li>If <var>node</var> has no [[children]], or is an [[ol]] or [[ul]], or
+    is an [[li]] whose [[parent]] is an [[ol]] or [[ul]], append it to
+    <var>node list</var>.
+  </ol>
 
   <li><span>Outdent</span> each member of <var>node list</var>.
 </ol>
@@ -2669,7 +2679,7 @@
 
       <li>If <var>child</var> is an [[li]] and the [[parent]] of
       <var>node</var> is not an [[ol]] or [[ul]], <span>set the tag name</span>
-      of <var>child</var> to "div".
+      of <var>child</var> to "div", and set <var>child</var> to the result.
 
       <li>Insert <var>child</var> into the [[parent]] of <var>node</var>
       immediately before <var>node</var>, <span>preserving ranges</span>.
@@ -2691,7 +2701,8 @@
     title=attr-ol-type>type</code> attributes of <var>node</var>, if any are
     set.
 
-    <li><span>Set the tag name</span> of <var>node</var> to "div".
+    <li><span>Set the tag name</span> of <var>node</var> to "div", and set
+    <var>node</var> to the result.
 
     <li>For each [[li]] [[child]] <var>child</var> of <var>node</var>, unset
     the <code data-anolis-spec=html title=attr-li-value>value</code> attribute
@@ -2709,7 +2720,7 @@
     <li>If <var>parent</var>'s [[parent]] is not an [[ol]] or [[ul]], unset the
     <code data-anolis-spec=html title=attr-li-value>value</code> attribute of
     <var>node</var> if set, then <span>set the tag name</span> of
-    <var>node</var> to "div".
+    <var>node</var> to "div" and set <var>node</var> to the result.
 
     <li>If <var>node</var>'s [[previoussibling]] is null, insert
     <var>node</var> into the [[parent]] of <var>parent</var> immediately before
@@ -2733,7 +2744,7 @@
     exclude other things like itemid or accesskey or . . .
 
     <li>Insert <var>new parent</var> into the [[parent]] of <var>parent</var>
-    immediately after <var>parent</var>.
+    immediately after <var>parent</var>, <span>preserving ranges</span>.
 
     <li>While <var>node</var>'s [[nextsibling]] is not null, insert the last
     [[child]] of <var>parent</var> as the first [[child]] of <var>new
@@ -2777,7 +2788,8 @@
   Firefox in CSS mode, for instance (color, font-family, etc.). -->
 
   <ol>
-    <li><span>Set the tag name</span> of <var>node</var> to "div".
+    <li><span>Set the tag name</span> of <var>node</var> to "div", and set
+    <var>node</var> to the result.
 
     <li>Unset the <code data-anolis-spec=html title=classes>class</code> and
     <code data-anolis-spec=html title="the dir attribute">dir</code>
@@ -2860,7 +2872,7 @@
     <li>Let <var>current ancestor</var> be the last member of <var>ancestor
     list</var>.
 
-    <li>Remove the last member of <var>ancestor list</var>.
+    <li>Remove the last member from <var>ancestor list</var>.
 
     <li>Let <var>target</var> be the [[child]] of <var>current ancestor</var>
     that is equal to either <var>node</var> or the last member of <var>ancestor