Another daily commit
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Thu, 24 Feb 2011 15:11:41 -0700
changeset 9 9223dc704133
parent 8 641c267313c3
child 10 67cb4992b0d5
Another daily commit
editcommands.html
implementation.html
preprocess
source.html
xrefs.json
--- a/editcommands.html	Wed Feb 23 15:15:21 2011 -0700
+++ b/editcommands.html	Thu Feb 24 15:11:41 2011 -0700
@@ -19,7 +19,7 @@
 <body class=draft>
 <div class=head id=head>
 <h1>HTML Editing Commands</h1>
-<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-23-february-2011>Work in Progress &mdash; Last Update 23 February 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-24-february-2011>Work in Progress &mdash; Last Update 24 February 2011</h2>
 <dl>
  <dt>Editor
  <dd>Aryeh Gregor &lt;ayg+spec@aryeh.name&gt;
@@ -87,17 +87,25 @@
   <li><p>Also not sure about computed style.  There are differences between
   "computed" and "used" and things like that, what do we actually want here?
 
-  <li><p>Some of the DOM stuff might benefit from more precision.  E.g., is
-  there a precise algorithm for what it means to append a node someplace, if
-  that node is already somewhere in the DOM?  What does that do if it's
-  selected, it has state (like a video or animated image), etc.?
+  <li><p>The wording I use for DOM stuff is a bit of a mess, often either
+  imprecise or unreasonably verbose.  I'm not quite sure how to fix it.
+
+  <li><p>I haven't put any thought yet into collapsed ranges or selections.
+  Currently my algorithms mostly do nothing if the selection is collapsed,
+  which is of course wrong.  E.g., bold with collapsed selection should put
+  &lt;b&gt;&lt;/b&gt; at the cursor, generally.
+
+  <li><p>I also don't pay attention to what happens to the selection when you
+  mutate the DOM.  This is essential.
 </ul>
 
 
 <h2 id=definitions><span class=secno>3 </span>Definitions</h2>
 
 <p>A <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> is an <dfn id=html-element>HTML element</dfn> if it is an <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> whose
-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-namespace title=concept-element-namespace>namespace</a> is the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#html-namespace>HTML namespace</a>.
+<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-namespace title=concept-element-namespace>namespace</a> is the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#html-namespace>HTML namespace</a>.  An <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#attr><code class=external data-anolis-spec=domcore>Attr</code></a> is an <dfn id=html-attribute>HTML attribute</dfn> if its
+<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-namespace title=concept-attr-namespace>namespace</a> is
+the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#html-namespace>HTML namespace</a>.
 
 <p>The <dfn id=first-node>first node</dfn> of a <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> is the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> returned by the
 following algorithm:
@@ -115,7 +123,8 @@
   <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment><code class=external data-anolis-spec=domcore>Comment</code></a>, or <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#processinginstruction><code class=external data-anolis-spec=domcore>ProcessingInstruction</code></a> node, return that.
 
   <li><p>If <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a> has children,
-  return the child with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> equal to the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a>.
+  return the child whose <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> is equal to <var title="">range</var>'s
+  <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a>.
 
   <li><p>Return <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
 </ol>
@@ -147,10 +156,15 @@
   <!-- This is what Firefox seems to do, no reason to change it . . . -->
 
   <p class=note>In user agents that support only one <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> per
-  <a href=http://html5.org/specs/dom-range.html#selection><code class=external data-anolis-spec=domrange>Selection</code></a>, <var title="">range</var> will simply be the only <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> associated
-  to <var title="">selection</var>.
+  <a href=http://html5.org/specs/dom-range.html#selection><code class=external data-anolis-spec=domrange>Selection</code></a>, the active range is simply the only one in the selection.
 </ol>
 
+<p>When the user agent is instructed to run a particular method, it must follow
+the steps defined for that method in the appropriate specification, not act as
+though the method had actually been called from JavaScript.  In particular,
+if the author has overridden the method with a custom method, the standard
+method must be run rather than the custom one.
+
 
 <h2 id=decomposing-a-range-into-nodes><span class=secno>4 </span>Decomposing a Range into Nodes</h2>
 <p>When a user agent is to <dfn id=decompose-a-range>decompose a <code class=external data-anolis-spec=domrange>Range</code></dfn> <var title="">range</var>, it must run the following steps.
@@ -182,8 +196,7 @@
     <var title="">start node</var> and set <var title="">start node</var> to the
     result.
 
-    <li><p>Run <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-text-splittext><code class=external data-anolis-spec=domcore title=dom-Text-splitText>splitText(<var title="">end offset</var> &minus; <var title="">start offset</var>)</code></a> on <var title="">start node</var> and set
-    <var title="">start node</var> to the previous sibling of the result.
+    <li><p>Run <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-text-splittext><code class=external data-anolis-spec=domcore title=dom-Text-splitText>splitText(<var title="">end offset</var> &minus; <var title="">start offset</var>)</code></a> on <var title="">start node</var>.
 
     <li><p>Return the list consisting of the single <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> <var title="">start
     node</var>, and abort these steps.
@@ -198,16 +211,16 @@
   <li><p>If <var title="">end node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node and <var title="">end
   offset</var> is neither 0 nor the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of <var title="">end
   node</var>, run <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-text-splittext><code class=external data-anolis-spec=domcore title=dom-Text-splitText>splitText(<var title="">end offset</var>)</code></a> on
-  <var title="">end node</var> and set <var title="">end node</var> to the previous
-  sibling of the returned node.  Set <var title="">end offset</var> to the
-  <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of the new <var title="">end node</var>.
+  <var title="">end node</var>.
 
-  <li><p>If <var title="">start node</var> is an <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> with at least one
-  child, let <var title="">node</var> be the child of <var title="">start node</var>
-  with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start offset</var>.
+  <li><p>If <var title="">start offset</var> is nonzero and equals the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of
+  <var title="">start node</var>, let <var title="">node</var> be the first <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> after
+  <var title="">start node</var> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>.  If there is no such <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a>, return
+  the empty list.
 
-  <li><p>Otherwise, if <var title="">start node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node and <var title="">start offset</var> is its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a>, let <var title="">node</var> be
-  the first <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> after <var title="">start node</var> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>.
+  <li><p>Otherwise, if <var title="">start node</var> is an <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> with at least
+  one child, let <var title="">node</var> be the <var title="">start offset</var>th child of
+  <var title="">start node</var>.
 
   <li><p>Otherwise, let <var title="">node</var> be <var title="">start node</var>.
 
@@ -215,7 +228,7 @@
   offset</var> is not 0, let <var title="">end</var> be the child of <var title="">end node</var> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">end offset</var> &minus; 1.
 
   <li><p>Otherwise, if <var title="">end offset</var> is 0, let <var title="">end</var> be the first <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> before <var title="">end node</var> in
-  <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>.
+  <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>.  If there is no such <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a>, return the empty list.
 
   <li><p>Otherwise, let <var title="">end</var> be <var title="">end node</var>.
 
@@ -225,10 +238,10 @@
   the selection, even if the browser registered the end as the text node "bar".
   -->
   <li><p>While <var title="">node</var> is the first child of its parent and <var title="">end</var> is not a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-descendant-node title=concept-descendant-node>descendant</a> of <var title="">node</var>'s parent,
-  set <var title="">node</var> to its parent.
+  set <var title="">node</var> to <var title="">node</var>'s parent.
 
   <li><p>While <var title="">end</var> is the last child of its parent and <var title="">node</var> is not a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-descendant-node title=concept-descendant-node>descendant</a> of <var title="">end</var>'s parent,
-  set <var title="">end</var> to its parent.
+  set <var title="">end</var> to <var title="">node</var>'s parent.
 
   <li><p>Let <var title="">node list</var> be an empty list of <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a>s.
 
@@ -238,11 +251,11 @@
   <ol>
     <li><p>Append <var title="">node</var> to <var title="">node list</var>.
 
-    <li><p>Set <var title="">node</var> to the first <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>
-    that is after <var title="">node</var> and (if applicable) all its
-    <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-descendant-node title=concept-descendant-node>descendants</a>.  If no such <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> exists, break out of these substeps.
+    <li><p>Set <var title="">node</var> to the first <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a> that is
+    after <var title="">node</var> and all its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-descendant-node title=concept-descendant-node>descendants</a> (if any).  If no such
+    <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> exists, break out of these substeps.
 
-    <li><p>While <var title="">node</var> is an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-ancestor-node title=concept-ancestor-node>ancestor</a> of <var title="">end</var>, set <var title="">node</var> to its first child.
+    <li><p>While <var title="">node</var> is an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-ancestor-node title=concept-ancestor-node>ancestor</a> of <var title="">end</var>, set <var title="">node</var> to <var title="">node</var>'s first child.
   </ol>
 
   <li><p>Return <var title="">node list</var>.
@@ -251,9 +264,7 @@
 
 <h2 id=unstyling-an-element><span class=secno>5 </span>Unstyling an element</h2>
 <p>When a user agent is to <dfn id=unstyle-an-element>unstyle an element</dfn>, it must run the
-following steps.  This algorithm might remove the element from the DOM and
-insert other elements in its place, in which case it will return an ordered
-list of the element's former children.
+following steps.
 
 <ol>
   <li><p>Let <var title="">element</var> be the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> to be unstyled.
@@ -296,7 +307,8 @@
 
       <li><p>Append <var title="">child</var> to <var title="">children</var>.
 
-      <li><p>Insert <var title="">child</var> as the previous sibling of <var title="">element</var>.
+      <li><p>Insert <var title="">child</var> as the previous sibling of
+      <var title="">element</var>.
     </ol>
 
     <li><p>Remove <var title="">element</var>.
@@ -310,8 +322,8 @@
   <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> is not in <var title="">tag list</var>, return the empty list.
 
   <li><p>Let <var title="">new element</var> be a new <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> "span", with the same attributes and <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a>
-  as <var title="">element</var>.
+  <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> "span", with the same attributes and <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> as
+  <var title="">element</var>.
 
   <li><p>Append <var title="">new element</var> to <var title="">element</var>'s
   parent as the previous sibling of <var title="">element</var>.
@@ -335,7 +347,7 @@
   <li><p>Let <var title="">node list</var> be the result of <a href=#decompose-a-range title="decompose
   a range">decomposing</a> <var title="">range</var>.
 
-  <li><p>For each <var title="">node</var> in <var title="">node list</var>, in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>:
+  <li><p>For each <var title="">node</var> in <var title="">node list</var>, in order:
 
   <ol>
     <li><p>If <var title="">node</var> is an <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>:
@@ -366,10 +378,11 @@
     <li><p>Otherwise, if <var title="">node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node:
 
     <ol>
-      <li><p>Let <var title="">new parent</var> be a new <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 the first string in <var title="">tag list</var> (or equal
-      to "span" if <var title="">tag list</var> is empty), with no attributes, and
-      <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> the same as <var title="">node</var>.
+      <li><p>Let <var title="">tag</var> be the first string in <var title="">tag list</var>, or
+      "span" if <var title="">tag list</var> is empty.
+
+      <li><p>Let <var title="">new parent</var> be the result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement(<var title="">tag</var>)</code></a> on
+      the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>.
 
       <li><p>Append <var title="">new parent</var> to <var title="">node</var>'s parent as the
       previous sibling of <var title="">node</var>.
@@ -409,8 +422,7 @@
   <li><p>Let <var title="">node list</var> be the result of <a href=#decompose-a-range title="decompose
   a range">decomposing</a> <var title="">range</var>.
 
-  <li><p>For each <var title="">node</var> in <var title="">node list</var>, in
-  order:
+  <li><p>For each <var title="">node</var> in <var title="">node list</var>, in order:
 
   <ol>
     <li><p>If <var title="">node</var> is an <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>:
@@ -447,10 +459,11 @@
     <li><p>Otherwise, if <var title="">node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node and the computed value of <var title="">property name</var> for <var title="">node</var>'s parent is not <var title="">property value</var>:
 
     <ol>
-      <li><p>Let <var title="">new parent</var> be a new <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> "span", with no attributes, and with <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> equal to <var title="">node</var>'s.
+      <li><p>Let <var title="">new parent</var> be the result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("span")</code></a> on the
+      <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>.
 
-      <li><p>Set the CSS property <var title="">property name</var> of <var title="">new parent</var> to <var title="">property value</var>.
+      <li><p>Set the CSS property <var title="">property name</var> of <var title="">new
+      parent</var> to <var title="">property value</var>.
 
       <li><p>Insert <var title="">new parent</var> as <var title="">node</var>'s
       previous sibling.
@@ -531,6 +544,14 @@
 the other background stuff.  I go with IE 9 RC and Opera 11, which only set
 background-color. -->
 
+<p class=XXX>Firefox and Opera use backColor to set the background color of the
+whole document.  The hiliteColor command can then be used to set the background
+of the selection (supported in all my test browsers except IE).  This
+terminology is inconsistent with foreColor, but the model I've specced leaves
+no way to change the document's overall background color.  I'm not sure how
+important this is, but maybe I should switch, since hiliteColor is more
+interoperably implemented than backColor.
+
 <dd><p><strong>State</strong>: Always false.
 
 <dd><p><strong>Value</strong>: The value is given by the following algorithm:
@@ -578,6 +599,143 @@
 boolean, so I'll go with Firefox and Opera. -->
 
 
+<dt><code title=""><dfn id=command-createlink title=command-createlink>createLink</dfn></code>
+
+<dd><p><strong>Action</strong>: The user agent must run the following steps:
+
+<ol>
+  <li><p>If <var title="">value</var> is the empty string, abort these steps and do
+  nothing.
+  <!-- This matches Firefox 4b11 and Chrome 11 dev.  IE 9 RC and Opera 11 both
+  treat the request literally.  Gecko and WebKit probably have it right here:
+  users who enter no URL are very unlikely to want to link to a relative URL
+  resolving to the current document.  If they really want to, they can always
+  specify "#" for the value, or the author can rewrite it, so it's not like
+  this makes the API less useful. -->
+
+  <li><p>Let <var title="">node list</var> be the result of <a href=#decompose-a-range title="decompose a
+  range">decomposing</a> the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>.
+
+  <li><p>For each <var title="">node</var> in <var title="">node list</var>, in order:
+
+  <ol>
+    <li><p>Let <var title="">text nodes</var> be a list of all <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node
+    <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-descendant-node title=concept-descendant-node>descendants</a> of <var title="">node</var>, or <var title="">node</var> itself if it's a
+    <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node.
+
+    <li><p>For each <var title="">text node</var> in <var title="">text nodes</var>, in
+    <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>:
+
+    <ol>
+      <li><p>Let <var title="">ancestor link</var> be the parent of <var title="">text
+      node</var>.
+
+      <li><p>While <var title="">ancestor link</var> is not an <a href=#html-element>HTML
+      element</a>, or 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> is not "a", or it has no <a href=#html-attribute>HTML
+      attribute</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-local-name title=concept-attr-local-name>local name</a> "href":
+
+      <ol>
+        <li><p>If the parent of <var title="">ancestor link</var> is not an <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>,
+        set <var title="">ancestor link</var> to null and break from this loop.
+
+        <li><p>Otherwise, set <var title="">ancestor link</var> to its parent.
+      </ol>
+
+      <li><p>If <var title="">ancestor link</var> is not null, set its "href" attribute
+      to <var title="">value</var> and continue with the next <var title="">text node</var>.
+      <!-- There are three approaches here.  For instance, if you ask browsers
+      to create a link to "http://example.org" on the "b" here:
+
+        <a href=http://example.com><b>Abc</b></a>
+
+      Chrome 10 dev produces:
+
+        <b><a href=http://example.com>A</a><a href=http://example.org>b</a>
+        <a href=http://example.com>c</a></b>
+
+      Firefox 4b11 produces (roughly):
+
+        <a href=http://example.com><b>A<a href=http://example.org>b</a>c</b></a>
+
+      IE 9 RC and Opera 11 produce simply:
+
+        <a href=http://example.org><b>Abc</b></a>
+
+      The last behavior produces valid markup (unlike Gecko), is simple (unlike
+      WebKit), and probably best matches user expectations.  If you happen to
+      miss out a character when selecting the link you want to change, do you
+      really intend to only change the link of part of it? -->
+
+      <li><p>Let <var title="">new parent</var> be the result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("a")</code></a> on the
+      <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">text node</var>.
+
+      <li><p>Call <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-element-setattribute><code class=external data-anolis-spec=domcore title=dom-Element-setAttribute>setAttribute("href",
+      <var title="">value</var>)</code></a> on <var title="">new parent</var>.
+
+      <li><p>Insert <var title="">new parent</var> into <var title="">text node</var>'s parent as
+      the previous sibling of <var title="">text node</var>.
+
+      <li><p>Append <var title="">text node</var> to <var title="">new parent</var> as its last
+      child.
+    </ol>
+  </ol>
+</ol>
+
+<dd><p><strong>State</strong>: Always false.
+
+<dd><p><strong>Value</strong>: Always the empty string.
+<!-- I'd have expected the value to be the URL, but guess not. -->
+
+
+<dt><code title=""><dfn id=command-fontname title=command-fontname>fontName</dfn></code>
+
+<dd><p><strong>Action</strong>: The user agent must <a href=#style-a-range title="style a
+range">style the <code class=external data-anolis-spec=domrange>Range</code></a> with <var title="">property name</var> equal to
+"font-family", <var title="">property value</var> equal to <var title="">value</var>, and
+<var title="">tag list</var> equal to the empty list.
+<!-- UAs differ a bit in the details here:
+
+IE 9 RC: Empty string sets <font face="">
+Firefox 4b11: Empty string does nothing
+Chrome 11 dev: Empty string does nothing, '"monospace"' same as 'monospace'
+  (i.e., cannot escape font-family keywords because quotes are stripped,
+  clearly wrong)
+Opera 11: Empty string sets <font face="">
+
+Setting an empty font-family has the effect of inheriting the font from the
+parent (although I don't see where the February 24, 2011 CSS 3 Fonts draft says
+that).  Thus it makes sense that if we special-case this, it should be to unset
+the font somehow.
+
+Special-casing the empty string to do nothing doesn't make sense to me.  With
+createLink we'd expect the user to enter the URL themselves, so it makes sense
+to special-case clicking OK without entering anything.  But here it's very
+likely that the font list will be fixed by the author (how many users will
+understand CSS font-family syntax?), so I don't think such usability concerns
+apply. -->
+
+<dd><p><strong>State</strong>: Always false.
+
+<dd><p><strong>Value</strong>: The computed value of the CSS property
+"font-family" for the <a href=#beginning-element>beginning element</a> of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>.
+<!-- Complicated.
+
+IE 9 RC: Always the empty string.  Not very useful.
+Firefox 4b11: Confusing.  Sometimes it returns generic family names, like
+  "sans-serif".  Sometimes it gives specific font names, like "tt" when the
+  font is specified as "monospace".  Sometimes it gives the literal font-family
+  string.  Not sure what it's doing here.
+Chrome 11 dev: Gives the literal value of font-family, except if it's inherited
+  from default values (no explicit style declarations anywhere), when it seems
+  to return the exact font name.
+Opera 11: Returns the literal value of font-family, except if it's inherited
+  from default values, when it returns the empty string.
+
+I'm just going to punt on this and say it should be the computed value of
+font-family.  I'll leave CSSOM to decide what that means if there are no
+applicable style rules. -->
+
+
 <dt><code title=""><dfn id=command-forecolor title=command-forecolor>foreColor</dfn></code>
 
 <dd><p><strong>Action</strong>: If <var title="">value</var> is not a valid CSS color,
@@ -613,6 +771,48 @@
 matches the other browsers. -->
 
 
+<dt><code title=""><dfn id=command-insertimage title=command-insertimage>insertImage</dfn></code>
+
+<dd><p><strong>Action</strong>: The user agent must run the following steps:
+
+<p class=XXX>We need to delete the selection if it's not collapsed.
+
+<ol>
+  <li><p>If <var title="">value</var> is the empty string, abort these steps and do
+  nothing.
+  <!-- Similar logic to createLink, except even more compelling, since an HTML
+  document linking to itself as an image is just silly.  In fact, the current
+  HTML spec instructs UAs to not even try displaying the image, and just fail
+  immediately if the URL is empty.  Firefox 4b11 bails out on an empty string,
+  but the other three browsers I tested stick in the <img> anyway. -->
+
+  <li><p>Let (<var title="">node</var>, <var title="">offset</var>) be the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>'s
+  <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>.
+
+  <li><p>Let <var title="">img</var> be a new <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> "img", the same <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> as <var title="">node</var>, and a
+  single <a href=#html-attribute>HTML attribute</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-local-name title=concept-attr-local-name>local name</a> "src" and with
+  <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-value title=concept-attr-value>value</a> <var title="">value</var>.
+  <!-- No alt text, so it's invalid.  This matches all browsers. -->
+
+  <li><p>If <var title="">node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node, and <var title="">offset</var> is not
+  equal to 0 or the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of <var title="">node</var>, run <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-text-splittext><code class=external data-anolis-spec=domcore title=dom-Text-splitText>splitText(<var title="">offset</var>)</code></a> on
+  <var title="">node</var>.
+
+  <li><p>If <var title="">node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a>, <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment><code class=external data-anolis-spec=domcore>Comment</code></a>, or
+  <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#processinginstruction><code class=external data-anolis-spec=domcore>ProcessingInstruction</code></a> node, run <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-insertbefore><code class=external data-anolis-spec=domcore title=dom-Node-insertBefore>insertBefore(<var title="">img</var>,
+  <var title="">node</var>)</code></a> on the parent of <var title="">node</var>.
+
+  <li><p>Otherwise, let <var title="">child</var> be the <var title="">offset</var>th child of
+  <var title="">node</var> (or null if there is no such child), and run <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-insertbefore><code class=external data-anolis-spec=domcore title=dom-Node-insertBefore>insertBefore(<var title="">img</var>,
+  <var title="">child</var>)</code></a> on <var title="">node</var>.
+</ol>
+
+<dd><p><strong>State</strong>:
+
+<dd><p><strong>Value</strong>:
+
+
 <dt><code title=""><dfn id=command-italic title=command-italic>italic</dfn></code>
 
 <dd><p><strong>Action</strong>: If the of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> for this command is
@@ -628,7 +828,19 @@
 false.
 
 <dd><p><strong>Value</strong>: Always the empty string.
-<!-- See comment for bold -->
+
+
+<dt><code title=""><dfn id=command-unlink title=command-unlink>unlink</dfn></code>
+
+<dd><p><strong>Action</strong>:
+<!-- IE 9 RC unlinks the whole link you're pointing at.  Others just unlink
+your selection, which does nothing if you have nothing selected.
+Unfortunately, everyone but IE winds up doing some DOM surgery here in some
+cases, creating and splitting elements in some cases. -->
+
+<dd><p><strong>State</strong>:
+
+<dd><p><strong>Value</strong>:
 
 
 <dt><code title=""><dfn id=command-underline title=command-underline>underline</dfn></code>
@@ -640,7 +852,6 @@
 <dd class=XXX><p><strong>State</strong>: ...
 
 <dd><p><strong>Value</strong>: Always the empty string.
-<!-- See comment for bold -->
 </dl>
 
 
--- a/implementation.html	Wed Feb 23 15:15:21 2011 -0700
+++ b/implementation.html	Thu Feb 24 15:11:41 2011 -0700
@@ -1,35 +1,21 @@
 <!doctype html>
 <title>execCommand() experimental implementation</title>
-<p><label>Command: <input oninput="command = this.value"></label>
-   <label>Value: <input oninput="val = this.value"></label>
+<p><label>Command: <input></label>
+   <label>Value: <input></label>
 <script>
-// Silly Firefox, prefilling inputs when you reload
-var command = document.querySelector("input").value;
-var val = document.querySelectorAll("input")[1].value;
+var command = document.querySelector("input");
+var val = document.querySelectorAll("input")[1];
 </script>
 <p>Spec:
-<button onclick='myExecCommand(command, null, val)'>exec</button>
-<button onclick='var ret = myQueryCommandState(command); alert(typeof ret + " \"" + ret + "\"")'>state</button>
-<button onclick='var ret = myQueryCommandValue(command); alert(typeof ret + " \"" + ret + "\"")'>value</button>
+<button tabindex=-1 accesskey=a onclick='myExecCommand(command.value, null, val.value)'>exec</button>
+<button tabindex=-1 accesskey=s onclick='var ret = myQueryCommandState(command.value); alert(typeof ret + " \"" + ret + "\"")'>state</button>
+<button tabindex=-1 accesskey=d onclick='var ret = myQueryCommandValue(command.value); alert(typeof ret + " \"" + ret + "\"")'>value</button>
 <p>Actual:
-<button onclick='execCommand(command, null, val)'>exec</button>
-<button onclick='var ret = queryCommandState(command); alert(typeof ret + " \"" + ret + "\"")'>state</button>
-<button onclick='var ret = queryCommandValue(command); alert(typeof ret + " \"" + ret + "\"")'>value</button>
-<div contenteditable=true id=test>
-	<br> <br>
-	Some simple text<br>
-	<span>Some more text</span><br>
-	<b>Some more text</b><br>
-	<strong>Some more text</strong><br>
-	<span style=font-weight:bold>Some more text</span><br>
-	<i>Some more text</i><br>
-	<span style=font-style:italic;font-weight:bold>Some more text</span><br>
-	<b>Some <span style=font-weight:200>more <b>te<span style=font-weight:bold>xt<strong>!</strong></span></b></span></b><br>
-	<p>Some simple text
-	<p><span>Some more text</span>
-	<p><b>Some more text</b>
-	<p><i>Some more text</i>
-	<p><b>Some <span style=font-weight:200>more <b>te<span style=font-weight:bold>xt<strong>!</strong></span></b></span></b>
+<button tabindex=-1 accesskey=z onclick='execCommand(command.value, null, val.value)'>exec</button>
+<button tabindex=-1 accesskey=x onclick='var ret = queryCommandState(command.value); alert(typeof ret + " \"" + ret + "\"")'>state</button>
+<button tabindex=-1 accesskey=c onclick='var ret = queryCommandValue(command.value); alert(typeof ret + " \"" + ret + "\"")'>value</button>
+<div contenteditable=true>
+	Abcdef
 </div>
 <script>
 "use strict";
@@ -150,7 +136,11 @@
 
 function activeRange(doc) {
 	// "Let selection be the result of calling getSelection() on the Document."
-	var selection = doc.getSelection();
+	//
+	// We call getSelection() on defaultView instead, because Firefox and Opera
+	// don't follow the DOM Range spec here:
+	// https://bugzilla.mozilla.org/show_bug.cgi?id=636512
+	var selection = doc.defaultView.getSelection();
 
 	// "If there are no Ranges associated with selection, return null."
 	if (selection.rangeCount == 0) {
@@ -452,7 +442,7 @@
 			// "Let new parent be a new HTML element with local name equal to
 			// the first string in tag list (or equal to "span" if tag list is
 			// empty), with no attributes, and ownerDocument the same as node."
-			newParent = node.ownerDocument.createElement(tagList.length ? tagList[0] : "span");
+			var newParent = node.ownerDocument.createElement(tagList.length ? tagList[0] : "span");
 
 			// "Append new parent to node's parent as the previous sibling of
 			// node."
@@ -563,6 +553,82 @@
 		}
 		break;
 
+		case "createlink":
+		// "If value is the empty string, do nothing."
+		if (value === "") {
+			break;
+		}
+
+		// "Let node list be the result of decomposing the Range."
+		var nodeList = decomposeRange(range);
+
+		// "For each node in node list, in order:"
+		for (var i = 0; i < nodeList.length; i++) {
+			var node = nodeList[i];
+
+			// "Let text nodes be a list of all Text node descendants of node,
+			// or node itself if it's a Text node."
+			var textNodes = [];
+			if (node.nodeType == Node.TEXT_NODE) {
+				textNodes.push(node);
+			} else {
+				for (var cur = node.firstChild;
+				cur && cur.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_CONTAINS;
+				cur = nextNode(cur)) {
+					if (cur.nodeType == Node.TEXT_NODE) {
+						textNodes.push(cur);
+					}
+				}
+			}
+
+			// "For each text node in text nodes, in tree order:"
+			for (var j = 0; j < textNodes.length; j++) {
+				var textNode = textNodes[j];
+
+				// "Let ancestor link be the parent of text node."
+				var ancestorLink = textNode.parentNode;
+
+				// "While ancestor link is not an HTML element, or its local
+				// name is not "a", or it has no HTML attribute with local name
+				// "href":"
+				while (ancestorLink.namespaceURI != htmlNamespace
+				|| ancestorLink.nodeType != Node.ELEMENT_NODE
+				|| ancestorLink.tagName != "A"
+				|| !ancestorLink.hasAttribute("href")) {
+					// "If the parent of ancestor link is not an Element, set
+					// ancestor link to null and break from this loop."
+					if (!ancestorLink.parentNode
+					|| ancestorLink.parentNode.nodeType != Node.ELEMENT_NODE) {
+						ancestorLink = null;
+						break;
+					}
+
+					// "Otherwise, set ancestor link to its parent."
+					ancestorLink = ancestorLink.parentNode;
+				}
+
+				// "If ancestor link is not null, set its "href" attribute to
+				// value and continue with the next text node."
+				if (ancestorLink) {
+					ancestorLink.setAttribute("href", value);
+					continue;
+				}
+
+				// "Let new parent be a new HTML element with local name "a",
+				// the same ownerDocument as text node, and a single HTML
+				// attribute with local name "href" and value value."
+				var newParent = textNode.ownerDocument.createElement("a");
+				newParent.setAttribute("href", value);
+
+				// "Insert new parent into text node's parent as the previous
+				// sibling of text node."
+				textNode.parentNode.insertBefore(newParent, textNode);
+
+				// "Append text node to new parent as its last child."
+				newParent.appendChild(textNode);
+			}
+		}
+
 		case "foreColor":
 		// Hacky test to see if the color is valid
 		var testEl = document.createElement("span");
@@ -621,21 +687,31 @@
 		return "";
 	}
 
+	var style = getComputedStyle(beginningElement(range));
+
 	switch (commandId) {
 		case "backcolor":
+		// "Let element be the beginning element of the Range."
 		var element = beginningElement(range);
+		// "While the computed style of "background-color" on element is any
+		// fully transparent value, set element to its parent."
 		while (element.nodeType == Node.ELEMENT_NODE
 		&& (getComputedStyle(element).backgroundColor == "rgba(0, 0, 0, 0)"
-		|| getComputedStyle(element).backgroundColor === "")) {
+		|| getComputedStyle(element).backgroundColor === ""
+		|| getComputedStyle(element).backgroundColor == "transparent")) {
 			element = element.parentNode;
 		}
+		// "Return the computed style of "background-color" for element."
 		if (element.nodeType != Node.ELEMENT_NODE) {
 			return 'rgb(255, 255, 255)';
 		}
 		return getComputedStyle(element).backgroundColor;
 
+		case "fontname":
+		return style.fontFamily;
+
 		case "forecolor":
-		return getComputedStyle(beginningElement(range)).color;
+		return style.color;
 
 		default:
 		return "";
--- a/preprocess	Wed Feb 23 15:15:21 2011 -0700
+++ b/preprocess	Thu Feb 24 15:11:41 2011 -0700
@@ -13,6 +13,7 @@
     "bpnode": "<span data-anolis-spec=domrange title=concept-boundary-point-node>node</span>",
     "bpoffset": "<span data-anolis-spec=domrange title=concept-boundary-point-offset>offset</span>",
     "bpposition": "<span data-anolis-spec=domrange title=concept-bp-position>position</span>",
+    "collection": "<span data-anolis-spec=html title=collections>collection</span>",
     "comment": "<code data-anolis-spec=domcore>Comment</code>",
     "contextobject": "<span data-anolis-spec=domrange>context object</span>",
     "descendant": "<span data-anolis-spec=domcore title=concept-descendant-node>descendant</span>",
--- a/source.html	Wed Feb 23 15:15:21 2011 -0700
+++ b/source.html	Thu Feb 24 15:11:41 2011 -0700
@@ -77,17 +77,26 @@
   <li><p>Also not sure about computed style.  There are differences between
   "computed" and "used" and things like that, what do we actually want here?
 
-  <li><p>Some of the DOM stuff might benefit from more precision.  E.g., is
-  there a precise algorithm for what it means to append a node someplace, if
-  that node is already somewhere in the DOM?  What does that do if it's
-  selected, it has state (like a video or animated image), etc.?
+  <li><p>The wording I use for DOM stuff is a bit of a mess, often either
+  imprecise or unreasonably verbose.  I'm not quite sure how to fix it.
+
+  <li><p>I haven't put any thought yet into collapsed ranges or selections.
+  Currently my algorithms mostly do nothing if the selection is collapsed,
+  which is of course wrong.  E.g., bold with collapsed selection should put
+  &lt;b>&lt;/b> at the cursor, generally.
+
+  <li><p>I also don't pay attention to what happens to the selection when you
+  mutate the DOM.  This is essential.
 </ul>
 
 
 <h2>Definitions</h2>
 
 <p>A [[node]] is an <dfn>HTML element</dfn> if it is an [[element]] whose
-[[namespace]] is the <span data-anolis-spec=domcore>HTML namespace</span>.
+[[namespace]] is the [[htmlnamespace]].  An <code
+data-anolis-spec=domcore>Attr</code> is an <dfn>HTML attribute</dfn> if its
+<span data-anolis-spec=domcore title=concept-attr-namespace>namespace</span> is
+the [[htmlnamespace]].
 
 <p>The <dfn>first node</dfn> of a [[range]] is the [[node]] returned by the
 following algorithm:
@@ -105,7 +114,8 @@
   [[comment]], or [[processinginstruction]] node, return that.
 
   <li><p>If <var>range</var>'s [[rangestart]] [[bpnode]] has children,
-  return the child with [[index]] equal to the [[rangestart]] [[bpoffset]].
+  return the child whose [[index]] is equal to <var>range</var>'s
+  [[rangestart]] [[bpoffset]].
 
   <li><p>Return <var>range</var>'s [[rangestart]] [[bpnode]].
 </ol>
@@ -137,10 +147,15 @@
   <!-- This is what Firefox seems to do, no reason to change it . . . -->
 
   <p class=note>In user agents that support only one [[range]] per
-  [[selection]], <var>range</var> will simply be the only [[range]] associated
-  to <var>selection</var>.
+  [[selection]], the active range is simply the only one in the selection.
 </ol>
 
+<p>When the user agent is instructed to run a particular method, it must follow
+the steps defined for that method in the appropriate specification, not act as
+though the method had actually been called from JavaScript.  In particular,
+if the author has overridden the method with a custom method, the standard
+method must be run rather than the custom one.
+
 
 <h2>Decomposing a Range into Nodes</h2>
 <p>When a user agent is to <dfn>decompose a [[range]]</dfn> <var
@@ -177,8 +192,7 @@
 
     <li><p>Run <code data-anolis-spec=domcore
     title=dom-Text-splitText>splitText(<var>end offset</var> &minus; <var
-    title>start offset</var>)</code> on <var>start node</var> and set
-    <var>start node</var> to the previous sibling of the result.
+    title>start offset</var>)</code> on <var>start node</var>.
 
     <li><p>Return the list consisting of the single [[node]] <var>start
     node</var>, and abort these steps.
@@ -195,17 +209,16 @@
   offset</var> is neither 0 nor the [[nodelength]] of <var>end
   node</var>, run <code data-anolis-spec=domcore
   title=dom-Text-splitText>splitText(<var>end offset</var>)</code> on
-  <var>end node</var> and set <var>end node</var> to the previous
-  sibling of the returned node.  Set <var>end offset</var> to the
-  [[nodelength]] of the new <var>end node</var>.
+  <var>end node</var>.
 
-  <li><p>If <var>start node</var> is an [[element]] with at least one
-  child, let <var>node</var> be the child of <var>start node</var>
-  with [[index]] <var>start offset</var>.
+  <li><p>If <var>start offset</var> is nonzero and equals the [[nodelength]] of
+  <var>start node</var>, let <var>node</var> be the first [[node]] after
+  <var>start node</var> in [[treeorder]].  If there is no such [[node]], return
+  the empty list.
 
-  <li><p>Otherwise, if <var>start node</var> is a [[text]] node and <var
-  title>start offset</var> is its [[nodelength]], let <var>node</var> be
-  the first [[node]] after <var>start node</var> in [[treeorder]].
+  <li><p>Otherwise, if <var>start node</var> is an [[element]] with at least
+  one child, let <var>node</var> be the <var>start offset</var>th child of
+  <var>start node</var>.
 
   <li><p>Otherwise, let <var>node</var> be <var>start node</var>.
 
@@ -215,7 +228,7 @@
 
   <li><p>Otherwise, if <var>end offset</var> is 0, let <var
   title>end</var> be the first [[node]] before <var>end node</var> in
-  [[treeorder]].
+  [[treeorder]].  If there is no such [[node]], return the empty list.
 
   <li><p>Otherwise, let <var>end</var> be <var>end node</var>.
 
@@ -226,11 +239,11 @@
   -->
   <li><p>While <var>node</var> is the first child of its parent and <var
   title>end</var> is not a [[descendant]] of <var>node</var>'s parent,
-  set <var>node</var> to its parent.
+  set <var>node</var> to <var>node</var>'s parent.
 
   <li><p>While <var>end</var> is the last child of its parent and <var
   title>node</var> is not a [[descendant]] of <var>end</var>'s parent,
-  set <var>end</var> to its parent.
+  set <var>end</var> to <var>node</var>'s parent.
 
   <li><p>Let <var>node list</var> be an empty list of [[node]]s.
 
@@ -240,12 +253,12 @@
   <ol>
     <li><p>Append <var>node</var> to <var>node list</var>.
 
-    <li><p>Set <var>node</var> to the first [[node]] in [[treeorder]]
-    that is after <var>node</var> and (if applicable) all its
-    [[descendants]].  If no such [[node]] exists, break out of these substeps.
+    <li><p>Set <var>node</var> to the first [[node]] in [[treeorder]] that is
+    after <var>node</var> and all its [[descendants]] (if any).  If no such
+    [[node]] exists, break out of these substeps.
 
     <li><p>While <var>node</var> is an [[ancestor]] of <var
-    title>end</var>, set <var>node</var> to its first child.
+    title>end</var>, set <var>node</var> to <var>node</var>'s first child.
   </ol>
 
   <li><p>Return <var>node list</var>.
@@ -254,13 +267,10 @@
 
 <h2>Unstyling an element</h2>
 <p>When a user agent is to <dfn>unstyle an element</dfn>, it must run the
-following steps.  This algorithm might remove the element from the DOM and
-insert other elements in its place, in which case it will return an ordered
-list of the element's former children.
+following steps.
 
 <ol>
-  <li><p>Let <var>element</var> be the <code
-  data-anolis-spec=domcore>Element</code> to be unstyled.
+  <li><p>Let <var>element</var> be the [[element]] to be unstyled.
 
   <li><p>Let <var>property name</var> and <var>tag list</var> be as
   in the invoking algorithm.
@@ -296,13 +306,12 @@
     <li><p>While <var>element</var> has children:
 
     <ol>
-      <li><p>Let <var>child</var> be the first child of <var
-      title>element</var>.
+      <li><p>Let <var>child</var> be the first child of <var>element</var>.
 
       <li><p>Append <var>child</var> to <var>children</var>.
 
-      <li><p>Insert <var>child</var> as the previous sibling of <var
-      title>element</var>.
+      <li><p>Insert <var>child</var> as the previous sibling of
+      <var>element</var>.
     </ol>
 
     <li><p>Remove <var>element</var>.
@@ -310,16 +319,14 @@
     <li><p>Return <var>children</var>.
   </ol>
 
-  <li><p>Unset the CSS property <var>property name</var> of <var
-  title>element</var>.
+  <li><p>Unset the CSS property <var>property name</var> of <var>element</var>.
 
   <li><p>If <var>element</var> is not an <span>HTML element</span> or its
   [[localname]] is not in <var>tag list</var>, return the empty list.
 
   <li><p>Let <var>new element</var> be a new <span>HTML element</span> with
-  [[localname]] "span", with the same attributes and <code
-  data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code>
-  as <var>element</var>.
+  [[localname]] "span", with the same attributes and [[ownerdocument]] as
+  <var>element</var>.
 
   <li><p>Append <var>new element</var> to <var>element</var>'s
   parent as the previous sibling of <var>element</var>.
@@ -343,8 +350,7 @@
   <li><p>Let <var>node list</var> be the result of <span title="decompose
   a range">decomposing</span> <var>range</var>.
 
-  <li><p>For each <var>node</var> in <var>node list</var>, in <span
-  data-anolis-spec=domcore>tree order</span>:
+  <li><p>For each <var>node</var> in <var>node list</var>, in order:
 
   <ol>
     <li><p>If <var>node</var> is an <code
@@ -378,10 +384,13 @@
     data-anolis-spec=domcore>Text</code> node:
 
     <ol>
-      <li><p>Let <var>new parent</var> be a new <span>HTML element</span> with
-      [[localname]] equal to the first string in <var>tag list</var> (or equal
-      to "span" if <var>tag list</var> is empty), with no attributes, and
-      [[ownerdocument]] the same as <var>node</var>.
+      <li><p>Let <var>tag</var> be the first string in <var>tag list</var>, or
+      "span" if <var>tag list</var> is empty.
+
+      <li><p>Let <var>new parent</var> be the result of calling <code
+      data-anolis-spec=domcore
+      title=dom-Document-createElement>createElement(<var>tag</var>)</code> on
+      the [[ownerdocument]] of <var>node</var>.
 
       <li><p>Append <var>new parent</var> to <var>node</var>'s parent as the
       previous sibling of <var>node</var>.
@@ -421,8 +430,7 @@
   <li><p>Let <var>node list</var> be the result of <span title="decompose
   a range">decomposing</span> <var>range</var>.
 
-  <li><p>For each <var>node</var> in <var>node list</var>, in
-  order:
+  <li><p>For each <var>node</var> in <var>node list</var>, in order:
 
   <ol>
     <li><p>If <var>node</var> is an <code
@@ -466,14 +474,13 @@
     title>property value</var>:
 
     <ol>
-      <li><p>Let <var>new parent</var> be a new <span>HTML element</span> with
-      [[localname]] "span", with no attributes, and with <code
+      <li><p>Let <var>new parent</var> be the result of calling <code
       data-anolis-spec=domcore
-      title=dom-Node-ownerDocument>ownerDocument</code> equal to <var
-      title>node</var>'s.
+      title=dom-Document-createElement>createElement("span")</code> on the
+      [[ownerdocument]] of <var>node</var>.
 
-      <li><p>Set the CSS property <var>property name</var> of <var
-      title>new parent</var> to <var>property value</var>.
+      <li><p>Set the CSS property <var>property name</var> of <var>new
+      parent</var> to <var>property value</var>.
 
       <li><p>Insert <var>new parent</var> as <var>node</var>'s
       previous sibling.
@@ -557,6 +564,14 @@
 the other background stuff.  I go with IE 9 RC and Opera 11, which only set
 background-color. -->
 
+<p class=XXX>Firefox and Opera use backColor to set the background color of the
+whole document.  The hiliteColor command can then be used to set the background
+of the selection (supported in all my test browsers except IE).  This
+terminology is inconsistent with foreColor, but the model I've specced leaves
+no way to change the document's overall background color.  I'm not sure how
+important this is, but maybe I should switch, since hiliteColor is more
+interoperably implemented than backColor.
+
 <dd><p><strong>State</strong>: Always false.
 
 <dd><p><strong>Value</strong>: The value is given by the following algorithm:
@@ -604,6 +619,146 @@
 boolean, so I'll go with Firefox and Opera. -->
 
 
+<dt><code title><dfn title=command-createlink>createLink</dfn></code>
+
+<dd><p><strong>Action</strong>: The user agent must run the following steps:
+
+<ol>
+  <li><p>If <var>value</var> is the empty string, abort these steps and do
+  nothing.
+  <!-- This matches Firefox 4b11 and Chrome 11 dev.  IE 9 RC and Opera 11 both
+  treat the request literally.  Gecko and WebKit probably have it right here:
+  users who enter no URL are very unlikely to want to link to a relative URL
+  resolving to the current document.  If they really want to, they can always
+  specify "#" for the value, or the author can rewrite it, so it's not like
+  this makes the API less useful. -->
+
+  <li><p>Let <var>node list</var> be the result of <span title="decompose a
+  range">decomposing</span> the [[range]].
+
+  <li><p>For each <var>node</var> in <var>node list</var>, in order:
+
+  <ol>
+    <li><p>Let <var>text nodes</var> be a list of all [[text]] node
+    [[descendants]] of <var>node</var>, or <var>node</var> itself if it's a
+    [[text]] node.
+
+    <li><p>For each <var>text node</var> in <var>text nodes</var>, in
+    [[treeorder]]:
+
+    <ol>
+      <li><p>Let <var>ancestor link</var> be the parent of <var>text
+      node</var>.
+
+      <li><p>While <var>ancestor link</var> is not an <span>HTML
+      element</span>, or its [[localname]] is not "a", or it has no <span>HTML
+      attribute</span> with [[attrlocalname]] "href":
+
+      <ol>
+        <li><p>If the parent of <var>ancestor link</var> is not an [[element]],
+        set <var>ancestor link</var> to null and break from this loop.
+
+        <li><p>Otherwise, set <var>ancestor link</var> to its parent.
+      </ol>
+
+      <li><p>If <var>ancestor link</var> is not null, set its "href" attribute
+      to <var>value</var> and continue with the next <var>text node</var>.
+      <!-- There are three approaches here.  For instance, if you ask browsers
+      to create a link to "http://example.org" on the "b" here:
+
+        <a href=http://example.com><b>Abc</b></a>
+
+      Chrome 10 dev produces:
+
+        <b><a href=http://example.com>A</a><a href=http://example.org>b</a>
+        <a href=http://example.com>c</a></b>
+
+      Firefox 4b11 produces (roughly):
+
+        <a href=http://example.com><b>A<a href=http://example.org>b</a>c</b></a>
+
+      IE 9 RC and Opera 11 produce simply:
+
+        <a href=http://example.org><b>Abc</b></a>
+
+      The last behavior produces valid markup (unlike Gecko), is simple (unlike
+      WebKit), and probably best matches user expectations.  If you happen to
+      miss out a character when selecting the link you want to change, do you
+      really intend to only change the link of part of it? -->
+
+      <li><p>Let <var>new parent</var> be the result of calling <code
+      data-anolis-spec=domcore
+      title=dom-Document-createElement>createElement("a")</code> on the
+      [[ownerdocument]] of <var>text node</var>.
+
+      <li><p>Call <code data-anolis-spec=domcore
+      title=dom-Element-setAttribute>setAttribute("href",
+      <var>value</var>)</code> on <var>new parent</var>.
+
+      <li><p>Insert <var>new parent</var> into <var>text node</var>'s parent as
+      the previous sibling of <var>text node</var>.
+
+      <li><p>Append <var>text node</var> to <var>new parent</var> as its last
+      child.
+    </ol>
+  </ol>
+</ol>
+
+<dd><p><strong>State</strong>: Always false.
+
+<dd><p><strong>Value</strong>: Always the empty string.
+<!-- I'd have expected the value to be the URL, but guess not. -->
+
+
+<dt><code title><dfn title=command-fontname>fontName</dfn></code>
+
+<dd><p><strong>Action</strong>: The user agent must <span title="style a
+range">style the [[range]]</span> with <var>property name</var> equal to
+"font-family", <var>property value</var> equal to <var>value</var>, and
+<var>tag list</var> equal to the empty list.
+<!-- UAs differ a bit in the details here:
+
+IE 9 RC: Empty string sets <font face="">
+Firefox 4b11: Empty string does nothing
+Chrome 11 dev: Empty string does nothing, '"monospace"' same as 'monospace'
+  (i.e., cannot escape font-family keywords because quotes are stripped,
+  clearly wrong)
+Opera 11: Empty string sets <font face="">
+
+Setting an empty font-family has the effect of inheriting the font from the
+parent (although I don't see where the February 24, 2011 CSS 3 Fonts draft says
+that).  Thus it makes sense that if we special-case this, it should be to unset
+the font somehow.
+
+Special-casing the empty string to do nothing doesn't make sense to me.  With
+createLink we'd expect the user to enter the URL themselves, so it makes sense
+to special-case clicking OK without entering anything.  But here it's very
+likely that the font list will be fixed by the author (how many users will
+understand CSS font-family syntax?), so I don't think such usability concerns
+apply. -->
+
+<dd><p><strong>State</strong>: Always false.
+
+<dd><p><strong>Value</strong>: The computed value of the CSS property
+"font-family" for the <span>beginning element</span> of the [[range]].
+<!-- Complicated.
+
+IE 9 RC: Always the empty string.  Not very useful.
+Firefox 4b11: Confusing.  Sometimes it returns generic family names, like
+  "sans-serif".  Sometimes it gives specific font names, like "tt" when the
+  font is specified as "monospace".  Sometimes it gives the literal font-family
+  string.  Not sure what it's doing here.
+Chrome 11 dev: Gives the literal value of font-family, except if it's inherited
+  from default values (no explicit style declarations anywhere), when it seems
+  to return the exact font name.
+Opera 11: Returns the literal value of font-family, except if it's inherited
+  from default values, when it returns the empty string.
+
+I'm just going to punt on this and say it should be the computed value of
+font-family.  I'll leave CSSOM to decide what that means if there are no
+applicable style rules. -->
+
+
 <dt><code title><dfn title=command-forecolor>foreColor</dfn></code>
 
 <dd><p><strong>Action</strong>: If <var>value</var> is not a valid CSS color,
@@ -639,6 +794,53 @@
 matches the other browsers. -->
 
 
+<dt><code title><dfn title=command-insertimage>insertImage</dfn></code>
+
+<dd><p><strong>Action</strong>: The user agent must run the following steps:
+
+<p class=XXX>We need to delete the selection if it's not collapsed.
+
+<ol>
+  <li><p>If <var>value</var> is the empty string, abort these steps and do
+  nothing.
+  <!-- Similar logic to createLink, except even more compelling, since an HTML
+  document linking to itself as an image is just silly.  In fact, the current
+  HTML spec instructs UAs to not even try displaying the image, and just fail
+  immediately if the URL is empty.  Firefox 4b11 bails out on an empty string,
+  but the other three browsers I tested stick in the <img> anyway. -->
+
+  <li><p>Let (<var>node</var>, <var>offset</var>) be the [[range]]'s
+  [[rangestart]].
+
+  <li><p>Let <var>img</var> be a new <span>HTML element</span> with
+  [[localname]] "img", the same [[ownerdocument]] as <var>node</var>, and a
+  single <span>HTML attribute</span> with [[attrlocalname]] "src" and with
+  [[attrvalue]] <var>value</var>.
+  <!-- No alt text, so it's invalid.  This matches all browsers. -->
+
+  <li><p>If <var>node</var> is a [[text]] node, and <var>offset</var> is not
+  equal to 0 or the [[nodelength]] of <var>node</var>, run <code
+  data-anolis-spec=domcore
+  title=dom-Text-splitText>splitText(<var>offset</var>)</code> on
+  <var>node</var>.
+
+  <li><p>If <var>node</var> is a [[text]], [[comment]], or
+  [[processinginstruction]] node, run <code data-anolis-spec=domcore
+  title=dom-Node-insertBefore>insertBefore(<var>img</var>,
+  <var>node</var>)</code> on the parent of <var>node</var>.
+
+  <li><p>Otherwise, let <var>child</var> be the <var>offset</var>th child of
+  <var>node</var> (or null if there is no such child), and run <code
+  data-anolis-spec=domcore
+  title=dom-Node-insertBefore>insertBefore(<var>img</var>,
+  <var>child</var>)</code> on <var>node</var>.
+</ol>
+
+<dd><p><strong>State</strong>:
+
+<dd><p><strong>Value</strong>:
+
+
 <dt><code title><dfn title=command-italic>italic</dfn></code>
 
 <dd><p><strong>Action</strong>: If the of the [[range]] for this command is
@@ -654,7 +856,19 @@
 false.
 
 <dd><p><strong>Value</strong>: Always the empty string.
-<!-- See comment for bold -->
+
+
+<dt><code title><dfn title=command-unlink>unlink</dfn></code>
+
+<dd><p><strong>Action</strong>:
+<!-- IE 9 RC unlinks the whole link you're pointing at.  Others just unlink
+your selection, which does nothing if you have nothing selected.
+Unfortunately, everyone but IE winds up doing some DOM surgery here in some
+cases, creating and splitting elements in some cases. -->
+
+<dd><p><strong>State</strong>:
+
+<dd><p><strong>Value</strong>:
 
 
 <dt><code title><dfn title=command-underline>underline</dfn></code>
@@ -666,7 +880,6 @@
 <dd class=XXX><p><strong>State</strong>: ...
 
 <dd><p><strong>Value</strong>: Always the empty string.
-<!-- See comment for bold -->
 </dl>
 
 
--- a/xrefs.json	Wed Feb 23 15:15:21 2011 -0700
+++ b/xrefs.json	Thu Feb 24 15:11:41 2011 -0700
@@ -3,12 +3,17 @@
   "beginning element": "beginning-element",
   "command-backcolor": "command-backcolor",
   "command-bold": "command-bold",
+  "command-createlink": "command-createlink",
+  "command-fontname": "command-fontname",
   "command-forecolor": "command-forecolor",
+  "command-insertimage": "command-insertimage",
   "command-italic": "command-italic",
   "command-underline": "command-underline",
+  "command-unlink": "command-unlink",
   "decompose a range": "decompose-a-range",
   "execcommand()": "execcommand()",
   "first node": "first-node",
+  "html attribute": "html-attribute",
   "html element": "html-element",
   "querycommandstate()": "querycommandstate()",
   "querycommandvalue()": "querycommandvalue()",