--- a/editcommands.html Wed Jun 29 14:50:14 2011 -0600
+++ b/editcommands.html Wed Jun 29 15:56:26 2011 -0600
@@ -3121,12 +3121,14 @@
<h3 id=assorted-block-formatting-command-algorithms><span class=secno>8.2 </span>Assorted block formatting command algorithms</h3>
-<p>To <dfn id=fix-disallowed-ancestors>fix disallowed ancestors</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>:
+<p>To <dfn id=fix-disallowed-ancestors>fix disallowed ancestors</dfn> of <var title="">node</var>:
<p class=XXX>Do we want to get rid of attributes that are no longer allowed
here?
<ol>
+ <li>If <var title="">node</var> is not <a href=#editable>editable</a>, abort these steps.
+
<li>If <var title="">node</var> is not an <a href=#allowed-child>allowed child</a> of any of its
<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>ancestors</a> <a href=#in-the-same-editing-host>in the same editing host</a>:
@@ -3154,58 +3156,6 @@
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>:
-
-<p class=note>This will fix any case where a descendant of node is a prohibited
-paragraph child. The function returns a list consisting of <var title="">node</var> and
-any new siblings this algorithm might give it, if some of its children are
-split out of it.
-
-<p class=XXX>Possibly can be converted to just fix disallowed ancestors of all
-descendant nodes. The only reason this is nontrivial is because the caller
-needs the list of returned nodes. (It's only used by formatBlock, but it
-currently has to be a separate function because it's recursive.)
-
-<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>:
<!--
@@ -5357,44 +5307,34 @@
<li><a href=#block-extend>Block-extend</a> the <a href=#active-range>active range</a>, and let <var title="">new
range</var> be the result.
- <li>Let <var title="">original node list</var> be an empty 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>.
+ <li>Let <var title="">node list</var> be an empty 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>.
<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="">new range</var>,
- append <var title="">node</var> to <var title="">original node list</var> if it is
+ append <var title="">node</var> to <var title="">node list</var> if it is
<a href=#editable>editable</a>, the last member of <var title="">original node list</var> (if
- any) is not an <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>, and <var title="">node</var> is either
- a <a href=#non-list-single-line-container>non-list single-line container</a> or an <a href=#allowed-child>allowed
- child</a> of "p".
-
- <li>For each <var title="">node</var> in <var title="">original node list</var>, while either
- <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"; or
- <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 not null, and "p" is not an <a href=#allowed-child>allowed
- child</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-parent title=concept-tree-parent>parent</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="">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>
-
- <p class=XXX>We probably don't want to break out of tables and such here.
-
- <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="">original node list</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>.
+ any) is not an <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>, <var title="">node</var> is either a
+ <a href=#non-list-single-line-container>non-list single-line container</a> or an <a href=#allowed-child>allowed child</a>
+ of "p", and <var title="">node</var> is not the <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 a <a href=#prohibited-paragraph-child>prohibited
+ paragraph child</a>.
+
+ <li>For each <var title="">node</var> in <var title="">node list</var>, while <var title="">node</var>
+ is the <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>, which has <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",
+ "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and which is not
+ the <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 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="">node</var>.
+ <!--
+ This tries to avoid misnesting if only some lines of an element are selected,
+ so <h1>[foo]<br>bar</h1> becomes <p>[foo]</p><h1>bar</h1> instead of
+ <h1><p>[foo]</p><br>bar</h1> or such. It tries to heuristically distinguish
+ between divs used as line-breakers and divs used as actual wrappers by
+ checking if they have prohibited paragraph children as descendants. It works
+ for address too, in case there are paragraphs nested inside. Thus
+ <address>[foo]<br>bar</address> becomes <p>[foo]</p><address>bar</address>,
+ but <address>[foo]<p>bar</p></address> becomes
+ <address><p>[foo]</p><p>bar</p></address>. Likewise, we don't break things
+ out of lists or tables or such if they happen to be nested in a <div>.
+ -->
<!--
We have two different behaviors, one for div and p and one for everything
@@ -5455,7 +5395,13 @@
<li><a href=#wrap>Wrap</a> <var title="">sublist</var>, with <a href=#sibling-criteria>sibling
criteria</a> matching nothing and <a href=#new-parent-instructions>new parent instructions</a>
returning the result of running <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="">value</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>.
+ <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>. Then <a href=#fix-disallowed-ancestors>fix disallowed ancestors</a> of the
+ result.
+ <!-- It's possible to have disallowed ancestors in obscure corner cases,
+ where a node is an allowed child of a p but p is not an allowed child of
+ the node's parent and the node's parent is also not one of the whitelisted
+ elements but is a block element. <xmp>[foo]</xmp> is the only case I can
+ think of. -->
</ol>
<li>Otherwise, while <var title="">node list</var> is not empty:
@@ -5494,7 +5440,8 @@
criteria</a> matching any <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>
<var title="">value</var> and no attributes, and <a href=#new-parent-instructions>new parent
instructions</a> returning the result of running
- <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="">value</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>.
+ <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="">value</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>. Then
+ <a href=#fix-disallowed-ancestors>fix disallowed ancestors</a> of the result.
</ol>
</ol>
@@ -5525,15 +5472,13 @@
"address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", set
<var title="">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>.
- <p class=XXX>This doesn't really make sense if there's an intervening table
- or something.
-
<li>Let <var title="">current type</var> be the empty string.
<li>If <var title="">node</var> is an <a href=#editable>editable</a> <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", "div", "h1", "h2", "h3", "h4",
- "h5", "h6", "p", or "pre", set <var title="">current type</var> to <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-element-local-name title=concept-element-local-name>local name</a>.
+ "h5", "h6", "p", or "pre", and <var title="">node</var> is not the <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 a
+ <a href=#prohibited-paragraph-child>prohibited paragraph child</a>, set <var title="">current type</var> to
+ <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-element-local-name title=concept-element-local-name>local name</a>.
<li>If <var title="">type</var> is null, set <var title="">type</var> to <var title="">current
type</var>.
@@ -5573,24 +5518,21 @@
the same editing host</a> as <var title="">node</var>, and <var title="">node</var> is not
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", "div", "h1", "h2",
"h3", "h4", "h5", "h6", "p", or "pre", set <var title="">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>.
- <!--
- Opera 11.11 doesn't require it be editable, so it will return "DIV" instead of
- "" for <div contenteditable>foo</div>.
-
- Chrome 14 dev will report "div" for <div><ol><li>foo</ol></div> or such.
- Opera 11.11 reports "". IE and Firefox didn't cooperate with testing. Opera
- makes somewhat more sense, but formatBlock is actually broken in that case
- right now anyway for any wrapper other than div, so I'll punt on a solution.
- -->
- <p class=XXX>This doesn't really make sense if there's an intervening table
- or something.
+ <!-- Opera 11.11 doesn't require it be editable, so it will return "DIV"
+ instead of "" for <div contenteditable>foo</div>. -->
<li>If <var title="">node</var> is an <a href=#editable>editable</a> <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", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p",
- or "pre", return its <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>, <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-lowercase>converted
- to lowercase</a>.
- <!-- Actually, we don't really need to specify "editable", since it has to be
- editable. -->
+ or "pre", and <var title="">node</var> is not the <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 a <a href=#prohibited-paragraph-child>prohibited
+ paragraph child</a>, return <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-element-local-name title=concept-element-local-name>local name</a>, <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-lowercase>converted to lowercase</a>.
+ <!--
+ Chrome 14 dev will report "div" for <div><ol><li>foo</ol></div> or such.
+ Opera 11.11 reports "". IE and Firefox didn't cooperate with testing. Opera
+ makes more sense, and matches the fact that formatBlock now doesn't recognize
+ such a div as a formatBlock candidate, so Opera it is.
+
+ We don't really need to specify "editable", since it has to be editable.
+ -->
<li>Return the empty string.
</ol>
--- a/implementation.js Wed Jun 29 14:50:14 2011 -0600
+++ b/implementation.js Wed Jun 29 15:56:26 2011 -0600
@@ -81,6 +81,15 @@
return Boolean(node1.compareDocumentPosition(node2) & Node.DOCUMENT_POSITION_PRECEDING);
}
+function getAncestors(node) {
+ var ancestors = [];
+ while (node.parentNode) {
+ ancestors.unshift(node.parentNode);
+ node = node.parentNode;
+ }
+ return ancestors;
+}
+
function getDescendants(node) {
var descendants = [];
for (var i = 0; i < node.childNodes.length; i++) {
@@ -3494,6 +3503,11 @@
//@{
function fixDisallowedAncestors(node) {
+ // "If node is not editable, abort these steps."
+ if (!isEditable(node)) {
+ return;
+ }
+
// "If node is not an allowed child of any of its ancestors in the same
// editing host:"
var hasAllowedAncestor = false;
@@ -3535,59 +3549,6 @@
}
}
-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) {
@@ -5476,59 +5437,37 @@
// "Block-extend the active range, and let new range be the result."
var newRange = blockExtend(getActiveRange());
- // "Let original node list be an empty list of nodes."
- var originalNodeList = [];
-
- // "For each node node contained in new range, append node to original
- // node list if it is editable, the last member of original node list
- // (if any) is not an ancestor of node, and node is either a non-list
- // single-line container or an allowed child of "p"."
- originalNodeList = getContainedNodes(newRange, function(node) {
+ // "Let node list be an empty list of nodes."
+ //
+ // "For each node node contained in new range, append node to node list
+ // if it is editable, the last member of original node list (if any) is
+ // not an ancestor of node, node is either a non-list single-line
+ // container or an allowed child of "p", and node is not the ancestor
+ // of a prohibited paragraph child."
+ var nodeList = getContainedNodes(newRange, function(node) {
return isEditable(node)
&& (isNonListSingleLineContainer(node)
- || isAllowedChild(node, "p"));
+ || isAllowedChild(node, "p"))
+ && !getDescendants(node).some(isProhibitedParagraphChild);
});
- // "For each node in original node list, while either 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"; or node's parent is not null, and "p" is not an allowed child
- // of node's parent: split the parent of the one-node list consisting
- // of node."
- for (var i = 0; i < originalNodeList.length; i++) {
- var node = originalNodeList[i];
-
- while (true) {
- if (node.parentNode
- && !isAllowedChild("p", node.parentNode)) {
- splitParent([node]);
- continue;
- }
-
- var ancestor = node.parentNode;
- while (ancestor
- && !isHtmlElement(ancestor, ["ADDRESS", "H1", "H2", "H3", "H4", "H5", "H6", "P", "PRE"])) {
- ancestor = ancestor.parentNode;
- }
- if (ancestor
- && isEditable(ancestor)
- && inSameEditingHost(node, ancestor)) {
- splitParent([node]);
- } else {
- break;
- }
+ // "For each node in node list, while node is the descendant of an
+ // editable HTML element in the same editing host, which has local name
+ // "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre",
+ // and which is not the ancestor of a prohibited paragraph child, split
+ // the parent of the one-node list consisting of node."
+ for (var i = 0; i < nodeList.length; i++) {
+ var node = nodeList[i];
+ while (getAncestors(node).some(function(ancestor) {
+ return isEditable(ancestor)
+ && inSameEditingHost(ancestor, node)
+ && isHtmlElement(ancestor, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])
+ && !getDescendants(ancestor).some(isProhibitedParagraphChild);
+ })) {
+ splitParent([node]);
}
}
- // "Let node list be a list of nodes, initially empty."
- var nodeList = [];
-
- // "For each node in original node list, fix prohibited paragraph
- // descendants of node, and append the resulting nodes to node list."
- for (var i = 0; i < originalNodeList.length; i++) {
- nodeList = nodeList.concat(fixProhibitedParagraphDescendants(originalNodeList[i]));
- }
-
// "If value is "div" or "p", then while node list is not empty:"
if (value == "div" || value == "p") {
while (nodeList.length) {
@@ -5564,10 +5503,11 @@
// "Wrap sublist, with sibling criteria matching nothing and
// new parent instructions returning the result of running
- // createElement(value) on the context object."
- wrap(sublist,
+ // createElement(value) on the context object. Then fix
+ // disallowed ancestors of the result."
+ fixDisallowedAncestors(wrap(sublist,
function() { return false },
- function() { return document.createElement(value) });
+ function() { return document.createElement(value) }));
}
// "Otherwise, while node list is not empty:"
@@ -5615,10 +5555,11 @@
// "Wrap sublist, with sibling criteria matching any HTML
// element with local name value and no attributes, and new
// parent instructions returning the result of running
- // createElement(value) on the context object."
- wrap(sublist,
+ // createElement(value) on the context object. Then fix
+ // disallowed ancestors of the result."
+ fixDisallowedAncestors(wrap(sublist,
function(node) { return isHtmlElement(node, value.toUpperCase()) && !node.attributes.length },
- function() { return document.createElement(value) });
+ function() { return document.createElement(value) }));
}
}
}, indeterm: function() {
@@ -5659,10 +5600,12 @@
var currentType = "";
// "If node is an editable HTML element with local name "address",
- // "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", set
+ // "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and
+ // node is not the ancestor of a prohibited paragraph child, set
// current type to node's local name."
if (isEditable(node)
- && isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])) {
+ && isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])
+ && !getDescendants(node).some(isProhibitedParagraphChild)) {
currentType = node.tagName;
}
@@ -5706,10 +5649,12 @@
}
// "If node is an editable HTML element with local name "address",
- // "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", return its
+ // "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and node
+ // is not the ancestor of a prohibited paragraph child, return node's
// local name, converted to lowercase."
if (isEditable(node)
- && isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])) {
+ && isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])
+ && !getDescendants(node).some(isProhibitedParagraphChild)) {
return node.tagName.toLowerCase();
}
--- a/source.html Wed Jun 29 14:50:14 2011 -0600
+++ b/source.html Wed Jun 29 15:56:26 2011 -0600
@@ -3103,12 +3103,14 @@
<h3>Assorted block formatting command algorithms</h3>
<!-- @{ -->
-<p>To <dfn>fix disallowed ancestors</dfn> of a [[node]] <var>node</var>:
+<p>To <dfn>fix disallowed ancestors</dfn> of <var>node</var>:
<p class=XXX>Do we want to get rid of attributes that are no longer allowed
here?
<ol>
+ <li>If <var>node</var> is not <span>editable</span>, abort these steps.
+
<li>If <var>node</var> is not an <span>allowed child</span> of any of its
[[ancestors]] <span>in the same editing host</span>:
@@ -3136,58 +3138,6 @@
of <var>node</var>.
</ol>
-<p>To <dfn>fix prohibited paragraph descendants</dfn> of a [[node]]
-<var>node</var>:
-
-<p class=note>This will fix any case where a descendant of node is a prohibited
-paragraph child. The function returns a list consisting of <var>node</var> and
-any new siblings this algorithm might give it, if some of its children are
-split out of it.
-
-<p class=XXX>Possibly can be converted to just fix disallowed ancestors of all
-descendant nodes. The only reason this is nontrivial is because the caller
-needs the list of returned nodes. (It's only used by formatBlock, but it
-currently has to be a separate function because it's recursive.)
-
-<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]]:
<!--
@@ -5363,44 +5313,34 @@
<li><span>Block-extend</span> the <span>active range</span>, and let <var>new
range</var> be the result.
- <li>Let <var>original node list</var> be an empty list of [[nodes]].
+ <li>Let <var>node list</var> be an empty list of [[nodes]].
<li>For each [[node]] <var>node</var> [[contained]] in <var>new range</var>,
- append <var>node</var> to <var>original node list</var> if it is
+ append <var>node</var> to <var>node list</var> if it is
<span>editable</span>, the last member of <var>original node list</var> (if
- any) is not an [[ancestor]] of <var>node</var>, and <var>node</var> is either
- a <span>non-list single-line container</span> or an <span>allowed
- child</span> of "p".
-
- <li>For each <var>node</var> in <var>original node list</var>, while either
- <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"; or
- <var>node</var>'s [[parent]] is not null, and "p" is not an <span>allowed
- child</span> of <var>node</var>'s [[parent]]: <span>split the parent</span>
- of the one-[[node]] list consisting 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>
-
- <p class=XXX>We probably don't want to break out of tables and such here.
-
- <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
-
- <li>For each <var>node</var> in <var>original node list</var>, <span>fix
- prohibited paragraph descendants</span> of <var>node</var>, and append the
- resulting [[nodes]] to <var>node list</var>.
+ any) is not an [[ancestor]] of <var>node</var>, <var>node</var> is either a
+ <span>non-list single-line container</span> or an <span>allowed child</span>
+ of "p", and <var>node</var> is not the [[ancestor]] of a <span>prohibited
+ paragraph child</span>.
+
+ <li>For each <var>node</var> in <var>node list</var>, while <var>node</var>
+ is the [[descendant]] of an <span>editable</span> <span>HTML element</span>
+ <span>in the same editing host</span>, which has [[localname]] "address",
+ "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and which is not
+ the [[ancestor]] of a <span>prohibited paragraph child</span>, <span>split
+ the parent</span> of the one-[[node]] list consisting of <var>node</var>.
+ <!--
+ This tries to avoid misnesting if only some lines of an element are selected,
+ so <h1>[foo]<br>bar</h1> becomes <p>[foo]</p><h1>bar</h1> instead of
+ <h1><p>[foo]</p><br>bar</h1> or such. It tries to heuristically distinguish
+ between divs used as line-breakers and divs used as actual wrappers by
+ checking if they have prohibited paragraph children as descendants. It works
+ for address too, in case there are paragraphs nested inside. Thus
+ <address>[foo]<br>bar</address> becomes <p>[foo]</p><address>bar</address>,
+ but <address>[foo]<p>bar</p></address> becomes
+ <address><p>[foo]</p><p>bar</p></address>. Likewise, we don't break things
+ out of lists or tables or such if they happen to be nested in a <div>.
+ -->
<!--
We have two different behaviors, one for div and p and one for everything
@@ -5461,7 +5401,13 @@
<li><span>Wrap</span> <var>sublist</var>, with <span>sibling
criteria</span> matching nothing and <span>new parent instructions</span>
returning the result of running [[createelement|<var>value</var>]] on the
- [[contextobject]].
+ [[contextobject]]. Then <span>fix disallowed ancestors</span> of the
+ result.
+ <!-- It's possible to have disallowed ancestors in obscure corner cases,
+ where a node is an allowed child of a p but p is not an allowed child of
+ the node's parent and the node's parent is also not one of the whitelisted
+ elements but is a block element. <xmp>[foo]</xmp> is the only case I can
+ think of. -->
</ol>
<li>Otherwise, while <var>node list</var> is not empty:
@@ -5500,7 +5446,8 @@
criteria</span> matching any <span>HTML element</span> with [[localname]]
<var>value</var> and no attributes, and <span>new parent
instructions</span> returning the result of running
- [[createelement|<var>value</var>]] on the [[contextobject]].
+ [[createelement|<var>value</var>]] on the [[contextobject]]. Then
+ <span>fix disallowed ancestors</span> of the result.
</ol>
</ol>
@@ -5531,15 +5478,13 @@
"address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", set
<var>node</var> to its [[parent]].
- <p class=XXX>This doesn't really make sense if there's an intervening table
- or something.
-
<li>Let <var>current type</var> be the empty string.
<li>If <var>node</var> is an <span>editable</span> <span>HTML
element</span> with [[localname]] "address", "div", "h1", "h2", "h3", "h4",
- "h5", "h6", "p", or "pre", set <var>current type</var> to <var>node</var>'s
- [[localname]].
+ "h5", "h6", "p", or "pre", and <var>node</var> is not the [[ancestor]] of a
+ <span>prohibited paragraph child</span>, set <var>current type</var> to
+ <var>node</var>'s [[localname]].
<li>If <var>type</var> is null, set <var>type</var> to <var>current
type</var>.
@@ -5579,24 +5524,22 @@
the same editing host</span> as <var>node</var>, and <var>node</var> is not
an <span>HTML element</span> with [[localname]] "address", "div", "h1", "h2",
"h3", "h4", "h5", "h6", "p", or "pre", set <var>node</var> to its [[parent]].
- <!--
- Opera 11.11 doesn't require it be editable, so it will return "DIV" instead of
- "" for <div contenteditable>foo</div>.
-
- Chrome 14 dev will report "div" for <div><ol><li>foo</ol></div> or such.
- Opera 11.11 reports "". IE and Firefox didn't cooperate with testing. Opera
- makes somewhat more sense, but formatBlock is actually broken in that case
- right now anyway for any wrapper other than div, so I'll punt on a solution.
- -->
- <p class=XXX>This doesn't really make sense if there's an intervening table
- or something.
+ <!-- Opera 11.11 doesn't require it be editable, so it will return "DIV"
+ instead of "" for <div contenteditable>foo</div>. -->
<li>If <var>node</var> is an <span>editable</span> <span>HTML element</span>
with [[localname]] "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p",
- or "pre", return its [[localname]], <span data-anolis-spec=domcore>converted
- to lowercase</span>.
- <!-- Actually, we don't really need to specify "editable", since it has to be
- editable. -->
+ or "pre", and <var>node</var> is not the [[ancestor]] of a <span>prohibited
+ paragraph child</span>, return <var>node</var>'s [[localname]], <span
+ data-anolis-spec=domcore>converted to lowercase</span>.
+ <!--
+ Chrome 14 dev will report "div" for <div><ol><li>foo</ol></div> or such.
+ Opera 11.11 reports "". IE and Firefox didn't cooperate with testing. Opera
+ makes more sense, and matches the fact that formatBlock now doesn't recognize
+ such a div as a formatBlock candidate, so Opera it is.
+
+ We don't really need to specify "editable", since it has to be editable.
+ -->
<li>Return the empty string.
</ol>