--- 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-—-last-update-23-february-2011>Work in Progress — Last Update 23 February 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-—-last-update-24-february-2011>Work in Progress — Last Update 24 February 2011</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <ayg+spec@aryeh.name>
@@ -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
+ <b></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 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> − <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> − <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> − 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
+ <b></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> − <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()",