Improve delete line-break handling
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Tue, 07 Jun 2011 14:19:06 -0600
changeset 250 2f6bc0e1d5e0
parent 249 6a1817dbf0eb
child 251 1ce2c6a84a33
Improve delete line-break handling

Now we correctly handle stuff like <p>foo<br>{</p><p>}bar</p> (becomes
<p>foo{}bar</p> not <p>foo<br>{}bar</p>). Previously I ignored that
case because such selections normally can't be created, but it turns out
that handling it right simplifies the delete command proper.

This fixed bugs where a <br> would be incorrectly deleted even though
the blocks weren't merged, like running the delete command on
<table><tr>foo<br><br></table>[]bar.
editcommands.html
implementation.js
source.html
tests.js
--- a/editcommands.html	Tue Jun 07 13:51:26 2011 -0600
+++ b/editcommands.html	Tue Jun 07 14:19:06 2011 -0600
@@ -1317,6 +1317,10 @@
     <li>While <var title="">reference node</var> is not 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> of <var title="">end
     block</var>, set <var title="">reference 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>.
 
+    <li>If <var title="">reference 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 an <a href=#inline-node>inline
+    node</a> and <var title="">start block</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 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>, remove
+    <var title="">start block</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> from it.
+
     <li>While 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="">reference node</var> is neither null
     nor 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> nor a <a href=#prohibited-paragraph-child>prohibited paragraph child</a>, append 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="">reference 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
@@ -1334,6 +1338,10 @@
     <li>Set the <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 <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> of <var title="">range</var> to
     (<var title="">start block</var>, <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 block</var>).
 
+    <li>If <var title="">end block</var>'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 block</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 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>, remove <var title="">start
+    block</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> from it.
+
     <li>While <var title="">end block</var> has <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>, append 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="">end block</var> to <var title="">start block</var>, <a href=#preserving-ranges>preserving
     ranges</a>.
@@ -2607,21 +2615,6 @@
     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>If <var title="">start node</var> is a <a href=#prohibited-paragraph-child>prohibited paragraph child</a>
-    whose 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> 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>, and <var title="">start offset</var> is 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>, subtract one from <var title="">start
-    offset</var>.
-    <!--
-    It wouldn't be enough to just remove extraneous line breaks at the end of
-    start node, because we want to remove the line break even if it's not
-    actually extraneous.  For instance,
-
-      <p>foo<br><br></p><p>[]bar</p>
-      -> <p>foo<br>bar</p>
-      not
-      -> <p>foo<br><br>bar</p>.
-    -->
-
     <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>).
@@ -2642,9 +2635,6 @@
     <li>Let <var title="">start offset</var> be 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>If <var title="">start node</var>'s 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> 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>, subtract one
-    from <var title="">start offset</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>).
--- a/implementation.js	Tue Jun 07 13:51:26 2011 -0600
+++ b/implementation.js	Tue Jun 07 14:19:06 2011 -0600
@@ -1135,6 +1135,13 @@
 			referenceNode = referenceNode.parentNode;
 		}
 
+		// "If reference node's nextSibling is an inline node and start block's
+		// lastChild is a br, remove start block's lastChild from it."
+		if (isInlineNode(referenceNode.nextSibling)
+		&& isHtmlElement(startBlock.lastChild, "br")) {
+			startBlock.removeChild(startBlock.lastChild);
+		}
+
 		// "While the nextSibling of reference node is neither null nor a br
 		// nor a prohibited paragraph child, append the nextSibling of
 		// reference node as the last child of start block, preserving ranges."
@@ -1157,6 +1164,13 @@
 		range.setStart(startBlock, getNodeLength(startBlock));
 		range.setEnd(startBlock, getNodeLength(startBlock));
 
+		// "If end block's firstChild is an inline node and start block's
+		// lastChild is a br, remove start block's lastChild from it."
+		if (isInlineNode(endBlock.firstChild)
+		&& isHtmlElement(startBlock.lastChild, "br")) {
+			startBlock.removeChild(startBlock.lastChild);
+		}
+
 		// "While end block has children, append the first child of end block
 		// to start block, preserving ranges."
 		while (endBlock.hasChildNodes()) {
@@ -3315,15 +3329,6 @@
 				startOffset = getNodeLength(startNode);
 			}
 
-			// "If start node is a prohibited paragraph child whose last child
-			// is a br, and start offset is the length of start node, subtract
-			// one from start offset."
-			if (isProhibitedParagraphChild(startNode)
-			&& isHtmlElement(startNode.lastChild, "br")
-			&& startOffset == getNodeLength(startNode)) {
-				startOffset--;
-			}
-
 			// "Delete the contents of the range with start (start node, start
 			// offset) and end (node, offset)."
 			deleteContents(startNode, startOffset, node, offset);
@@ -3349,12 +3354,6 @@
 			// "Let start offset be the length of start node."
 			var startOffset = getNodeLength(startNode);
 
-			// "If start node's last child is a br, subtract one from start
-			// offset."
-			if (isHtmlElement(startNode.lastChild, "br")) {
-				startOffset--;
-			}
-
 			// "Delete the contents of the range with start (start node, start
 			// offset) and end (node, offset)."
 			deleteContents(startNode, startOffset, node, offset);
--- a/source.html	Tue Jun 07 13:51:26 2011 -0600
+++ b/source.html	Tue Jun 07 14:19:06 2011 -0600
@@ -1274,6 +1274,10 @@
     <li>While <var>reference node</var> is not a [[child]] of <var>end
     block</var>, set <var>reference node</var> to its [[parent]].
 
+    <li>If <var>reference node</var>'s [[nextsibling]] is an <span>inline
+    node</span> and <var>start block</var>'s [[lastchild]] is a [[br]], remove
+    <var>start block</var>'s [[lastchild]] from it.
+
     <li>While the [[nextsibling]] of <var>reference node</var> is neither null
     nor a [[br]] nor a <span>prohibited paragraph child</span>, append the
     [[nextsibling]] of <var>reference node</var> as the last [[child]] of
@@ -1291,6 +1295,10 @@
     <li>Set the [[rangestart]] and [[rangeend]] of <var>range</var> to
     (<var>start block</var>, [[nodelength]] of <var>start block</var>).
 
+    <li>If <var>end block</var>'s [[firstchild]] is an <span>inline node</span>
+    and <var>start block</var>'s [[lastchild]] is a [[br]], remove <var>start
+    block</var>'s [[lastchild]] from it.
+
     <li>While <var>end block</var> has [[children]], append the first [[child]]
     of <var>end block</var> to <var>start block</var>, <span>preserving
     ranges</span>.
@@ -2588,21 +2596,6 @@
     then set <var>start offset</var> to the [[nodelength]] of <var>start
     node</var>.
 
-    <li>If <var>start node</var> is a <span>prohibited paragraph child</span>
-    whose last [[child]] is a [[br]], and <var>start offset</var> is the
-    [[nodelength]] of <var>start node</var>, subtract one from <var>start
-    offset</var>.
-    <!--
-    It wouldn't be enough to just remove extraneous line breaks at the end of
-    start node, because we want to remove the line break even if it's not
-    actually extraneous.  For instance,
-
-      <p>foo<br><br></p><p>[]bar</p>
-      -> <p>foo<br>bar</p>
-      not
-      -> <p>foo<br><br>bar</p>.
-    -->
-
     <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>).
@@ -2623,9 +2616,6 @@
     <li>Let <var>start offset</var> be the [[nodelength]] of <var>start
     node</var>.
 
-    <li>If <var>start node</var>'s last [[child]] is a [[br]], subtract one
-    from <var>start offset</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>).
--- a/tests.js	Tue Jun 07 13:51:26 2011 -0600
+++ b/tests.js	Tue Jun 07 14:19:06 2011 -0600
@@ -343,6 +343,13 @@
 		'<div><p>foo</p>bar[</div>]baz',
 		'<div>foo<p>bar[</p></div>]baz',
 
+		'<p>foo<br>{</p>]bar',
+		'<p>foo<br><br>{</p>]bar',
+		'foo<br>{<p>]bar</p>',
+		'foo<br><br>{<p>]bar</p>',
+		'<p>foo<br>{</p><p>}bar</p>',
+		'<p>foo<br><br>{</p><p>}bar</p>',
+
 		'<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>',
 		'<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>',
 		'<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>',