Fix a couple of paragraph-wrapping bugs
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Tue, 31 May 2011 13:31:25 -0600
changeset 214 bb8c2ac33480
parent 213 4a5af8f2e33e
child 215 364fa153bdae
Fix a couple of paragraph-wrapping bugs

Outdenting <ol><li>foo<br>bar</li></ol> now produces <p>foo<br>bar</p>
instead of <p>foo</p><p>bar</p>; and doing formatBlock to <p> on
<div>foo<p>bar</p></div> no longer produces non-serializable DOMs.
autoimplementation.html
editcommands.html
implementation.js
source.html
--- a/autoimplementation.html	Tue May 31 13:31:07 2011 -0600
+++ b/autoimplementation.html	Tue May 31 13:31:25 2011 -0600
@@ -700,6 +700,7 @@
 		['<h1>', '<pre>[foo<br>bar]</pre>'],
 
 		['<h1>', '<p>[foo</p>bar]'],
+		['<p>', '<div>[foo<p>bar]</p></div>'],
 	],
 	hilitecolor: [
 		'foo[]bar',
--- a/editcommands.html	Tue May 31 13:31:07 2011 -0600
+++ b/editcommands.html	Tue May 31 13:31:25 2011 -0600
@@ -2866,12 +2866,12 @@
   <code class=external data-anolis-spec=html title="the dl element"><a href=http://www.whatwg.org/html/#the-dl-element>dl</a></code>:
 
   <ol>
-    <li>Let <var title="">children</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a> of <var title="">node</var>.
-
-    <li>Remove <var title="">node</var>, <a href=#preserving-its-descendants>preserving its descendants</a>.
-
-    <li><a href=#block-format>Block-format</a> <var title="">children</var>, with <var title="">value</var>
-    equal to the <a href=#default-single-line-container-name>default single-line container name</a>.
+    <li><a href=#set-the-tag-name>Set the tag name</a> of <var title="">node</var> to "div", and let
+    <var title="">node</var> be the result.
+
+    <li><a href=#block-format>Block-format</a> the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of
+    <var title="">node</var>, with <var title="">value</var> equal to the <a href=#default-single-line-container-name>default
+    single-line container name</a>.
 
     <li>Abort these steps.
   </ol>
@@ -2885,6 +2885,48 @@
   of <var title="">node</var>.
 </ol>
 
+<p>To <dfn id=fix-prohibited-paragraph-descendants>fix prohibited paragraph descendants</dfn> of 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> 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>, return the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list
+  consisting of <var title="">node</var>.
+
+  <li>Let <var title="">children</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a> of <var title="">node</var>.
+
+  <li><a href=#fix-prohibited-paragraph-descendants>Fix prohibited paragraph descendants</a> of each member of
+  <var title="">children</var>.
+
+  <!-- When we split the parent of a node, three things can happen.  Either the
+  node gets stuck before its parent, or after its parent, or the parent gets
+  copied and the copy gets stuck before it.  So the nodes we want to return are
+  consecutive siblings; the first is either the original first child of node or
+  its parent, and the last is either the last child of node or node itself. -->
+  <li>Let <var title="">children</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a> of <var title="">node</var>.
+
+  <li>For each <var title="">child</var> in <var title="">children</var>, if <var title="">child</var> is
+  a <a href=#prohibited-paragraph-child>prohibited paragraph child</a>, <a href=#split-the-parent>split the parent</a> of
+  the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of <var title="">child</var>.
+
+  <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 null, let <var title="">node</var> equal the
+  last member of <var title="">children</var>.
+
+  <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>Repeat these steps:
+
+  <ol>
+    <li>Prepend <var title="">node</var> to <var title="">node list</var>.
+
+    <li>If <var title="">node</var> is <var title="">children</var>'s first member, or
+    <var title="">children</var>'s first member'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>, break from this loop.
+
+    <li>Set <var title="">node</var> to 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>.
+  </ol>
+
+  <li>Return <var title="">node list</var>.
+</ol>
+
 <p>To <dfn id=indent>indent</dfn> a list <var title="">node list</var> of consecutive <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-sibling title=concept-tree-sibling>sibling</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>nodes</a>:
 <!--
@@ -3129,11 +3171,11 @@
 
 <h3 id=block-formatting-a-node-list><span class=secno>7.4 </span>Block-formatting a node list</h3>
 
-<p>To <dfn id=block-format>block-format</dfn> 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> <var title="">node list</var> to a
+<p>To <dfn id=block-format>block-format</dfn> 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> <var title="">input nodes</var> to a
 string <var title="">value</var>:
 
 <ol>
-  <li>For each <var title="">node</var> in <var title="">node list</var>, while <var title="">node</var>
+  <li>For each <var title="">node</var> in <var title="">input nodes</var>, while <var title="">node</var>
   is a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendant</a> of an <a href=#editable>editable</a> <a href=#html-element>HTML element</a>
   <a href=#in-the-same-editing-host>in the same editing host</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> "address", "h1",
   "h2", "h3", "h4", "h5", "h6", "p", or "pre", <a href=#split-the-parent>split the parent</a> of
@@ -3156,6 +3198,12 @@
   <p class=XXX>Do we need to fix disallowed ancestors later, or is this step
   enough that it's not an issue?
 
+  <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 <var title="">node</var> in <var title="">input nodes</var>, <a href=#fix-prohibited-paragraph-descendants>fix prohibited
+  paragraph descendants</a> of <var title="">node</var>, and append the resulting
+  <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> to <var title="">node list</var>.
+
   <!--
   We have two different behaviors, one for div and p and one for everything
   else.  The basic difference is that for div and p, we assume that it should
--- a/implementation.js	Tue May 31 13:31:07 2011 -0600
+++ b/implementation.js	Tue May 31 13:31:25 2011 -0600
@@ -2045,13 +2045,13 @@
 	return newRange;
 }
 
-function blockFormat(nodeList, value) {
-	// "For each node in node list, while node is a descendant of an
-	// editable HTML element in the same editing host with local name
-	// "address", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", split
-	// the parent of the one-node list consisting of node."
-	for (var i = 0; i < nodeList.length; i++) {
-		var node = nodeList[i];
+function blockFormat(inputNodes, value) {
+	// "For each node in input nodes, while node is a descendant of an editable
+	// HTML element in the same editing host with local name "address", "h1",
+	// "h2", "h3", "h4", "h5", "h6", "p", or "pre", split the parent of the
+	// one-node list consisting of node."
+	for (var i = 0; i < inputNodes.length; i++) {
+		var node = inputNodes[i];
 
 		do {
 			var ancestor = node.parentNode;
@@ -2069,6 +2069,15 @@
 		} while (true);
 	}
 
+	// "Let node list be a list of nodes, initially empty."
+	var nodeList = [];
+
+	// "For each node in input nodes, fix prohibited paragraph descendants of
+	// node, and append the resulting nodes to node list."
+	for (var i = 0; i < inputNodes.length; i++) {
+		nodeList = nodeList.concat(fixProhibitedParagraphDescendants(inputNodes[i]));
+	}
+
 	// "If value is "div" or "p", then while node list is not empty:"
 	if (value == "div" || value == "p") {
 		while (nodeList.length) {
@@ -3704,15 +3713,12 @@
 	&& !isHtmlElement(node.parentNode, ["ol", "ul"]))
 	|| (isHtmlElement(node, ["dt", "dd"])
 	&& !isHtmlElement(node.parentNode, "dl"))) {
-		// "Let children be the children of node."
-		var children = [].slice.call(node.childNodes);
-
-		// "Remove node, preserving its descendants."
-		removePreservingDescendants(node);
-
-		// "Block-format children, with value equal to the default single-line
-		// container name."
-		blockFormat(children, defaultSingleLineContainerName);
+		// "Set the tag name of node to "div", and let node be the result."
+		node = setTagName(node, "div");
+
+		// "Block-format the one-node list consisting of node, with value equal
+		// to the default single-line container name."
+		blockFormat([node], defaultSingleLineContainerName);
 
 		// "Abort these steps."
 		return;
@@ -3744,6 +3750,59 @@
 	}
 }
 
+function fixProhibitedParagraphDescendants(node) {
+	// "If node has no children, return the one-node list consisting of node."
+	if (!node.hasChildNodes()) {
+		return [node];
+	}
+
+	// "Let children be the children of node."
+	var children = [].slice.call(node.childNodes);
+
+	// "Fix prohibited paragraph descendants of each member of children."
+	for (var i = 0; i < children.length; i++) {
+		fixProhibitedParagraphDescendants(children[i]);
+	}
+
+	// "Let children be the children of node."
+	children = [].slice.call(node.childNodes);
+
+	// "For each child in children, if child is a prohibited paragraph child,
+	// split the parent of the one-node list consisting of child."
+	for (var i = 0; i < children.length; i++) {
+		if (isProhibitedParagraphChild(children[i])) {
+			splitParent([children[i]]);
+		}
+	}
+
+	// "If node's parent is null, let node equal the last member of children."
+	if (!node.parentNode) {
+		node = children[children.length - 1];
+	}
+
+	// "Let node list be a list of nodes, initially empty."
+	var nodeList = [];
+
+	// "Repeat these steps:"
+	while (true) {
+		// "Prepend node to node list."
+		nodeList.unshift(node);
+
+		// "If node is children's first member, or children's first member's
+		// parent, break from this loop."
+		if (node == children[0]
+		|| node == children[0].parentNode) {
+			break;
+		}
+
+		// "Set node to its previousSibling."
+		node = node.previousSibling;
+	}
+
+	// "Return node list."
+	return nodeList;
+}
+
 function indentNodes(nodeList) {
 	// "If node list is empty, do nothing and abort these steps."
 	if (!nodeList.length) {
--- a/source.html	Tue May 31 13:31:07 2011 -0600
+++ b/source.html	Tue May 31 13:31:25 2011 -0600
@@ -2868,12 +2868,12 @@
   [[dl]]:
 
   <ol>
-    <li>Let <var>children</var> be the [[children]] of <var>node</var>.
-
-    <li>Remove <var>node</var>, <span>preserving its descendants</span>.
-
-    <li><span>Block-format</span> <var>children</var>, with <var>value</var>
-    equal to the <span>default single-line container name</span>.
+    <li><span>Set the tag name</span> of <var>node</var> to "div", and let
+    <var>node</var> be the result.
+
+    <li><span>Block-format</span> the one-[[node]] list consisting of
+    <var>node</var>, with <var>value</var> equal to the <span>default
+    single-line container name</span>.
 
     <li>Abort these steps.
   </ol>
@@ -2887,6 +2887,48 @@
   of <var>node</var>.
 </ol>
 
+<p>To <dfn>fix prohibited paragraph descendants</dfn> of a [[node]]
+<var>node</var>:
+
+<ol>
+  <li>If <var>node</var> has no [[children]], return the one-[[node]] list
+  consisting of <var>node</var>.
+
+  <li>Let <var>children</var> be the [[children]] of <var>node</var>.
+
+  <li><span>Fix prohibited paragraph descendants</span> of each member of
+  <var>children</var>.
+
+  <!-- When we split the parent of a node, three things can happen.  Either the
+  node gets stuck before its parent, or after its parent, or the parent gets
+  copied and the copy gets stuck before it.  So the nodes we want to return are
+  consecutive siblings; the first is either the original first child of node or
+  its parent, and the last is either the last child of node or node itself. -->
+  <li>Let <var>children</var> be the [[children]] of <var>node</var>.
+
+  <li>For each <var>child</var> in <var>children</var>, if <var>child</var> is
+  a <span>prohibited paragraph child</span>, <span>split the parent</span> of
+  the one-[[node]] list consisting of <var>child</var>.
+
+  <li>If <var>node</var>'s [[parent]] is null, let <var>node</var> equal the
+  last member of <var>children</var>.
+
+  <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
+
+  <li>Repeat these steps:
+
+  <ol>
+    <li>Prepend <var>node</var> to <var>node list</var>.
+
+    <li>If <var>node</var> is <var>children</var>'s first member, or
+    <var>children</var>'s first member's [[parent]], break from this loop.
+
+    <li>Set <var>node</var> to its [[previoussibling]].
+  </ol>
+
+  <li>Return <var>node list</var>.
+</ol>
+
 <p>To <dfn>indent</dfn> a list <var>node list</var> of consecutive [[sibling]]
 [[nodes]]:
 <!--
@@ -3137,11 +3179,11 @@
 
 <h3>Block-formatting a node list</h3>
 
-<p>To <dfn>block-format</dfn> a list of [[nodes]] <var>node list</var> to a
+<p>To <dfn>block-format</dfn> a list of [[nodes]] <var>input nodes</var> to a
 string <var>value</var>:
 
 <ol>
-  <li>For each <var>node</var> in <var>node list</var>, while <var>node</var>
+  <li>For each <var>node</var> in <var>input nodes</var>, while <var>node</var>
   is a [[descendant]] of an <span>editable</span> <span>HTML element</span>
   <span>in the same editing host</span> with [[localname]] "address", "h1",
   "h2", "h3", "h4", "h5", "h6", "p", or "pre", <span>split the parent</span> of
@@ -3164,6 +3206,12 @@
   <p class=XXX>Do we need to fix disallowed ancestors later, or is this step
   enough that it's not an issue?
 
+  <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
+
+  <li>For each <var>node</var> in <var>input nodes</var>, <span>fix prohibited
+  paragraph descendants</span> of <var>node</var>, and append the resulting
+  [[nodes]] to <var>node list</var>.
+
   <!--
   We have two different behaviors, one for div and p and one for everything
   else.  The basic difference is that for div and p, we assume that it should