Revamp allowed elements
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Wed, 25 May 2011 12:27:02 -0600
changeset 169 d08f8d6ea8cb
parent 168 cb6aa0868ea5
child 170 63622e2e065c
Revamp allowed elements
editcommands.html
implementation.js
preprocess
source.html
--- a/editcommands.html	Wed May 25 10:18:04 2011 -0600
+++ b/editcommands.html	Wed May 25 12:27:02 2011 -0600
@@ -27,15 +27,10 @@
     margin-top: 0;
     margin-bottom: 0;
   }
-  dd .XXX p {
-    margin: 1em 0;
-  }
-  ol li {
-    margin: 1em 0;
-  }
-  li li {
-    margin: 0;
-  }
+  dd .XXX p { margin: 1em 0 }
+  ol li { margin: 1em 0 }
+  li li { margin: 0 }
+  table { margin: 1em 0 }
 </style>
 <body class=draft>
 <div class=head id=head>
@@ -299,11 +294,20 @@
 <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>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 the <a href=#editing-host-of>editing
+host of</a> the first is non-null and the same as the <a href=#editing-host-of>editing host
+of</a> the second.
+
+<p>The <dfn id=prohibited-paragraph-children>prohibited paragraph children</dfn> are "address", "article",
+"aside", "blockquote", "center", "details", "dd", "dir", "div", "dl", "dt",
+"fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4",
+"h5", "h6", "header", "hgroup", "hr", "li", "listing", "menu", "nav", "ol",
+"p", "plaintext", "pre", "section", "summary", "table", "ul", and "xmp".
+<!-- These are all the things that will close a <p> if found as a child.  I
+think. -->
+
+<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> or string <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> or string <var title="">parent</var> if the following algorithm returns true:
 
 <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
@@ -311,24 +315,97 @@
 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>
+text/html.  It's not intended to be complete, and in particular, it omits lots
+of cases that aren't likely to come up for us.
+
+<ol>
+  <li>If <var title="">parent</var> is "colgroup", "table", "tbody", "tfoot", "thead",
+  "tr", or 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> equal to one of
+  those, and <var title="">child</var> is a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node whose <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> does not
+  consist solely of <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#space-character title="space character">space characters</a>, return false.
+
+  <li>If <var title="">parent</var> is "script", "style", "plaintext", or "xmp", or 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> equal to one of those, and
+  <var title="">child</var> is not a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node, return false.
+  <!-- Actually, no node can occur in the DOM after plaintext, generally.  But
+  let's not get too carried away. -->
+
+  <li>If <var title="">child</var> is a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#document>Document</a></code>, <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#documentfragment>DocumentFragment</a></code>, or
+  <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#documenttype>DocumentType</a></code>, return false.
+
+  <li>If <var title="">child</var> is an <a href=#html-element>HTML element</a>, set <var title="">child</var>
+  to 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="">child</var>.
+
+  <li>If <var title="">child</var> is not a string, return true.
+
+  <li>If <var title="">parent</var> is an <a href=#html-element>HTML element</a>:
+
+  <ol>
+    <li>If <var title="">child</var> is "a", 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>, return false.
+    <!-- Cannot be serialized as text/html.  In some cases it can, like
+    <a>foo<table><td><a>bar</a></td></table>baz</a>, but it's invalid in those
+    cases too, so no need for complication. -->
+
+    <li>If <var title="">child</var> is one of the <a href=#prohibited-paragraph-children>prohibited paragraph
+    children</a> 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", return false.
+    <!-- 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. -->
+
+    <li>Let <var title="">parent</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="">parent</var>.
+    <!-- Further requirements only care about the parent itself, not ancestors,
+    so we don't need to know the node itself. -->
+  </ol>
+
+  <li>If <var title="">parent</var> is an <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code> or <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#documentfragment>DocumentFragment</a></code>, return
+  true.
+
+  <li>If <var title="">parent</var> is not a string, return false.
+
+  <li>If <var title="">parent</var> is in the following table, then return true if
+  <var title="">child</var> is listed as an allowed child, and false otherwise.
+  <!-- We allow children even where some intervening nodes will be inserted,
+  like tr as a child of table. -->
+
+  <table>
+    <tr><th>Parent <th>Allowed children
+    <tr><td>colgroup <td>col
+    <tr><td>table <td>caption, col, colgroup, tbody, td, tfoot, th, thead, tr
+    <tr><td>tbody, tfoot, thead <td>td, th, tr
+    <tr><td>tr <td>td, th
+  </table>
+
+  <li>If <var title="">child</var> is "body", "caption", "col", "colgroup", "frame",
+  "frameset", "head", "html", "tbody", "td", "tfoot", "th", "thead", or "tr",
+  return false.
+
+  <!-- dd/dt/li will serialize fine as the child of random stuff, but it makes
+  no sense at all, so we want to avoid it anyway. -->
+  <li>If <var title="">child</var> is "dd" or "dt" and <var title="">parent</var> is not "dl",
+  return false.
+
+  <li>If <var title="">child</var> is "li" and <var title="">parent</var> is not "ol" or "ul",
+  return false.
+
+  <li>If <var title="">parent</var> is in the following table and <var title="">child</var> is
+  listed as a prohibited child, return false.
+
+  <table>
+    <tr><th>Parent <th>Prohibited children
+    <tr><td>a <td>a
+    <tr><td>dd, dt <td>dd, dt
+    <tr><td>li <td>li
+    <tr><td>nobr <td>nobr
+    <tr><td>td, th <td>caption, col, colgroup, tbody, td, tfoot, th, thead, tr
+    <tr><td>h1, h2, h3, h4, h5, h6, p <td>All <a href=#prohibited-paragraph-children>prohibited paragraph
+      children</a>
+  </table>
+
+  <li>Return true.
+</ol>
 
 <p>The <dfn id=css-styling-flag>CSS styling flag</dfn> is a boolean flag, which must initially be
 false.
@@ -511,9 +588,14 @@
   <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>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>If <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>, but is an
+    <a href=#allowed-child>allowed child</a> of 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 the first member of
+    <var title="">node list</var> that is <a href=#in-the-same-editing-host>in the same editing host</a> as the
+    first member of <var title="">node list</var>, then 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
@@ -3322,7 +3404,7 @@
   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>;
   <var title="">node</var> is not a <a href=#potential-indentation-element>potential indentation element</a>; and
   either <var title="">node</var> is an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, or 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> is an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>
-  or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, or it can 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 an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>; then append
+  or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, or it is an <a href=#allowed-child>allowed child</a> of "li"; then append
   <var title="">node</var> to <var title="">node list</var>.
   <!--
   We exclude potential indentation elements so that selecting some random text
@@ -3338,14 +3420,10 @@
   different from how it would work if you reversed the commands.
   OpenOffice.org 3.2.1 (Ubuntu) and Word 2007 both agree with the spec in this
   case.
-
-  We don't ask whether the node's parent can contain an <ol>.  The only place
-  where this is likely to cause serious problems is <p>, which we special-case.
   -->
 
-  <p class=XXX>Similar to a number of other places in the spec, "can be the
-  child" is not well-defined, and it's not clear what the right definition
-  should be.
+  <p class=XXX>Double-check what happens if the node's parent can't contain a
+  list.
 
   <li>If every member of <var title="">node list</var> is equal to or 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
   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> <var title="">tag name</var>, and no
@@ -3390,10 +3468,16 @@
     remove the first member from <var title="">node list</var> and append it to
     <var title="">sublist</var>.
 
-    <li>If <var title="">sublist</var> contains more than one member, <a href=#wrap>wrap</a>
-    it, with <a href=#sibling-criteria>sibling criteria</a> matching nothing and with <a href=#new-parent-instructions>new
-    parent instructions</a> returning 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("li")</a></code> on the
-    <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.  Let <var title="">node</var> be the result.
+    <li>If <var title="">sublist</var> contains more than one member, 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("li")</a></code> on the
+    <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a> and let <var title="">node</var> be the result.  Insert
+    <var title="">node</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="">sublist</var> immediately before the first member of
+    <var title="">sublist</var>.  Then <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 <var title="">node</var>.
+
+    <p class=XXX>This is a hack to avoid the wrap algorithm trying to reparent
+    the li.  Think of a better way to fix it.
 
     <li>Otherwise, let <var title="">node</var> be the sole member of
     <var title="">sublist</var>.
@@ -3475,11 +3559,16 @@
     elements</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="">other tag name</var> (if any) to
     <var title="">node list</var> and continue from the beginning of this loop.
 
-    <li>If <var title="">node</var> is not an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>, <a href=#wrap>wrap</a> the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a>
-    list consisting of <var title="">node</var>, with the <a href=#sibling-criteria>sibling criteria</a>
-    matching nothing, and the <a href=#new-parent-instructions>new parent instructions</a> returning
-    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("li")</a></code> on the
-    <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.  Let <var title="">node</var> be the result.
+    <li>If <var title="">node</var> is not an <code class=external data-anolis-spec=html title="the li element"><a href=http://www.whatwg.org/html/#the-li-element>li</a></code>, 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("li")</a></code> on the
+    <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a> and let <var title="">new item</var> be the result.  Insert
+    <var title="">new item</var> into <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> immediately before
+    <var title="">node</var>.  Then <a href=#wrap>wrap</a> the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting
+    of <var title="">node</var>, with <a href=#sibling-criteria>sibling criteria</a> matching nothing and
+    <a href=#new-parent-instructions>new parent instructions</a> returning <var title="">new item</var>.  Then
+    set <var title="">node</var> to <var title="">new item</var>.
+
+    <p class=XXX>This is a hack to avoid the wrap algorithm trying to reparent
+    the li.  Think of a better way to fix it.
 
     <li><a href=#wrap>Wrap</a> the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of <var title="">node</var>,
     with the <a href=#sibling-criteria>sibling criteria</a> matching any <a href=#html-element>HTML
@@ -3592,10 +3681,10 @@
   "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>.
+  is a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendant</a> of an <a href=#editable>editable</a> <a href=#html-element>HTML element</a>
+  <a href=#in-the-same-editing-host>in the same editing host</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> "address", "h1",
+  "h2", "h3", "h4", "h5", "h6", "p", or "pre", <a href=#split-the-parent>split the parent</a> of
+  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
--- a/implementation.js	Wed May 25 10:18:04 2011 -0600
+++ b/implementation.js	Wed May 25 12:27:02 2011 -0600
@@ -390,6 +390,9 @@
 	if (typeof tags == "string") {
 		tags = [tags];
 	}
+	if (typeof tags == "object") {
+		tags = tags.map(function(tag) { return tag.toUpperCase() });
+	}
 	return node
 		&& node.nodeType == Node.ELEMENT_NODE
 		&& isHtmlNamespace(node.namespaceURI)
@@ -574,10 +577,25 @@
 
 	// "If new parent's parent is null:"
 	if (!newParent.parentNode) {
-		// "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);
+		// "If new parent is not an allowed child of the parent of the first
+		// member of node list, but is an allowed child of some ancestor of the
+		// first member of node list that is in the same editing host as the
+		// first member of node list, then while new parent is not an allowed
+		// child of the parent of the first member of node list, split the
+		// parent of node list."
+		var ancestor = nodeList[0].parentNode;
+		while (ancestor) {
+			if (isAllowedChild(newParent, ancestor)
+			&& inSameEditingHost(ancestor, nodeList[0])) {
+				while (!isAllowedChild(newParent, nodeList[0].parentNode)) {
+					splitParent(nodeList);
+				}
+				break;
+			}
+			ancestor = ancestor.parentNode;
+		}
+		if (!ancestor && !isAllowedChild(newParent, nodeList[0].parentNode)) {
+			throw "Is this an error?  Investigate.";
 		}
 
 		// "Insert new parent into the parent of the first member of node list
@@ -749,50 +767,163 @@
 	}
 }
 
-// "Two nodes are in the same editing host if both are editable and the editing
-// host of both is the same."
+// "Two nodes are in the same editing host if the editing host of the first is
+// non-null and the same as the editing host of the second."
 function inSameEditingHost(node1, node2) {
-	return isEditable(node1)
-		&& isEditable(node2)
+	return getEditingHostOf(node1)
 		&& 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"."
+// "The prohibited paragraph children are "address", "article", "aside",
+// "blockquote", "center", "details", "dd", "dir", "div", "dl", "dt",
+// "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3",
+// "h4", "h5", "h6", "header", "hgroup", "hr", "li", "listing", "menu", "nav",
+// "ol", "p", "plaintext", "pre", "section", "summary", "table", "ul", and
+// "xmp"."
+var prohibitedParagraphChildren = ["address", "article", "aside", "blockquote",
+	"center", "details", "dd", "dir", "div", "dl", "dt", "fieldset",
+	"figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5",
+	"h6", "header", "hgroup", "hr", "li", "listing", "menu", "nav", "ol", "p",
+	"plaintext", "pre", "section", "summary", "table", "ul", "xmp"];
+
 function isAllowedChild(child, parent_) {
-	if (isHtmlElement(child, "A")) {
-		var ancestor = parent_;
-		while (ancestor && !isHtmlElement(ancestor, "A")) {
-			ancestor = ancestor.parentNode;
+	// "If parent is "colgroup", "table", "tbody", "tfoot", "thead", "tr", or
+	// an HTML element with local name equal to one of those, and child is a
+	// Text node whose data does not consist solely of space characters, return
+	// false."
+	if ((["colgroup", "table", "tbody", "tfoot", "thead", "tr"].indexOf(parent_) != -1
+	|| isHtmlElement(parent_, ["colgroup", "table", "tbody", "tfoot", "thead", "tr"]))
+	&& typeof child == "object"
+	&& child.nodeType == Node.TEXT_NODE
+	&& !/^[ \t\n\f\r]*$/.test(child.data)) {
+		return false;
+	}
+
+	// "If parent is "script", "style", "plaintext", or "xmp", or an HTML
+	// element with local name equal to one of those, and child is not a Text
+	// node, return false."
+	if ((["script", "style", "plaintext", "xmp"].indexOf(parent_) != -1
+	|| isHtmlElement(parent, ["script", "style", "plaintext", "xmp"]))
+	&& (typeof child != "object" || child.nodeType != Node.TEXT_NODE)) {
+		return false;
+	}
+
+	// "If child is a Document, DocumentFragment, or DocumentType, return
+	// false."
+	if (typeof child == "object"
+	&& (child.nodeType == Node.DOCUMENT_NODE
+	|| child.nodeType == Node.DOCUMENT_FRAGMENT_NODE
+	|| child.nodeType == Node.DOCUMENT_TYPE_NODE)) {
+		return false;
+	}
+
+	// "If child is an HTML element, set child to the local name of child."
+	if (isHtmlElement(child)) {
+		child = child.tagName.toLowerCase();
+	}
+
+	// "If child is not a string, return true."
+	if (typeof child != "string") {
+		return true;
+	}
+
+	// "If parent is an HTML element:"
+	if (isHtmlElement(parent_)) {
+		// "If child is "a", and parent or some ancestor of parent is an a,
+		// return false."
+		if (child == "a") {
+			var ancestor = parent_;
+			while (ancestor) {
+				if (isHtmlElement(ancestor, "a")) {
+					return false;
+				}
+				ancestor = ancestor.parentNode;
+			}
 		}
-		if (isHtmlElement(ancestor, "A")) {
+
+		// "If child is one of the prohibited paragraph children and parent or
+		// some ancestor of parent is an HTML element with local name "h1",
+		// "h2", "h3", "h4", "h5", "h6", or "p", return false."
+		if (prohibitedParagraphChildren.indexOf(child) != -1) {
+			var ancestor = parent_;
+			while (ancestor) {
+				if (isHtmlElement(ancestor, ["h1", "h2", "h3", "h4", "h5", "h6", "p"])) {
+					return false;
+				}
+				ancestor = ancestor.parentNode;
+			}
+		}
+
+		// "Let parent be the local name of parent."
+		parent_ = parent_.tagName.toLowerCase();
+	}
+
+	// "If parent is an Element or DocumentFragment, return true."
+	if (typeof parent_ == "object"
+	&& (parent_.nodeType == Node.ELEMENT_NODE
+	|| parent_.nodeType == Node.DOCUMENT_FRAGMENT_NODE)) {
+		return true;
+	}
+
+	// "If parent is not a string, return false."
+	if (typeof parent_ != "string") {
+		return false;
+	}
+
+	// "If parent is in the following table, then return true if child is
+	// listed as an allowed child, and false otherwise."
+	switch (parent_) {
+		case "colgroup":
+			return child == "col";
+		case "table":
+			return ["caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"].indexOf(child) != -1;
+		case "tbody":
+		case "thead":
+		case "tfoot":
+			return ["td", "th", "tr"].indexOf(child) != -1;
+		case "tr":
+			return ["td", "th"].indexOf(child) != -1;
+	}
+
+	// "If child is "body", "caption", "col", "colgroup", "frame", "frameset",
+	// "head", "html", "tbody", "td", "tfoot", "th", "thead", or "tr", return
+	// false."
+	if (["body", "caption", "col", "colgroup", "frame", "frameset", "head",
+	"html", "tbody", "td", "tfoot", "th", "thead", "tr"].indexOf(child) != -1) {
+		return false;
+	}
+
+	// "If child is "dd" or "dt" and parent is not "dl", return false."
+	if (["dd", "dt"].indexOf(child) != -1
+	&& parent_ != "dl") {
+		return false;
+	}
+
+	// "If child is "li" and parent is not "ol" or "ul", return false."
+	if (child == "li"
+	&& parent_ != "ol"
+	&& parent_ != "ul") {
+		return false;
+	}
+
+	// "If parent is in the following table and child is listed as a prohibited
+	// child, return false."
+	var table = [
+		[["a"], ["a"]],
+		[["dd", "dt"], ["dd", "dt"]],
+		[["li"], ["li"]],
+		[["nobr"], ["nobr"]],
+		[["td", "th"], ["caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"]],
+		[["h1", "h2", "h3", "h4", "h5", "h6", "p"], prohibitedParagraphChildren],
+	];
+	for (var i = 0; i < table.length; i++) {
+		if (table[i][0].indexOf(parent_) != -1
+		&& table[i][1].indexOf(child) != -1) {
 			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."
 	return true;
 }
 
@@ -2593,10 +2724,10 @@
 				"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 each node in node list, while node is a descendant of an
+		// editable HTML element in the same editing host with local name
+		// "address", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", split
+		// the parent of the one-node list consisting of node."
 		for (var i = 0; i < nodeList.length; i++) {
 			node = nodeList[i];
 
@@ -2607,6 +2738,7 @@
 					ancestor = ancestor.parentNode;
 				}
 				if (ancestor
+				&& isEditable(ancestor)
 				&& inSameEditingHost(node, ancestor)) {
 					splitParent([node]);
 				} else {
@@ -3401,7 +3533,7 @@
 	// "For each node node contained in new range, if node is editable; the
 	// last member of node list (if any) is not an ancestor of node; node
 	// is not a potential indentation element; and either node is an ol or
-	// ul, or its parent is an ol or ul, or it can be the child of an li;
+	// ul, or its parent is an ol or ul, or it is an allowed child of "li";
 	// then append node to node list."
 	for (
 		var node = newRange.startContainer;
@@ -3414,10 +3546,7 @@
 		&& !isPotentialIndentationElement(node)
 		&& (isHtmlElement(node, ["OL", "UL"])
 		|| isHtmlElement(node.parentNode, ["OL", "UL"])
-		// As usual with content restrictions, we fake it for testing
-		// purposes.
-		|| !isHtmlElement(node)
-		|| ["THEAD", "TBODY", "TR", "TH", "TD", "DT", "DD"].indexOf(node.tagName) == -1)) {
+		|| isAllowedChild(node, "li"))) {
 			nodeList.push(node);
 		}
 	}
@@ -3485,16 +3614,19 @@
 				sublist.push(nodeList.shift());
 			}
 
-			// "If sublist contains more than one member, wrap it, with
-			// sibling criteria matching nothing and with new parent
-			// instructions returning the result of calling
-			// createElement("li") on the context object. Let node be the
-			// result."
+			// "If sublist contains more than one member, call
+			// createElement("li") on the context object and let node be the
+			// result. Insert node into the parent of the first member of
+			// sublist immediately before the first member of sublist. Then
+			// wrap sublist, with sibling criteria matching nothing and new
+			// parent instructions returning node."
 			var node;
 			if (sublist.length > 1) {
+				node = document.createElement("li");
+				sublist[0].parentNode.insertBefore(node, sublist[0]);
 				node = wrap(sublist,
 					function() { return false },
-					function() { return document.createElement("li") });
+					function() { return node });
 
 			// "Otherwise, let node be the sole member of sublist."
 			} else {
@@ -3564,15 +3696,19 @@
 				continue;
 			}
 
-			// "If node is not an li, wrap the one-node list consisting of
-			// node, with the sibling criteria matching nothing, and the
-			// new parent instructions returning the result of calling
-			// createElement("li") on the context object. Let node be the
-			// result."
+			// "If node is not an li, call createElement("li") on the context
+			// object and let new item be the result. Insert new item into
+			// node's parent immediately before node. Then wrap the one-node
+			// list consisting of node, with sibling criteria matching nothing
+			// and new parent instructions returning new item. Then set node to
+			// new item."
 			if (!isHtmlElement(node, "LI")) {
-				node = wrap([node],
+				var newItem = document.createElement("li");
+				node.parentNode.insertBefore(newItem, node);
+				wrap([node],
 					function() { return false },
-					function() { return document.createElement("li") });
+					function() { return newItem });
+				node = newItem;
 			}
 
 			// "Wrap the one-node list consisting of node, with the sibling
--- a/preprocess	Wed May 25 10:18:04 2011 -0600
+++ b/preprocess	Wed May 25 12:27:02 2011 -0600
@@ -31,6 +31,7 @@
     'dl': '<code data-anolis-spec=html title="the dl element">dl</code>',
     'document': '<code data-anolis-spec=domcore>Document</code>',
     'documentfragment': '<code data-anolis-spec=domcore>DocumentFragment</code>',
+    'documenttype': '<code data-anolis-spec=domcore>DocumentType</code>',
     'element': '<code data-anolis-spec=domcore>Element</code>',
     'em': '<code data-anolis-spec=html title="the em element">em</code>',
     'followingsibling': '<span data-anolis-spec=domcore title="concept-tree-following-sibling">following sibling</span>',
--- a/source.html	Wed May 25 10:18:04 2011 -0600
+++ b/source.html	Wed May 25 12:27:02 2011 -0600
@@ -28,15 +28,10 @@
     margin-top: 0;
     margin-bottom: 0;
   }
-  dd .XXX p {
-    margin: 1em 0;
-  }
-  ol li {
-    margin: 1em 0;
-  }
-  li li {
-    margin: 0;
-  }
+  dd .XXX p { margin: 1em 0 }
+  ol li { margin: 1em 0 }
+  li li { margin: 0 }
+  table { margin: 1em 0 }
 </style>
 <body class=draft>
 <div class=head id=head>
@@ -253,11 +248,20 @@
 [[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>Two [[nodes]] are <dfn>in the same editing host</dfn> if the <span>editing
+host of</span> the first is non-null and the same as the <span>editing host
+of</span> the second.
+
+<p>The <dfn>prohibited paragraph children</dfn> are "address", "article",
+"aside", "blockquote", "center", "details", "dd", "dir", "div", "dl", "dt",
+"fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4",
+"h5", "h6", "header", "hgroup", "hr", "li", "listing", "menu", "nav", "ol",
+"p", "plaintext", "pre", "section", "summary", "table", "ul", and "xmp".
+<!-- These are all the things that will close a <p> if found as a child.  I
+think. -->
+
+<p>A [[node]] or string <var>child</var> is an <dfn>allowed child</dfn> of a
+[[node]] or string <var>parent</var> if the following algorithm returns true:
 
 <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
@@ -265,24 +269,97 @@
 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>
+text/html.  It's not intended to be complete, and in particular, it omits lots
+of cases that aren't likely to come up for us.
+
+<ol>
+  <li>If <var>parent</var> is "colgroup", "table", "tbody", "tfoot", "thead",
+  "tr", or an <span>HTML element</span> with [[localname]] equal to one of
+  those, and <var>child</var> is a [[text]] node whose [[cddata]] does not
+  consist solely of [[spacecharacters]], return false.
+
+  <li>If <var>parent</var> is "script", "style", "plaintext", or "xmp", or an
+  <span>HTML element</span> with [[localname]] equal to one of those, and
+  <var>child</var> is not a [[text]] node, return false.
+  <!-- Actually, no node can occur in the DOM after plaintext, generally.  But
+  let's not get too carried away. -->
+
+  <li>If <var>child</var> is a [[document]], [[documentfragment]], or
+  [[documenttype]], return false.
+
+  <li>If <var>child</var> is an <span>HTML element</span>, set <var>child</var>
+  to the [[localname]] of <var>child</var>.
+
+  <li>If <var>child</var> is not a string, return true.
+
+  <li>If <var>parent</var> is an <span>HTML element</span>:
+
+  <ol>
+    <li>If <var>child</var> is "a", and <var>parent</var> or some [[ancestor]]
+    of <var>parent</var> is an [[a]], return false.
+    <!-- Cannot be serialized as text/html.  In some cases it can, like
+    <a>foo<table><td><a>bar</a></td></table>baz</a>, but it's invalid in those
+    cases too, so no need for complication. -->
+
+    <li>If <var>child</var> is one of the <span>prohibited paragraph
+    children</span> 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", return false.
+    <!-- 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. -->
+
+    <li>Let <var>parent</var> be the [[localname]] of <var>parent</var>.
+    <!-- Further requirements only care about the parent itself, not ancestors,
+    so we don't need to know the node itself. -->
+  </ol>
+
+  <li>If <var>parent</var> is an [[element]] or [[documentfragment]], return
+  true.
+
+  <li>If <var>parent</var> is not a string, return false.
+
+  <li>If <var>parent</var> is in the following table, then return true if
+  <var>child</var> is listed as an allowed child, and false otherwise.
+  <!-- We allow children even where some intervening nodes will be inserted,
+  like tr as a child of table. -->
+
+  <table>
+    <tr><th>Parent <th>Allowed children
+    <tr><td>colgroup <td>col
+    <tr><td>table <td>caption, col, colgroup, tbody, td, tfoot, th, thead, tr
+    <tr><td>tbody, tfoot, thead <td>td, th, tr
+    <tr><td>tr <td>td, th
+  </table>
+
+  <li>If <var>child</var> is "body", "caption", "col", "colgroup", "frame",
+  "frameset", "head", "html", "tbody", "td", "tfoot", "th", "thead", or "tr",
+  return false.
+
+  <!-- dd/dt/li will serialize fine as the child of random stuff, but it makes
+  no sense at all, so we want to avoid it anyway. -->
+  <li>If <var>child</var> is "dd" or "dt" and <var>parent</var> is not "dl",
+  return false.
+
+  <li>If <var>child</var> is "li" and <var>parent</var> is not "ol" or "ul",
+  return false.
+
+  <li>If <var>parent</var> is in the following table and <var>child</var> is
+  listed as a prohibited child, return false.
+
+  <table>
+    <tr><th>Parent <th>Prohibited children
+    <tr><td>a <td>a
+    <tr><td>dd, dt <td>dd, dt
+    <tr><td>li <td>li
+    <tr><td>nobr <td>nobr
+    <tr><td>td, th <td>caption, col, colgroup, tbody, td, tfoot, th, thead, tr
+    <tr><td>h1, h2, h3, h4, h5, h6, p <td>All <span>prohibited paragraph
+      children</span>
+  </table>
+
+  <li>Return true.
+</ol>
 
 <p>The <dfn>CSS styling flag</dfn> is a boolean flag, which must initially be
 false.
@@ -470,9 +547,14 @@
   <li>If <var>new parent</var>'s [[parent]] is null:
 
   <ol>
-    <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>If <var>new parent</var> is not an <span>allowed child</span> of the
+    [[parent]] of the first member of <var>node list</var>, but is an
+    <span>allowed child</span> of some [[ancestor]] of the first member of
+    <var>node list</var> that is <span>in the same editing host</span> as the
+    first member of <var>node list</var>, then 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
@@ -3339,7 +3421,7 @@
   list</var> (if any) is not an [[ancestor]] of <var>node</var>;
   <var>node</var> is not a <span>potential indentation element</span>; and
   either <var>node</var> is an [[ol]] or [[ul]], or its [[parent]] is an [[ol]]
-  or [[ul]], or it can be the [[child]] of an [[li]]; then append
+  or [[ul]], or it is an <span>allowed child</span> of "li"; then append
   <var>node</var> to <var>node list</var>.
   <!--
   We exclude potential indentation elements so that selecting some random text
@@ -3355,14 +3437,10 @@
   different from how it would work if you reversed the commands.
   OpenOffice.org 3.2.1 (Ubuntu) and Word 2007 both agree with the spec in this
   case.
-
-  We don't ask whether the node's parent can contain an <ol>.  The only place
-  where this is likely to cause serious problems is <p>, which we special-case.
   -->
 
-  <p class=XXX>Similar to a number of other places in the spec, "can be the
-  child" is not well-defined, and it's not clear what the right definition
-  should be.
+  <p class=XXX>Double-check what happens if the node's parent can't contain a
+  list.
 
   <li>If every member of <var>node list</var> is equal to or the [[child]] of
   an <span>HTML element</span> with [[localname]] <var>tag name</var>, and no
@@ -3407,12 +3485,18 @@
     remove the first member from <var>node list</var> and append it to
     <var>sublist</var>.
 
-    <li>If <var>sublist</var> contains more than one member, <span>wrap</span>
-    it, with <span>sibling criteria</span> matching nothing and with <span>new
-    parent instructions</span> returning the result of calling <code
+    <li>If <var>sublist</var> contains more than one member, call <code
     data-anolis-spec=domcore
     title=dom-Document-createElement>createElement("li")</code> on the
-    [[contextobject]].  Let <var>node</var> be the result.
+    [[contextobject]] and let <var>node</var> be the result.  Insert
+    <var>node</var> into the [[parent]] of the first member of
+    <var>sublist</var> immediately before the first member of
+    <var>sublist</var>.  Then <span>wrap</span> <var>sublist</var>, with
+    <span>sibling criteria</span> matching nothing and <span>new parent
+    instructions</span> returning <var>node</var>.
+
+    <p class=XXX>This is a hack to avoid the wrap algorithm trying to reparent
+    the li.  Think of a better way to fix it.
 
     <li>Otherwise, let <var>node</var> be the sole member of
     <var>sublist</var>.
@@ -3499,12 +3583,18 @@
     elements</span> with [[localname]] <var>other tag name</var> (if any) to
     <var>node list</var> and continue from the beginning of this loop.
 
-    <li>If <var>node</var> is not an [[li]], <span>wrap</span> the one-[[node]]
-    list consisting of <var>node</var>, with the <span>sibling criteria</span>
-    matching nothing, and the <span>new parent instructions</span> returning
-    the result of calling <code data-anolis-spec=domcore
+    <li>If <var>node</var> is not an [[li]], call <code
+    data-anolis-spec=domcore
     title=dom-Document-createElement>createElement("li")</code> on the
-    [[contextobject]].  Let <var>node</var> be the result.
+    [[contextobject]] and let <var>new item</var> be the result.  Insert
+    <var>new item</var> into <var>node</var>'s [[parent]] immediately before
+    <var>node</var>.  Then <span>wrap</span> the one-[[node]] list consisting
+    of <var>node</var>, with <span>sibling criteria</span> matching nothing and
+    <span>new parent instructions</span> returning <var>new item</var>.  Then
+    set <var>node</var> to <var>new item</var>.
+
+    <p class=XXX>This is a hack to avoid the wrap algorithm trying to reparent
+    the li.  Think of a better way to fix it.
 
     <li><span>Wrap</span> the one-[[node]] list consisting of <var>node</var>,
     with the <span>sibling criteria</span> matching any <span>HTML
@@ -3621,10 +3711,10 @@
   "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>.
+  is a [[descendant]] of an <span>editable</span> <span>HTML element</span>
+  <span>in the same editing host</span> with [[localname]] "address", "h1",
+  "h2", "h3", "h4", "h5", "h6", "p", or "pre", <span>split the parent</span> of
+  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