--- a/autoimplementation.html Wed May 25 08:59:52 2011 -0600
+++ b/autoimplementation.html Wed May 25 10:18:04 2011 -0600
@@ -644,9 +644,45 @@
['<p>', '<h1>[foo]<br>bar</h1>'],
['<p>', '<h1>foo<br>[bar]</h1>'],
['<p>', '<h1>[foo<br>bar]</h1>'],
+ ['<address>', '<h1>[foo]<br>bar</h1>'],
+ ['<address>', '<h1>foo<br>[bar]</h1>'],
+ ['<address>', '<h1>[foo<br>bar]</h1>'],
+ ['<pre>', '<h1>[foo]<br>bar</h1>'],
+ ['<pre>', '<h1>foo<br>[bar]</h1>'],
+ ['<pre>', '<h1>[foo<br>bar]</h1>'],
+ ['<h2>', '<h1>[foo]<br>bar</h1>'],
+ ['<h2>', '<h1>foo<br>[bar]</h1>'],
+ ['<h2>', '<h1>[foo<br>bar]</h1>'],
+
['<h1>', '<p>[foo]<br>bar</p>'],
['<h1>', '<p>foo<br>[bar]</p>'],
['<h1>', '<p>[foo<br>bar]</p>'],
+ ['<address>', '<p>[foo]<br>bar</p>'],
+ ['<address>', '<p>foo<br>[bar]</p>'],
+ ['<address>', '<p>[foo<br>bar]</p>'],
+ ['<pre>', '<p>[foo]<br>bar</p>'],
+ ['<pre>', '<p>foo<br>[bar]</p>'],
+ ['<pre>', '<p>[foo<br>bar]</p>'],
+
+ ['<p>', '<address>[foo]<br>bar</address>'],
+ ['<p>', '<address>foo<br>[bar]</address>'],
+ ['<p>', '<address>[foo<br>bar]</address>'],
+ ['<pre>', '<address>[foo]<br>bar</address>'],
+ ['<pre>', '<address>foo<br>[bar]</address>'],
+ ['<pre>', '<address>[foo<br>bar]</address>'],
+ ['<h1>', '<address>[foo]<br>bar</address>'],
+ ['<h1>', '<address>foo<br>[bar]</address>'],
+ ['<h1>', '<address>[foo<br>bar]</address>'],
+
+ ['<p>', '<pre>[foo]<br>bar</pre>'],
+ ['<p>', '<pre>foo<br>[bar]</pre>'],
+ ['<p>', '<pre>[foo<br>bar]</pre>'],
+ ['<address>', '<pre>[foo]<br>bar</pre>'],
+ ['<address>', '<pre>foo<br>[bar]</pre>'],
+ ['<address>', '<pre>[foo<br>bar]</pre>'],
+ ['<h1>', '<pre>[foo]<br>bar</pre>'],
+ ['<h1>', '<pre>foo<br>[bar]</pre>'],
+ ['<h1>', '<pre>[foo<br>bar]</pre>'],
],
hilitecolor: [
'foo[]bar',
--- a/editcommands.html Wed May 25 08:59:52 2011 -0600
+++ b/editcommands.html Wed May 25 10:18:04 2011 -0600
@@ -293,6 +293,43 @@
editable, so authors are assured that editing commands will only modify the
editing host's contents and not the editing host itself.
+<p>The <dfn id=editing-host-of>editing host of</dfn> <var title="">node</var> is null if <var title="">node</var> is
+neither <a href=#editable>editable</a> nor an <a href=#editing-host>editing host</a>; <var title="">node</var>
+itself, if <var title="">node</var> is an <a href=#editing-host>editing host</a>; or the nearest
+<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> that is an <a href=#editing-host>editing host</a>, if
+<var title="">node</var> is <a href=#editable>editable</a>.
+
+<p>Two <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> are <dfn id=in-the-same-editing-host>in the same editing host</dfn> if both are
+<a href=#editable>editable</a> and the <a href=#editing-host-of>editing host of</a> both is the same.
+
+<p>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="">child</var> is an <dfn id=allowed-child>allowed child</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="">parent</var> unless one of the following conditions is met:
+
+<p class=XXX>This is very ad hoc and might need to be rethought. We can't use
+the HTML spec's definitions because those are too complicated, they don't take
+obsolete elements into account, and they're sometimes too restrictive. (We
+don't like having to contort the DOM to ensure that it's valid, because it can
+have unwanted side effects, so we want to minimize the number of cases we
+disallow.) Mostly this list covers only things that don't serialize as
+text/html.
+
+<ul>
+ <li><var title="">child</var> is an <code class=external data-anolis-spec=html title="the a element"><a href=http://www.whatwg.org/html/#the-a-element>a</a></code>, and <var title="">parent</var> or 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="">parent</var> is an <code class=external data-anolis-spec=html title="the a element"><a href=http://www.whatwg.org/html/#the-a-element>a</a></code>. <!-- Cannot be serialized as text/html.
+ -->
+
+ <li><var title="">child</var> is an <a href=#html-element>HTML element</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", "article", "aside", "blockquote", "center", "details", "dir",
+ "div", "dl", "fieldset", "figcaption", "figure", "footer", "h1", "h2", "h3",
+ "h4", "h5", "h6", "header", "hgroup", "hr", "listing", "menu", "nav", "ol",
+ "p", "plaintext", "pre", "section", "summary", "table", "ul", or "xmp"; and
+ <var title="">parent</var> or 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="">parent</var> is an <a href=#html-element>HTML
+ element</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> "h1", "h2", "h3", "h4", "h5", "h6", or "p".
+ <!-- This cannot be serialized as text/html if the parent is a p, or if the
+ parent and child are both h*. Something like <h1>foo<p>bar</p></h1> will
+ actually work, but while we're here, we may as well disallow it. -->
+</ul>
+
<p>The <dfn id=css-styling-flag>CSS styling flag</dfn> is a boolean flag, which must initially be
false.
@@ -341,13 +378,14 @@
<li>Return <var title="">replacement element</var>.
</ol>
-<p>To remove 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> while <dfn id=preserving-its-descendants>preserving its
-descendants</dfn>, <a href=#split-the-parent>split the parent</a> of <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-child title=concept-tree-child>children</a>.
-
<p>To <dfn id=split-the-parent>split the parent</dfn> of 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>:
+<p class=XXX>Pretty much any time we call this algorithm, it can cause trouble
+if the parent had styles, classes, etc. There's not going to be any general
+way to handle this, but we should at least try to handle the special case of
+inline styles, because Firefox does actually add them to arbitrary elements.
+
<ol>
<li>Let <var title="">original parent</var> be 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 the first member of
<var title="">node list</var>.
@@ -360,18 +398,12 @@
parent</var>.
<li>If 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="">original parent</var> is in <var title="">node
- list</var>:
-
- <ol>
- <li><a href=#remove-extraneous-line-breaks-after>Remove extraneous line breaks after</a> <var title="">original
- parent</var>.
-
- <li>If <var title="">original parent</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> and <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> are
- both <a href=#inline-node title="inline node">inline nodes</a>, call <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
- <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">original parent</var>, then insert the result
- 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="">original parent</var> immediately after
- <var title="">original parent</var>.
- </ol>
+ list</var>, and <var title="">original parent</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> and
+ <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> are both <a href=#inline-node title="inline node">inline nodes</a>, call
+ <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
+ <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">original parent</var>, then insert the result 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="">original parent</var> immediately after <var title="">original
+ parent</var>.
<li>If 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="">original parent</var> is not in <var title="">node
list</var>, but its 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:
@@ -402,6 +434,9 @@
parent</var> immediately after <var title="">original parent</var>, <a href=#preserving-ranges>preserving
ranges</a>.
+ <li><a href=#remove-extraneous-line-breaks-at-the-end-of>Remove extraneous line breaks at the end of</a> <var title="">original
+ parent</var>.
+
<li>Abort these steps.
</ol>
@@ -439,10 +474,19 @@
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="">original parent</var> immediately before
<var title="">original parent</var>, <a href=#preserving-ranges>preserving ranges</a>.
+ <li>If the last member of <var title="">node list</var> is an <a href=#inline-node>inline node</a>
+ other than 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 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="">original parent</var> 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 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="">original parent</var> from
+ <var title="">original parent</var>.
+
<li>If <var title="">original parent</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>, remove it from 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>.
</ol>
+<p>To remove 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> while <dfn id=preserving-its-descendants>preserving its
+descendants</dfn>, <a href=#split-the-parent>split the parent</a> of <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-child title=concept-tree-child>children</a>.
+
<p>To <dfn id=wrap>wrap</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>, given <dfn id=sibling-criteria>sibling criteria</dfn> and <dfn id=new-parent-instructions>new parent
instructions</dfn>:
@@ -467,11 +511,9 @@
<li>If <var title="">new 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 null:
<ol>
- <li>If <var title="">new parent</var> cannot 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 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
- the first member of <var title="">node list</var>, <a href=#split-the-parent>split the parent</a> of
- <var title="">node list</var>.
-
- <p class=XXX>"Cannot be the child" needs to be defined.
+ <li>While <var title="">new parent</var> is not an <a href=#allowed-child>allowed child</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 the first member of <var title="">node list</var>, <a href=#split-the-parent>split the
+ parent</a> of <var title="">node list</var>.
<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 the first member of
<var title="">node list</var> immediately before the first member of <var title="">node
@@ -555,7 +597,7 @@
of <var title="">node</var> from 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>.
</ol>
-<p>To <dfn id=remove-extraneous-line-breaks-after>remove extraneous line breaks after</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>
+<p>To <dfn id=remove-extraneous-line-breaks-at-the-end-of>remove extraneous line breaks at the end of</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>
@@ -569,8 +611,8 @@
</ol>
<p>To <dfn id=remove-extraneous-line-breaks-from>remove extraneous line breaks from</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>, first
-<a href=#remove-extraneous-line-breaks-before>remove extraneous line breaks before</a> it, then <a href=#remove-extraneous-line-breaks-after>remove
-extraneous line breaks after</a> it.
+<a href=#remove-extraneous-line-breaks-before>remove extraneous line breaks before</a> it, then <a href=#remove-extraneous-line-breaks-at-the-end-of>remove
+extraneous line breaks at the end of</a> it.
<p>To move 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> to a new location, <dfn id=preserving-ranges>preserving ranges</dfn>, remove
the <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> from its original <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> (if any), then insert it in the new
@@ -3549,6 +3591,26 @@
"header", "hgroup", "li", "nav", "ol", "section", "table", "tbody", "td",
"th", "thead", "tr", or "ul".
+ <li>For each <var title="">node</var> in <var title="">node list</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=#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 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
+ consistin of <var title="">node</var>.
+
+ <div class=XXX>
+ <p>This is needed so we don't get things like p nested inside address, and
+ instead convert part of the multi-line address into a p. But div can contain
+ any of these things, so we don't break that apart ever, which is bad. It
+ means if you have
+
+ </p><xmp><div>foo<br>bar</div></xmp>
+
+ <p>then formatBlocking "foo" then "bar" as p has different results from doing
+ both at once. Maybe we should split divs as well, but only if they're the
+ parent of the node we're dealing with? Or just split divs always, and hope
+ the "in the same editing host" thing handles it?
+ </div>
+
<!--
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 Wed May 25 08:59:52 2011 -0600
+++ b/implementation.js Wed May 25 10:18:04 2011 -0600
@@ -443,12 +443,6 @@
return replacementElement;
}
-// "To remove a node node while preserving its descendants, split the parent of
-// node's children."
-function removePreservingDescendants(node) {
- splitParent([].slice.call(node.childNodes));
-}
-
function splitParent(nodeList) {
// "Let original parent be the parent of the first member of node list."
var originalParent = nodeList[0].parentNode;
@@ -466,19 +460,15 @@
removeExtraneousLineBreaksBefore(originalParent);
}
- // "If the last child of original parent is in node list:"
- if (nodeList.indexOf(originalParent.lastChild) != -1) {
- // "Remove extraneous line breaks after original parent."
- removeExtraneousLineBreaksAfter(originalParent);
-
- // "If original parent's last child and nextSibling are both inline
- // nodes, call createElement("br") on the ownerDocument of original
- // parent, then insert the result into the parent of original parent
- // immediately after original parent."
- if (isInlineNode(originalParent.lastChild)
- && isInlineNode(originalParent.nextSibling)) {
- originalParent.parentNode.insertBefore(originalParent.ownerDocument.createElement("br"), originalParent.nextSibling);
- }
+ // "If the last child of original parent is in node list, and original
+ // parent's last child and nextSibling are both inline nodes, call
+ // createElement("br") on the ownerDocument of original parent, then insert
+ // the result into the parent of original parent immediately after original
+ // parent."
+ if (nodeList.indexOf(originalParent.lastChild) != -1
+ && isInlineNode(originalParent.lastChild)
+ && isInlineNode(originalParent.nextSibling)) {
+ originalParent.parentNode.insertBefore(originalParent.ownerDocument.createElement("br"), originalParent.nextSibling);
}
// "If the first child of original parent is not in node list, but its last
@@ -492,6 +482,9 @@
movePreservingRanges(nodeList[i], originalParent.parentNode, 1 + getNodeIndex(originalParent));
}
+ // "Remove extraneous line breaks at the end of original parent."
+ removeExtraneousLineBreaksAtTheEndOf(originalParent);
+
// "Abort these steps."
return;
}
@@ -529,12 +522,27 @@
movePreservingRanges(nodeList[i], originalParent.parentNode, getNodeIndex(originalParent));
}
+ // "If the last member of node list is an inline node other than a br, and
+ // the first child of original parent is a br, remove the first child of
+ // original parent from original parent."
+ if (isInlineNode(nodeList[nodeList.length - 1])
+ && !isHtmlElement(nodeList[nodeList.length - 1])
+ && isHtmlElement(originalParent.firstChild, "BR")) {
+ originalParent.removeChild(originalParent.firstChild);
+ }
+
// "If original parent has no children, remove it from its parent."
if (!originalParent.hasChildNodes()) {
originalParent.parentNode.removeChild(originalParent);
}
}
+// "To remove a node node while preserving its descendants, split the parent of
+// node's children."
+function removePreservingDescendants(node) {
+ splitParent([].slice.call(node.childNodes));
+}
+
function wrap(nodeList, siblingCriteria, newParentInstructions) {
// "If node list is empty, or the first member of node list is not
// editable, return null and abort these steps."
@@ -566,11 +574,9 @@
// "If new parent's parent is null:"
if (!newParent.parentNode) {
- // "If new parent cannot be the child of the parent of the first member
- // of node list, split the parent of node list."
- //
- // Hack for now, as usual. Don't use this for inline elements!
- if (isHtmlElement(nodeList[0].parentNode, "P")) {
+ // "While new parent is not an allowed child of the parent of the first
+ // member of node list, split the parent of node list."
+ while (!isAllowedChild(newParent, nodeList[0].parentNode)) {
splitParent(nodeList);
}
@@ -675,7 +681,7 @@
}
}
-function removeExtraneousLineBreaksAfter(node) {
+function removeExtraneousLineBreaksAtTheEndOf(node) {
// "If node is not an Element, or it is an inline node, do nothing and
// abort these steps."
if (!node
@@ -696,10 +702,10 @@
}
// "To remove extraneous line breaks from a node, first remove extraneous line
-// breaks before it, then remove extraneous line breaks after it."
+// breaks before it, then remove extraneous line breaks at the end of it."
function removeExtraneousLineBreaksFrom(node) {
removeExtraneousLineBreaksBefore(node);
- removeExtraneousLineBreaksAfter(node);
+ removeExtraneousLineBreaksAtTheEndOf(node);
}
// "An editing host is a node that is either an Element with a contenteditable
@@ -726,6 +732,70 @@
&& (isEditingHost(node.parentNode) || isEditable(node.parentNode));
}
+// "The editing host of node is null if node is neither editable nor an editing
+// host; node itself, if node is an editing host; or the nearest ancestor of
+// node that is an editing host, if node is editable."
+function getEditingHostOf(node) {
+ if (isEditingHost(node)) {
+ return node;
+ } else if (isEditable(node)) {
+ var ancestor = node.parentNode;
+ while (!isEditingHost(ancestor)) {
+ ancestor = ancestor.parentNode;
+ }
+ return ancestor;
+ } else {
+ return null;
+ }
+}
+
+// "Two nodes are in the same editing host if both are editable and the editing
+// host of both is the same."
+function inSameEditingHost(node1, node2) {
+ return isEditable(node1)
+ && isEditable(node2)
+ && getEditingHostOf(node1) == getEditingHostOf(node2);
+}
+
+// "A node child is an allowed child of a node parent unless one of the
+// following conditions is met:
+//
+// * "child is an a, and parent or some ancestor of parent is an a.
+// * "child is an HTML element with local name "address", "article", "aside",
+// "blockquote", "center", "details", "dir", "div", "dl", "fieldset",
+// "figcaption", "figure", "footer", "h1", "h2", "h3", "h4", "h5", "h6",
+// "header", "hgroup", "hr", "listing", "menu", "nav", "ol", "p",
+// "plaintext", "pre", "section", "summary", "table", "ul", or "xmp"; and
+// parent or some ancestor of parent is an HTML element with local name
+// "h1", "h2", "h3", "h4", "h5", "h6", or "p"."
+function isAllowedChild(child, parent_) {
+ if (isHtmlElement(child, "A")) {
+ var ancestor = parent_;
+ while (ancestor && !isHtmlElement(ancestor, "A")) {
+ ancestor = ancestor.parentNode;
+ }
+ if (isHtmlElement(ancestor, "A")) {
+ return false;
+ }
+ }
+
+ if (isHtmlElement(child, ["ADDRESS", "ARTICLE", "ASIDE", "BLOCKQUOTE",
+ "CENTER", "DETAILS", "DIR", "DIV", "DL", "FIELDSET", "FIGCAPTION",
+ "FIGURE", "FOOTER", "H1", "H2", "H3", "H4", "H5", "H6", "HEADER", "HGROUP",
+ "HR", "LISTING", "MENU", "NAV", "OL", "P", "PLAINTEXT", "PRE", "SECTION",
+ "SUMMARY", "TABLE", "UL", "XMP"])) {
+ var ancestor = parent_;
+ while (ancestor && !isHtmlElement(ancestor, ["H1", "H2", "H3", "H4", "H5", "H6", "P"])) {
+ ancestor = ancestor.parentNode;
+ }
+ if (isHtmlElement(ancestor, ["H1", "H2", "H3", "H4", "H5", "H6", "P"])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
function hasEditableDescendants(node) {
for (var i = 0; i < node.childNodes.length; i++) {
if (isEditable(node.childNodes[i])
@@ -2523,6 +2593,28 @@
"TBODY", "TD", "TH", "THEAD", "TR", "UL"]);
});
+ // "For each node in node list, while node is a descendant of an 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++) {
+ node = nodeList[i];
+
+ do {
+ var ancestor = node.parentNode;
+ while (ancestor
+ && !isHtmlElement(ancestor, ["ADDRESS", "H1", "H2", "H3", "H4", "H5", "H6", "P", "PRE"])) {
+ ancestor = ancestor.parentNode;
+ }
+ if (ancestor
+ && inSameEditingHost(node, ancestor)) {
+ splitParent([node]);
+ } else {
+ break;
+ }
+ } while (true);
+ }
+
// "If value is "div" or "p", then while node list is not empty:"
if (value == "div" || value == "p") {
while (nodeList.length) {
--- a/source.html Wed May 25 08:59:52 2011 -0600
+++ b/source.html Wed May 25 10:18:04 2011 -0600
@@ -247,6 +247,43 @@
editable, so authors are assured that editing commands will only modify the
editing host's contents and not the editing host itself.
+<p>The <dfn>editing host of</dfn> <var>node</var> is null if <var>node</var> is
+neither <span>editable</span> nor an <span>editing host</span>; <var>node</var>
+itself, if <var>node</var> is an <span>editing host</span>; or the nearest
+[[ancestor]] of <var>node</var> that is an <span>editing host</span>, if
+<var>node</var> is <span>editable</span>.
+
+<p>Two [[nodes]] are <dfn>in the same editing host</dfn> if both are
+<span>editable</span> and the <span>editing host of</span> both is the same.
+
+<p>A [[node]] <var>child</var> is an <dfn>allowed child</dfn> of a [[node]]
+<var>parent</var> unless one of the following conditions is met:
+
+<p class=XXX>This is very ad hoc and might need to be rethought. We can't use
+the HTML spec's definitions because those are too complicated, they don't take
+obsolete elements into account, and they're sometimes too restrictive. (We
+don't like having to contort the DOM to ensure that it's valid, because it can
+have unwanted side effects, so we want to minimize the number of cases we
+disallow.) Mostly this list covers only things that don't serialize as
+text/html.
+
+<ul>
+ <li><var>child</var> is an [[a]], and <var>parent</var> or some [[ancestor]]
+ of <var>parent</var> is an [[a]]. <!-- Cannot be serialized as text/html.
+ -->
+
+ <li><var>child</var> is an <span>HTML element</span> with [[localname]]
+ "address", "article", "aside", "blockquote", "center", "details", "dir",
+ "div", "dl", "fieldset", "figcaption", "figure", "footer", "h1", "h2", "h3",
+ "h4", "h5", "h6", "header", "hgroup", "hr", "listing", "menu", "nav", "ol",
+ "p", "plaintext", "pre", "section", "summary", "table", "ul", or "xmp"; and
+ <var>parent</var> or some [[ancestor]] of <var>parent</var> is an <span>HTML
+ element</span> with [[localname]] "h1", "h2", "h3", "h4", "h5", "h6", or "p".
+ <!-- This cannot be serialized as text/html if the parent is a p, or if the
+ parent and child are both h*. Something like <h1>foo<p>bar</p></h1> will
+ actually work, but while we're here, we may as well disallow it. -->
+</ul>
+
<p>The <dfn>CSS styling flag</dfn> is a boolean flag, which must initially be
false.
@@ -297,13 +334,14 @@
<li>Return <var>replacement element</var>.
</ol>
-<p>To remove a [[node]] <var>node</var> while <dfn>preserving its
-descendants</dfn>, <span>split the parent</span> of <var>node</var>'s
-[[children]].
-
<p>To <dfn>split the parent</dfn> of a list <var>node list</var> of consecutive
[[sibling]] [[nodes]]:
+<p class=XXX>Pretty much any time we call this algorithm, it can cause trouble
+if the parent had styles, classes, etc. There's not going to be any general
+way to handle this, but we should at least try to handle the special case of
+inline styles, because Firefox does actually add them to arbitrary elements.
+
<ol>
<li>Let <var>original parent</var> be the [[parent]] of the first member of
<var>node list</var>.
@@ -316,20 +354,13 @@
parent</var>.
<li>If the last [[child]] of <var>original parent</var> is in <var>node
- list</var>:
-
- <ol>
- <li><span>Remove extraneous line breaks after</span> <var>original
- parent</var>.
-
- <li>If <var>original parent</var>'s last [[child]] and [[nextsibling]] are
- both <span title="inline node">inline nodes</span>, call <code
- data-anolis-spec=domcore
- title=dom-Document-createElement>createElement("br")</code> on the
- [[ownerdocument]] of <var>original parent</var>, then insert the result
- into the [[parent]] of <var>original parent</var> immediately after
- <var>original parent</var>.
- </ol>
+ list</var>, and <var>original parent</var>'s last [[child]] and
+ [[nextsibling]] are both <span title="inline node">inline nodes</span>, call
+ <code data-anolis-spec=domcore
+ title=dom-Document-createElement>createElement("br")</code> on the
+ [[ownerdocument]] of <var>original parent</var>, then insert the result into
+ the [[parent]] of <var>original parent</var> immediately after <var>original
+ parent</var>.
<li>If the first [[child]] of <var>original parent</var> is not in <var>node
list</var>, but its last [[child]] is:
@@ -360,6 +391,9 @@
parent</var> immediately after <var>original parent</var>, <span>preserving
ranges</span>.
+ <li><span>Remove extraneous line breaks at the end of</span> <var>original
+ parent</var>.
+
<li>Abort these steps.
</ol>
@@ -399,10 +433,19 @@
into the [[parent]] of <var>original parent</var> immediately before
<var>original parent</var>, <span>preserving ranges</span>.
+ <li>If the last member of <var>node list</var> is an <span>inline node</span>
+ other than a [[br]], and the first [[child]] of <var>original parent</var> is
+ a [[br]], remove the first [[child]] of <var>original parent</var> from
+ <var>original parent</var>.
+
<li>If <var>original parent</var> has no [[children]], remove it from its
[[parent]].
</ol>
+<p>To remove a [[node]] <var>node</var> while <dfn>preserving its
+descendants</dfn>, <span>split the parent</span> of <var>node</var>'s
+[[children]].
+
<p>To <dfn>wrap</dfn> a list <var>node list</var> of consecutive [[sibling]]
[[nodes]], given <dfn>sibling criteria</dfn> and <dfn>new parent
instructions</dfn>:
@@ -427,11 +470,9 @@
<li>If <var>new parent</var>'s [[parent]] is null:
<ol>
- <li>If <var>new parent</var> cannot be the [[child]] of the [[parent]] of
- the first member of <var>node list</var>, <span>split the parent</span> of
- <var>node list</var>.
-
- <p class=XXX>"Cannot be the child" needs to be defined.
+ <li>While <var>new parent</var> is not an <span>allowed child</span> of the
+ [[parent]] of the first member of <var>node list</var>, <span>split the
+ parent</span> of <var>node list</var>.
<li>Insert <var>new parent</var> into the [[parent]] of the first member of
<var>node list</var> immediately before the first member of <var>node
@@ -518,7 +559,7 @@
of <var>node</var> from its [[parent]].
</ol>
-<p>To <dfn>remove extraneous line breaks after</dfn> a [[node]]
+<p>To <dfn>remove extraneous line breaks at the end of</dfn> a [[node]]
<var>node</var>:
<ol>
@@ -533,7 +574,7 @@
<p>To <dfn>remove extraneous line breaks from</dfn> a [[node]], first
<span>remove extraneous line breaks before</span> it, then <span>remove
-extraneous line breaks after</span> it.
+extraneous line breaks at the end of</span> it.
<p>To move a [[node]] to a new location, <dfn>preserving ranges</dfn>, remove
the [[node]] from its original [[parent]] (if any), then insert it in the new
@@ -3579,6 +3620,26 @@
"header", "hgroup", "li", "nav", "ol", "section", "table", "tbody", "td",
"th", "thead", "tr", or "ul".
+ <li>For each <var>node</var> in <var>node list</var>, while <var>node</var>
+ is a [[descendant]] of an <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 the one-[[node]] list
+ consistin of <var>node</var>.
+
+ <div class=XXX>
+ <p>This is needed so we don't get things like p nested inside address, and
+ instead convert part of the multi-line address into a p. But div can contain
+ any of these things, so we don't break that apart ever, which is bad. It
+ means if you have
+
+ <xmp><div>foo<br>bar</div></xmp>
+
+ <p>then formatBlocking "foo" then "bar" as p has different results from doing
+ both at once. Maybe we should split divs as well, but only if they're the
+ parent of the node we're dealing with? Or just split divs always, and hope
+ the "in the same editing host" thing handles it?
+ </div>
+
<!--
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