Make insertParagraph work right for headers
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Sun, 29 May 2011 13:43:27 -0600
changeset 182 9447ac9f919c
parent 181 82126988dd3f
child 183 c879b966938b
Make insertParagraph work right for headers
autoimplementation.html
editcommands.html
implementation.js
source.html
--- a/autoimplementation.html	Sun May 29 13:07:20 2011 -0600
+++ b/autoimplementation.html	Sun May 29 13:43:27 2011 -0600
@@ -1125,30 +1125,39 @@
 
 		'[]foo',
 		'foo[]',
+		'foo[]<br>',
 		'foo[]bar',
 		'<address>[]foo</address>',
 		'<address>foo[]</address>',
+		'<address>foo[]<br></address>',
 		'<address>foo[]bar</address>',
 		'<div>[]foo</div>',
 		'<div>foo[]</div>',
+		'<div>foo[]<br></div>',
 		'<div>foo[]bar</div>',
 		'<dl><dt>[]foo<dd>bar</dl>',
 		'<dl><dt>foo[]<dd>bar</dl>',
+		'<dl><dt>foo[]<br><dd>bar</dl>',
 		'<dl><dt>foo[]bar<dd>baz</dl>',
 		'<dl><dt>foo<dd>[]bar</dl>',
 		'<dl><dt>foo<dd>bar[]</dl>',
+		'<dl><dt>foo<dd>bar[]<br></dl>',
 		'<dl><dt>foo<dd>bar[]baz</dl>',
 		'<h1>[]foo</h1>',
 		'<h1>foo[]</h1>',
+		'<h1>foo[]<br></h1>',
 		'<h1>foo[]bar</h1>',
 		'<ol><li>[]foo</ol>',
 		'<ol><li>foo[]</ol>',
+		'<ol><li>foo[]<br></ol>',
 		'<ol><li>foo[]bar</ol>',
 		'<p>[]foo</p>',
 		'<p>foo[]</p>',
+		'<p>foo[]<br></p>',
 		'<p>foo[]bar</p>',
 		'<pre>[]foo</pre>',
 		'<pre>foo[]</pre>',
+		'<pre>foo[]<br></pre>',
 		'<pre>foo[]bar</pre>',
 
 		'<ol><li>foo<li>{}<br></ol>',
--- a/editcommands.html	Sun May 29 13:07:20 2011 -0600
+++ b/editcommands.html	Sun May 29 13:43:27 2011 -0600
@@ -4210,6 +4210,10 @@
   if a pre element has newlines in it, do they convert to line breaks when you
   make it no longer a pre?
 
+  <p class=XXX>In cases where hitting enter in a header doesn't break out of
+  the header, we should probably follow this code path too, instead of creating
+  an adjoining header.  No browser does this, though.
+
   <ol>
     <li>Let <var title="">br</var> be the result of calling <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>.
@@ -4229,18 +4233,31 @@
     <li>Abort these steps.
   </ol>
 
-  <li>Let <var title="">new container</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Node-cloneNode><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-clonenode>cloneNode(false)</a></code> on
+  <li>Let <var title="">new line range</var> be a new <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a> whose <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> is
+  the same as <var title="">range</var>'s, and whose <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> is
+  (<var title="">container</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="">container</var>).
+
+  <li>If 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 <var title="">container</var> is "h1", "h2", "h3", "h4",
+  "h5", or "h6", and <var title="">new line range</var> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained title=contained>contains</a> either nothing or a single <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, let
+  <var title="">new container name</var> be the <a href=#default-single-line-container-name>default single-line container
+  name</a>.
+  <!-- IE9 makes a new header if there's a trailing <br>.  Firefox 5.0a2,
+  Chrome 13 dev, and Opera 11.10 do not, and I follow them, since it makes more
+  sense (such a <br> is invisible). -->
+
+  <li>Otherwise, let <var title="">new container name</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
   <var title="">container</var>.
 
+  <li>Let <var title="">new container</var> be the result of calling
+  <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(<var title="">new container name</var>)</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.
+
+  <li>Copy all attributes of <var title="">container</var> to <var title="">new container</var>.
+
   <p class=XXX>Copies id's.
 
   <li>Insert <var title="">new container</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="">container</var> immediately after <var title="">container</var>.
 
-  <li>Let <var title="">new line range</var> be a new <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a> whose <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> is
-  the same as <var title="">range</var>'s, and whose <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> is
-  (<var title="">container</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="">container</var>).
-
   <li>Let <var title="">frag</var> be the result of calling <code class=external data-anolis-spec=domrange title=dom-Range-extractContents><a href=http://html5.org/specs/dom-range.html#dom-range-extractcontents>extractContents()</a></code> on <var title="">new line
   range</var>.
 
--- a/implementation.js	Sun May 29 13:07:20 2011 -0600
+++ b/implementation.js	Sun May 29 13:43:27 2011 -0600
@@ -307,6 +307,9 @@
  * for, omitting any with an ancestor already being returned.
  */
 function collectContainedNodes(range, condition) {
+	if (typeof condition == "undefined") {
+		condition = function() { return true };
+	}
 	var node = range.startContainer;
 	if (node.hasChildNodes()
 	&& range.startOffset < node.childNodes.length) {
@@ -693,7 +696,7 @@
 	// length, and either range's end node is not a Text or Comment node or
 	// range's end offset is 0, call deleteContents() on range and abort these
 	// steps."
-	if (!collectContainedNodes(range, function() { return true }).length
+	if (!collectContainedNodes(range).length
 	&& ((range.startContainer.nodeType != Node.TEXT_NODE
 	&& range.startContainer.nodeType != Node.COMMENT_NODE)
 	|| range.startOffset == getNodeLength(range.startContainer))
@@ -3281,20 +3284,43 @@
 			return;
 		}
 
-		// "Let new container be the result of calling cloneNode(false) on
-		// container."
-		var newContainer = container.cloneNode(false);
-
-		// "Insert new container into the parent of container immediately after
-		// container."
-		container.parentNode.insertBefore(newContainer, container.nextSibling);
-
 		// "Let new line range be a new range whose start is the same as
 		// range's, and whose end is (container, length of container)."
 		var newLineRange = document.createRange();
 		newLineRange.setStart(range.startContainer, range.startOffset);
 		newLineRange.setEnd(container, getNodeLength(container));
 
+		// "If the local name of container is "h1", "h2", "h3", "h4", "h5", or
+		// "h6", and new line range contains either nothing or a single br, let
+		// new container name be the default single-line container name."
+		var newContainerName;
+		var containedInNewLineRange = collectContainedNodes(newLineRange);
+		if (/^H[1-6]$/.test(container.tagName)
+		&& (!containedInNewLineRange.length
+			|| (containedInNewLineRange.length == 1
+				&& isHtmlElement(containedInNewLineRange[0], "br")
+			)
+		)) {
+			newContainerName = defaultSingleLineContainerName;
+
+		// "Otherwise, let new container name be the local name of container."
+		} else {
+			newContainerName = container.tagName.toLowerCase();
+		}
+
+		// "Let new container be the result of calling createElement(new
+		// container name) on the context object."
+		var newContainer = document.createElement(newContainerName);
+
+		// "Copy all attributes of container to new container."
+		for (var i = 0; i < container.attributes.length; i++) {
+			newContainer.setAttributeNS(container.attributes[i].namespaceURI, container.attributes[i].name, container.attributes[i].value);
+		}
+
+		// "Insert new container into the parent of container immediately after
+		// container."
+		container.parentNode.insertBefore(newContainer, container.nextSibling);
+
 		// "Let frag be the result of calling extractContents() on new line
 		// range."
 		var frag = newLineRange.extractContents();
--- a/source.html	Sun May 29 13:07:20 2011 -0600
+++ b/source.html	Sun May 29 13:43:27 2011 -0600
@@ -4245,6 +4245,10 @@
   if a pre element has newlines in it, do they convert to line breaks when you
   make it no longer a pre?
 
+  <p class=XXX>In cases where hitting enter in a header doesn't break out of
+  the header, we should probably follow this code path too, instead of creating
+  an adjoining header.  No browser does this, though.
+
   <ol>
     <li>Let <var>br</var> be the result of calling [[createelement|"br"]] on
     the [[contextobject]].
@@ -4264,19 +4268,32 @@
     <li>Abort these steps.
   </ol>
 
-  <li>Let <var>new container</var> be the result of calling <code
-  data-anolis-spec=domcore title=dom-Node-cloneNode>cloneNode(false)</code> on
+  <li>Let <var>new line range</var> be a new [[range]] whose [[rangestart]] is
+  the same as <var>range</var>'s, and whose [[rangeend]] is
+  (<var>container</var>, [[nodelength]] of <var>container</var>).
+
+  <li>If the [[localname]] of <var>container</var> is "h1", "h2", "h3", "h4",
+  "h5", or "h6", and <var>new line range</var> <span data-anolis-spec=domrange
+  title=contained>contains</span> either nothing or a single [[br]], let
+  <var>new container name</var> be the <span>default single-line container
+  name</span>.
+  <!-- IE9 makes a new header if there's a trailing <br>.  Firefox 5.0a2,
+  Chrome 13 dev, and Opera 11.10 do not, and I follow them, since it makes more
+  sense (such a <br> is invisible). -->
+
+  <li>Otherwise, let <var>new container name</var> be the [[localname]] of
   <var>container</var>.
 
+  <li>Let <var>new container</var> be the result of calling
+  [[createelement|<var>new container name</var>]] on the [[contextobject]].
+
+  <li>Copy all attributes of <var>container</var> to <var>new container</var>.
+
   <p class=XXX>Copies id's.
 
   <li>Insert <var>new container</var> into the [[parent]] of
   <var>container</var> immediately after <var>container</var>.
 
-  <li>Let <var>new line range</var> be a new [[range]] whose [[rangestart]] is
-  the same as <var>range</var>'s, and whose [[rangeend]] is
-  (<var>container</var>, [[nodelength]] of <var>container</var>).
-
   <li>Let <var>frag</var> be the result of calling <code
   data-anolis-spec=domrange
   title=dom-Range-extractContents>extractContents()</code> on <var>new line