--- a/editcommands.html Sun Feb 20 15:11:49 2011 -0700
+++ b/editcommands.html Mon Feb 21 14:25:51 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-20-february-2011>Work in Progress — Last Update 20 February 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-—-last-update-21-february-2011>Work in Progress — Last Update 21 February 2011</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <ayg+spec@aryeh.name>
@@ -78,18 +78,29 @@
<h2 id=definitions><span class=secno>3 </span>Definitions</h2>
-<p class=XXX>This definition is just an ugly workaround for the annoyance of
-xrefs. Fix it sometime.
+<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>.
-<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-with-name>HTML element
-with name</dfn> <var title="">name</var> 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>, its <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>, and 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
-<var title="">name</var>.
+<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:
-<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 its <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>,
-if that 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; or else
-the child of its <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> 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 its
-<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>, if that exists; or else its <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>
+ <li><p>Let <var title="">range</var> be the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> under discussion.
+
+ <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-offset title=concept-boundary-point-offset>offset</a> is equal 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 its <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>, return 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> that is after 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-node title=concept-boundary-point-node>node</a> 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) 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 last <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 the document.
+
+ <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> 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, 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>.
+
+ <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>
<p>The <dfn id=beginning-element>beginning element</dfn> of a <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> is its <a href=#first-node>first
node</a> if that 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>; or the parent of its <a href=#first-node>first
@@ -119,27 +130,42 @@
<p class=XXX>Figure out something sensible here.
+ <li><p>If <var title="">start node</var> and <var title="">end node</var> are both
+ <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> nodes, and <var title="">start node</var> is the same as <var title="">end
+ node</var>, and neither <var title="">start offset</var> nor <var title="">end
+ offset</var> is 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="">start
+ node</var>:
+
+ <ol>
+ <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="">start offset</var>)</code></a> on
+ <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>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.
+ </ol>
+
<li><p>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 neither 0 nor the <a href=http://html5.org/specs/dom-range.html#concept-node-length><code class=external data-anolis-spec=domrange title=concept-node-length>length</code></a> of <var title="">start
+ 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="">start
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="">start offset</var>)</code></a> on
<var title="">start node</var> and set <var title="">start node</var> to the
returned node. Set <var title="">start offset</var> to 0.
<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 href=http://html5.org/specs/dom-range.html#concept-node-length><code class=external data-anolis-spec=domrange title=concept-node-length>length</code></a> of <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 href=http://html5.org/specs/dom-range.html#concept-node-length><code class=external data-anolis-spec=domrange title=concept-node-length>length</code></a> of the new <var title="">end node</var>.
-
- <p class=XXX>What if the start and end nodes are the same <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?
- Handle explicitly.
+ <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>.
<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>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 href=http://html5.org/specs/dom-range.html#concept-node-length><code class=external data-anolis-spec=domrange title=concept-node-length>length</code></a>, let <var title="">node</var> be
+ <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, let <var title="">node</var> be <var title="">start node</var>.
@@ -152,17 +178,30 @@
<li><p>Otherwise, let <var title="">end</var> be <var title="">end node</var>.
+ <!-- We try to include a node's parent instead of that node if possible,
+ because this generally reduces the number of nodes we're handling. So if the
+ string "oo bar" was selected in <b>Foo <i>bar</i></b>, we'd add the <i> to
+ 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.
+
+ <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.
+
<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.
<li><p>While <var title="">node</var> is not after <var title="">end</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>Append <var title="">node</var> to <var title="">node list</var>.
+ <li><p>Append <var title="">node</var> to <var title="">node list</var>.
- <li>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 (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>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.
</ol>
<li><p>Return <var title="">node list</var>.
@@ -171,7 +210,9 @@
<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.
+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.
<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.
@@ -179,48 +220,77 @@
<li><p>Let <var title="">property name</var> and <var title="">tag list</var> be as
in the invoking algorithm.
+ <li><p>Let <var title="">element children</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> children of
+ <var title="">element</var>.
+
+ <li><p><a href=#unstyle-an-element title="unstyle an element">Unstyle</a> each <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> in
+ <var title="">element children</var>, in order.
+
+ <p class=note>Unstyling an element can change the number of children its
+ parent has, so the list of children to unstyle needs to be computed
+ beforehand.
+
+ <li><p>Let <var title="">children</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.
+
<li><p>If either
<ul>
- <li><p><var title="">element</var> is an <a href=#html-element-with-name>HTML element with
- name</a> either "span" or in <var title="">tag list</var>, and it has
+ <li><p><var title="">element</var> is an <a href=#html-element>HTML element</a> with
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> either "span" or in <var title="">tag list</var>, and it has
only a single attribute, and that attribute is named "style", and
that style attribute sets only the CSS property <var title="">property
name</var>; or
- <li><p><var title="">element</var> is an <a href=#html-element-with-name>HTML element with
- name</a> in <var title="">tag list</var> and it has no attributes,
+ <li><p><var title="">element</var> is an <a href=#html-element>HTML element</a> with
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> in <var title="">tag list</var> and it has no attributes,
</ul>
<p>then:
<ol>
- <li><p>While <var title="">element</var> has children, insert the first child
- of <var title="">element</var> as the previous sibling of <var title="">element</var>.
+ <li><p>While <var title="">element</var> has children:
+
+ <ol>
+ <li><p>Let <var title="">child</var> be the first child of <var title="">element</var>.
+
+ <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>.
+ </ol>
<li><p>Remove <var title="">element</var>.
- <li><p>Abort this algorithm.
+ <li><p>Return <var title="">children</var> and abort this algorithm.
</ol>
<li><p>Unset the CSS property <var title="">property name</var> of <var title="">element</var>.
- <li><p>If <var title="">element</var> is an <a href=#html-element-with-name>HTML element with
- name</a> in <var title="">tag list</var>:
+ <li><p>If <var title="">element</var> is an <a href=#html-element>HTML element</a> with
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> in <var title="">tag list</var>:
<ol>
- <li><p>Let <var title="">new element</var> be a new <a href=#html-element-with-name>HTML element with
- 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>
+ <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>.
<li><p>Append <var title="">new element</var> to <var title="">element</var>'s
parent as the previous sibling of <var title="">element</var>.
- <li><p>While <var title="">element</var> has children, append the first child
- of <var title="">element</var> as the last child of <var title="">new element</var>.
+ <li><p>While <var title="">element</var> has children:
+
+ <ol>
+ <li><p>Let <var title="">child</var> be the first child of <var title="">element</var>.
+
+ <li><p>Append <var title="">child</var> to <var title="">children</var>.
+
+ <li><p>Append <var title="">child</var> as the last child of <var title="">new
+ element</var>.
+ </ol>
<li><p>Remove <var title="">element</var>.
</ol>
+
+ <li><p>Return <var title="">children</var>.
</ol>
@@ -259,23 +329,39 @@
<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>:
<ol>
- <li><p>If <var title="">node</var> is an <a href=#html-element-with-name>HTML element with name</a>
+ <li><p>If <var title="">node</var> is an <a href=#html-element>HTML element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a>
in <var title="">tag list</var>, unset the CSS property <var title="">property
name</var> of <var title="">node</var>. Otherwise, set the CSS property
<var title="">property name</var> of <var title="">node</var> to <var title="">property value</var>.
- <li><p><a href=#unstyle-an-element title="unstyle an element">Unstyle</a> each <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></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>.
+ <li><p>Let <var title="">element children</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> children
+ of <var title="">node</var>.
+
+ <li><p><a href=#unstyle-an-element title="unstyle an element">Unstyle</a> each <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>
+ in <var title="">element children</var>, in order.
+
+ <p class=note>Unstyling an element can change the number of children its
+ parent has, so the list of children to unstyle needs to be computed
+ beforehand.
</ol>
<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-with-name>HTML element with
- name</a> equal to the first string in <var title="">tag list</var>, 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>.
+ <!-- This next step is not strictly necessary from a user point of view,
+ since there's no visible difference. We could just always insert a new
+ element. But that can drastically complicate the DOM if there are lots
+ of text nodes, which happens easily when the algorithms here are invoked
+ a lot: you get splitText() called when decomposing ranges, and unstyling
+ elements can also dump their text node children into the DOM next to
+ other text nodes. -->
+ <li><p>If the previous sibling of <var title="">node</var> is an <a href=#html-element>HTML
+ element</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> in <var title="">tag list</var> with no
+ attributes, let <var title="">new parent</var> equal the previous sibling 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>.
+ <li><p>Otherwise, 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>, 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>. Append <var title="">new parent</var> to <var title="">node</var>'s parent as the previous sibling of <var title="">node</var>.
<li><p>Append <var title="">node</var> to <var title="">new parent</var> as
its last child.
@@ -310,19 +396,39 @@
<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>:
<ol>
- <li><p><a href=#unstyle-an-element title="unstyle an element">Unstyle</a> <var title="">node</var>.
+ <li><p>Let <var title="">children</var> be the result of <a href=#unstyle-an-element title="unstyle an element">unstyling</a> <var title="">node</var>.
+
+ <li><p>If <var title="">node</var> no longer has a parent:
+
+ <ol>
+ <li><p>Insert all 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>s in <var title="">children</var> into <var title="">node list</var> immediately after <var title="">node</var>, in
+ order.
+
+ <li><p>Continue with the next <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 <var title="">node list</var>,
+ if any.
+
+ <p class=note>The next <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> will be the first former child of <var title="">node</var>, if <var title="">node</var> had children.
+ </ol>
<li><p>If the computed value of <var title="">property name</var> for <var title="">node</var> is not <var title="">property value</var>, set the CSS
property <var title="">property name</var> of <var title="">node</var> to <var title="">property value</var>.
- <li><p><a href=#unstyle-an-element title="unstyle an element">Unstyle</a> each <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></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>.
+ <li><p>Let <var title="">element children</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> children
+ of <var title="">node</var>.
+
+ <li><p><a href=#unstyle-an-element title="unstyle an element">Unstyle</a> each <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>
+ in <var title="">element children</var>, in order.
+
+ <p class=note>Unstyling an element can change the number of children its
+ parent has, so the list of children to unstyle needs to be computed
+ beforehand.
</ol>
<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-with-name>HTML element with
- 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 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>Set the CSS property <var title="">property name</var> of <var title="">new parent</var> to <var title="">property value</var>.
@@ -363,13 +469,17 @@
<dl>
<dt><code title=""><dfn id=command-bold title=command-bold>bold</dfn></code>
-<dd>If 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> has font-weight with computed value not
-equal to "bold", 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
+<dd><p>If 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> has font-weight
+with computed value not equal to "bold" (or less than 700), 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> "font-weight", <var title="">property value</var> "bold", and <var title="">tag list</var> ["b", "strong"]. Otherwise, it must <a href=#unstyle-a-range title="unstyle
a range">unstyle it</a> with <var title="">property name</var> "font-weight",
<var title="">property value</var> "normal", and <var title="">tag list</var> ["b",
"strong"].
+
+<p class=XXX>b has font-weight: bolder, not font-weight: bold. This produces
+unexpected behavior if there are font-weight: lighters or something thrown
+around. Maybe that's not worth worrying about.
</dl>
--- a/preprocess Sun Feb 20 15:11:49 2011 -0700
+++ b/preprocess Mon Feb 21 14:25:51 2011 -0700
@@ -4,6 +4,8 @@
# <span data-anolis-spec=domcore title=concept-element-namespace>namespace</span>.
replace = {
+ "ancestor": "<span data-anolis-spec=domcore title=concept-ancestor-node>ancestor</span>",
+ "ancestors": "<span data-anolis-spec=domcore title=concept-ancestor-node>ancestors</span>",
"bpnode": "<span data-anolis-spec=domrange title=concept-boundary-point-node>node</span>",
"bpnodes": "<span data-anolis-spec=domrange title=concept-boundary-point-node>nodes</span>",
"bpoffset": "<span data-anolis-spec=domrange title=concept-boundary-point-offset>offset</span>",
@@ -12,10 +14,12 @@
"descendant": "<span data-anolis-spec=domcore title=concept-descendant-node>descendant</span>",
"descendants": "<span data-anolis-spec=domcore title=concept-descendant-node>descendants</span>",
"element": "<code data-anolis-spec=domcore>Element</code>",
+ "htmlnamespace": "<span data-anolis-spec=domcore>HTML namespace</span>",
"index": "<span data-anolis-spec=domrange title=concept-indexof>index</span>",
+ "localname": "<span data-anolis-spec=domcore title=concept-element-local-name>local name</span>",
"namespace": "<span data-anolis-spec=domcore title=concept-element-namespace>namespace</span>",
"node": "<code data-anolis-spec=domcore>Node</code>",
- "nodelength": "<code data-anolis-spec=domrange title=concept-node-length>length</code>",
+ "nodelength": "<span data-anolis-spec=domrange title=concept-node-length>length</span>",
"processinginstruction": "<code data-anolis-spec=domcore>ProcessingInstruction</code>",
"range": "<code data-anolis-spec=domrange>Range</code>",
"rangeend": "<span data-anolis-spec=domrange title=concept-range-end>end</span>",
--- a/source.html Sun Feb 20 15:11:49 2011 -0700
+++ b/source.html Mon Feb 21 14:25:51 2011 -0700
@@ -66,22 +66,29 @@
<h2>Definitions</h2>
-<p class=XXX>This definition is just an ugly workaround for the annoyance of
-xrefs. Fix it sometime.
+<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>.
-<p>A <code data-anolis-spec=domcore>Node</code> is an <dfn>HTML element
-with name</dfn> <var title>name</var> if it is an <code
-data-anolis-spec=domcore>Element</code>, its <span data-anolis-spec=domcore
-title=concept-element-namespace>namespace</span> is the <span
-data-anolis-spec=domcore>HTML namespace</span>, and its <span
-data-anolis-spec=domcore title=concept-element-local-name>local name</span> is
-<var title>name</var>.
+<p>The <dfn>first node</dfn> of a [[range]] is the [[node]] returned by the
+following algorithm:
-<p>The <dfn>first node</dfn> of a [[range]] is its [[rangestart]] [[bpnode]],
-if that is a [[text]], [[comment]], or [[processinginstruction]] node; or else
-the child of its [[rangestart]] [[bpnode]] with [[index]] equal to its
-[[rangestart]] [[bpoffset]], if that exists; or else its [[rangestart]]
-[[bpnode]].
+<ol>
+ <li><p>Let <var title>range</var> be the [[range]] under discussion.
+
+ <li><p>If <var title>range</var>'s [[rangestart]] [[bpoffset]] is equal to
+ the [[nodelength]] of its [[rangestart]] [[bpnode]], return the first
+ [[node]] that is after the [[rangestart]] [[bpnode]] and all its
+ [[descendants]] (if any) in [[treeorder]]. If there is no such [[node]],
+ return the last [[node]] in the document.
+
+ <li><p>If <var title>range</var>'s [[rangestart]] [[bpnode]] is a [[text]],
+ [[comment]], or [[processinginstruction]] node, return that.
+
+ <li><p>If <var title>range</var>'s [[rangestart]] [[bpnode]] has children,
+ return the child with [[index]] equal to the [[rangestart]] [[bpoffset]].
+
+ <li><p>Return <var title>range</var>'s [[rangestart]] [[bpnode]].
+</ol>
<p>The <dfn>beginning element</dfn> of a [[range]] is its <span>first
node</span> if that is an [[element]]; or the parent of its <span>first
@@ -113,6 +120,27 @@
<p class=XXX>Figure out something sensible here.
+ <li><p>If <var title>start node</var> and <var title>end node</var> are both
+ [[text]] nodes, and <var title>start node</var> is the same as <var title>end
+ node</var>, and neither <var title>start offset</var> nor <var title>end
+ offset</var> is equal to 0 or the [[nodelength]] of <var title>start
+ node</var>:
+
+ <ol>
+ <li><p>Run <code data-anolis-spec=domcore
+ title=dom-Text-splitText>splitText(<var title>start offset</var>)</code> on
+ <var title>start node</var> and set <var title>start node</var> to the
+ result.
+
+ <li><p>Run <code data-anolis-spec=domcore
+ title=dom-Text-splitText>splitText(<var title>end offset</var> − <var
+ title>start offset</var>)</code> on <var title>start node</var> and set
+ <var title>start node</var> to the previous sibling of the result.
+
+ <li><p>Return the list consisting of the single [[node]] <var title>start
+ node</var>, and abort these steps.
+ </ol>
+
<li><p>If <var title>start node</var> is a [[text]] node and <var title>start
offset</var> is neither 0 nor the [[nodelength]] of <var title>start
node</var>, run <code data-anolis-spec=domcore
@@ -128,9 +156,6 @@
sibling of the returned node. Set <var title>end offset</var> to the
[[nodelength]] of the new <var title>end node</var>.
- <p class=XXX>What if the start and end nodes are the same [[text]] node?
- Handle explicitly.
-
<li><p>If <var title>start node</var> is an [[element]] with at least one
child, let <var title>node</var> be the child of <var title>start node</var>
with [[index]] <var title>start offset</var>.
@@ -151,17 +176,33 @@
<li><p>Otherwise, let <var title>end</var> be <var title>end node</var>.
+ <!-- We try to include a node's parent instead of that node if possible,
+ because this generally reduces the number of nodes we're handling. So if the
+ string "oo bar" was selected in <b>Foo <i>bar</i></b>, we'd add the <i> to
+ 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 [[descendant]] of <var title>node</var>'s parent,
+ set <var title>node</var> to its parent.
+
+ <li><p>While <var title>end</var> is the last child of its parent and <var
+ title>node</var> is not a [[descendant]] of <var title>end</var>'s parent,
+ set <var title>end</var> to its parent.
+
<li><p>Let <var title>node list</var> be an empty list of [[node]]s.
<li><p>While <var title>node</var> is not after <var title>end</var> in
[[treeorder]]:
<ol>
- <li>Append <var title>node</var> to <var title>node list</var>.
+ <li><p>Append <var title>node</var> to <var title>node list</var>.
- <li>Set <var title>node</var> to the first [[node]] in
- [[treeorder]] that is after <var title>node</var> and (if applicable) all
- its [[descendants]]. If no such [[node]] exists, break out of these substeps.
+ <li><p>Set <var title>node</var> to the first [[node]] in [[treeorder]]
+ that is after <var title>node</var> and (if applicable) all its
+ [[descendants]]. If no such [[node]] exists, break out of these substeps.
+
+ <li><p>While <var title>node</var> is an [[ancestor]] of <var
+ title>end</var>, set <var title>node</var> to its first child.
</ol>
<li><p>Return <var title>node list</var>.
@@ -170,7 +211,9 @@
<h2>Unstyling an element</h2>
<p>When a user agent is to <dfn>unstyle an element</dfn>, it must run the
-following steps.
+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.
<ol>
<li><p>Let <var title>element</var> be the <code
@@ -179,51 +222,82 @@
<li><p>Let <var title>property name</var> and <var title>tag list</var> be as
in the invoking algorithm.
+ <li><p>Let <var title>element children</var> be the [[element]] children of
+ <var title>element</var>.
+
+ <li><p><span title="unstyle an element">Unstyle</span> each [[element]] in
+ <var title>element children</var>, in order.
+
+ <p class=note>Unstyling an element can change the number of children its
+ parent has, so the list of children to unstyle needs to be computed
+ beforehand.
+
+ <li><p>Let <var title>children</var> be an empty list of [[node]]s.
+
<li><p>If either
<ul>
- <li><p><var title>element</var> is an <span>HTML element with
- name</span> either "span" or in <var title>tag list</var>, and it has
+ <li><p><var title>element</var> is an <span>HTML element</span> with
+ [[localname]] either "span" or in <var title>tag list</var>, and it has
only a single attribute, and that attribute is named "style", and
that style attribute sets only the CSS property <var title>property
name</var>; or
- <li><p><var title>element</var> is an <span>HTML element with
- name</span> in <var title>tag list</var> and it has no attributes,
+ <li><p><var title>element</var> is an <span>HTML element</span> with
+ [[localname]] in <var title>tag list</var> and it has no attributes,
</ul>
<p>then:
<ol>
- <li><p>While <var title>element</var> has children, insert the first child
- of <var title>element</var> as the previous sibling of <var
- title>element</var>.
+ <li><p>While <var title>element</var> has children:
+
+ <ol>
+ <li><p>Let <var title>child</var> be the first child of <var
+ title>element</var>.
+
+ <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>.
+ </ol>
<li><p>Remove <var title>element</var>.
- <li><p>Abort this algorithm.
+ <li><p>Return <var title>children</var> and abort this algorithm.
</ol>
<li><p>Unset the CSS property <var title>property name</var> of <var
title>element</var>.
- <li><p>If <var title>element</var> is an <span>HTML element with
- name</span> in <var title>tag list</var>:
+ <li><p>If <var title>element</var> is an <span>HTML element</span> with
+ [[localname]] in <var title>tag list</var>:
<ol>
- <li><p>Let <var title>new element</var> be a new <span>HTML element with
- name</span> "span", with the same attributes and <code
+ <li><p>Let <var title>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 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>.
- <li><p>While <var title>element</var> has children, append the first child
- of <var title>element</var> as the last child of <var title>new element</var>.
+ <li><p>While <var title>element</var> has children:
+
+ <ol>
+ <li><p>Let <var title>child</var> be the first child of <var
+ title>element</var>.
+
+ <li><p>Append <var title>child</var> to <var title>children</var>.
+
+ <li><p>Append <var title>child</var> as the last child of <var title>new
+ element</var>.
+ </ol>
<li><p>Remove <var title>element</var>.
</ol>
+
+ <li><p>Return <var title>children</var>.
</ol>
@@ -268,30 +342,48 @@
data-anolis-spec=domcore>Element</code>:
<ol>
- <li><p>If <var title>node</var> is an <span>HTML element with name</span>
+ <li><p>If <var title>node</var> is an <span>HTML element</span> with [[localname]]
in <var title>tag list</var>, unset the CSS property <var title>property
name</var> of <var title>node</var>. Otherwise, set the CSS property
<var title>property name</var> of <var title>node</var> to <var
title>property value</var>.
- <li><p><span title="unstyle an element">Unstyle</span> each <code
- data-anolis-spec=domcore>Element</code> <span data-anolis-spec=domcore
- title=concept-descendant-node>descendant</span> of <var title>node</var>.
+ <li><p>Let <var title>element children</var> be the [[element]] children
+ of <var title>node</var>.
+
+ <li><p><span title="unstyle an element">Unstyle</span> each [[element]]
+ in <var title>element children</var>, in order.
+
+ <p class=note>Unstyling an element can change the number of children its
+ parent has, so the list of children to unstyle needs to be computed
+ beforehand.
</ol>
<li><p>Otherwise, if <var title>node</var> is a <code
data-anolis-spec=domcore>Text</code> node:
<ol>
- <li><p>Let <var title>new parent</var> be a new <span>HTML element with
- name</span> equal to the first string in <var title>tag list</var>, with
- no attributes, and <code data-anolis-spec=domcore
+ <!-- This next step is not strictly necessary from a user point of view,
+ since there's no visible difference. We could just always insert a new
+ element. But that can drastically complicate the DOM if there are lots
+ of text nodes, which happens easily when the algorithms here are invoked
+ a lot: you get splitText() called when decomposing ranges, and unstyling
+ elements can also dump their text node children into the DOM next to
+ other text nodes. -->
+ <li><p>If the previous sibling of <var title>node</var> is an <span>HTML
+ element</span> with [[localname]] in <var title>tag list</var> with no
+ attributes, let <var title>new parent</var> equal the previous sibling of
+ <var title>node</var>.
+
+ <li><p>Otherwise, let <var title>new parent</var> be a new <span>HTML
+ element</span> with [[localname]] equal to the first string in <var
+ title>tag list</var>, with no attributes, and <code
+ data-anolis-spec=domcore
title=dom-Node-ownerDocument>ownerDocument</code> the same as <var
+ title>node</var>. Append <var title>new parent</var> to <var
+ title>node</var>'s parent as the previous sibling 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>.
-
<li><p>Append <var title>node</var> to <var title>new parent</var> as
its last child.
</ol>
@@ -328,17 +420,37 @@
data-anolis-spec=domcore>Element</code>:
<ol>
- <li><p><span title="unstyle an element">Unstyle</span> <var
- title>node</var>.
+ <li><p>Let <var title>children</var> be the result of <span
+ title="unstyle an element">unstyling</span> <var title>node</var>.
+
+ <li><p>If <var title>node</var> no longer has a parent:
+
+ <ol>
+ <li><p>Insert all the [[node]]s in <var title>children</var> into <var
+ title>node list</var> immediately after <var title>node</var>, in
+ order.
+
+ <li><p>Continue with the next [[node]] in <var title>node list</var>,
+ if any.
+
+ <p class=note>The next [[node]] will be the first former child of <var
+ title>node</var>, if <var title>node</var> had children.
+ </ol>
<li><p>If the computed value of <var title>property name</var> for <var
title>node</var> is not <var title>property value</var>, set the CSS
property <var title>property name</var> of <var title>node</var> to <var
title>property value</var>.
- <li><p><span title="unstyle an element">Unstyle</span> each <code
- data-anolis-spec=domcore>Element</code> <span data-anolis-spec=domcore
- title=concept-descendant-node>descendant</span> of <var title>node</var>.
+ <li><p>Let <var title>element children</var> be the [[element]] children
+ of <var title>node</var>.
+
+ <li><p><span title="unstyle an element">Unstyle</span> each [[element]]
+ in <var title>element children</var>, in order.
+
+ <p class=note>Unstyling an element can change the number of children its
+ parent has, so the list of children to unstyle needs to be computed
+ beforehand.
</ol>
<li><p>Otherwise, if <var title>node</var> is a <code
@@ -347,8 +459,8 @@
title>property value</var>:
<ol>
- <li><p>Let <var title>new parent</var> be a new <span>HTML element with
- name</span> "span", with no attributes, and with <code
+ <li><p>Let <var title>new parent</var> be a new <span>HTML element</span> with
+ [[localname]] "span", with no attributes, and with <code
data-anolis-spec=domcore
title=dom-Node-ownerDocument>ownerDocument</code> equal to <var
title>node</var>'s.
@@ -396,15 +508,18 @@
<dl>
<dt><code title><dfn title=command-bold>bold</dfn></code>
-<dd>If the <span>beginning element</span> of the <code
-data-anolis-spec=domrange>Range</code> has font-weight with computed value not
-equal to "bold", the user agent must <span title="style a range">style the
-<code data-anolis-spec=domrange>Range</code></span> with <var title>property
+<dd><p>If the <span>beginning element</span> of the [[range]] has font-weight
+with computed value not equal to "bold" (or less than 700), the user agent must
+<span title="style a range">style the [[range]]</span> with <var title>property
name</var> "font-weight", <var title>property value</var> "bold", and <var
title>tag list</var> ["b", "strong"]. Otherwise, it must <span title="unstyle
a range">unstyle it</span> with <var title>property name</var> "font-weight",
<var title>property value</var> "normal", and <var title>tag list</var> ["b",
"strong"].
+
+<p class=XXX>b has font-weight: bolder, not font-weight: bold. This produces
+unexpected behavior if there are font-weight: lighters or something thrown
+around. Maybe that's not worth worrying about.
</dl>
--- a/test/bold.html Sun Feb 20 15:11:49 2011 -0700
+++ b/test/bold.html Mon Feb 21 14:25:51 2011 -0700
@@ -16,7 +16,7 @@
<span style=font-style:italic>Some more text</span><br>
<span style=font-style:italic;font-weight:bold>Some more text</span><br>
<em style=font-weight:bold>Some more text</em><br>
- <b>Some <span style=font-weight:light>more <b>te<span style=font-weight:bold>xt<strong>!</strong></span></b></span></b><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>
@@ -30,7 +30,7 @@
<p><span style=font-style:italic>Some more text</span>
<p><span style=font-style:italic;font-weight:bold>Some more text</span>
<p><em style=font-weight:bold>Some more text</em>
- <p><b>Some <span style=font-weight:light>more <b>te<span style=font-weight:bold>xt<strong>!</strong></span></b></span></b>
+ <p><b>Some <span style=font-weight:200>more <b>te<span style=font-weight:bold>xt<strong>!</strong></span></b></span></b>
</div>
<script>
"use strict";
@@ -45,6 +45,16 @@
return ret;
}
+function nodeLength(node) {
+ if (node.nodeType == Node.TEXT_NODE
+ || node.nodeType == Node.COMMENT_NODE
+ || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
+ return node.data.length;
+ }
+
+ return node.childNodes.length;
+}
+
function nextNode(node) {
if (node.hasChildNodes()) {
return node.firstChild;
@@ -60,15 +70,16 @@
}
return node;
}
- if (node.parentElement) {
- return node.parentElement;
+ if (node.parentNode
+ && node.parentNode.nodeType == Node.ELEMENT_NODE) {
+ return node.parentNode;
}
return null;
}
function nextNodeDescendants(node) {
while (node && !node.nextSibling) {
- node = node.parentElement;
+ node = node.parentNode;
}
if (!node) {
return null;
@@ -83,16 +94,36 @@
function firstNode(range) {
+ // "If range's start offset is equal to the length of its start node,
+ // return the first Node that is after the start node and all its
+ // descendants (if any) in tree order. If there is no such Node, return the
+ // last Node in the document."
+ if (range.startOffset == nodeLength(range.startContainer)) {
+ var ret = nextNodeDescendants(range.startContainer);
+ if (!ret) {
+ ret = range.startContainer;
+ while (ret.hasChildNodes()) {
+ ret = ret.childNodes[ret.childNodes.length - 1];
+ }
+ }
+ return ret;
+ }
+
+ // "If range's start node is a Text, Comment, or ProcessingInstruction
+ // node, return that."
if (range.startContainer.nodeType == Node.TEXT_NODE
|| range.startContainer.nodeType == Node.COMMENT_NODE
|| range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
return range.startContainer;
}
- if (range.startContainer.childNodes.length > range.startOffset) {
+ // "If range's start node has children, return the child with index equal
+ // to the start offset."
+ if (range.startContainer.hasChildNodes()) {
return range.startContainer.childNodes[range.startOffset];
}
+ // "Return range's start node."
return range.startContainer;
}
@@ -122,6 +153,29 @@
// parent, abort these steps."
// Skip the sanity check about node types/detached non-elements
+ // "If start node and end node are both Text nodes, and start node is the
+ // same as end node, and neither start offset nor end offset is equal to 0
+ // or the length of start node:"
+ if (startNode.nodeType == Node.TEXT_NODE
+ && endNode.nodeType == Node.TEXT_NODE
+ && startNode.isSameNode(endNode)
+ && startOffset != 0
+ && startOffset != startNode.data.length
+ && endOffset != 0
+ && endOffset != startNode.data.length) {
+ // "Run splitText(start offset) on start node and set start node to the
+ // result."
+ startNode = startNode.splitText(startOffset);
+
+ // "Run splitText(end offset − start offset) on start node and set
+ // start node to the previous sibling of the result."
+ startNode = startNode.splitText(endOffset - startOffset).previousSibling;
+
+ // "Return the list consisting of the single Node start node, and abort
+ // these steps."
+ return [startNode];
+ }
+
// "If start node is a Text node and start offset is neither 0 nor the
// length of start node, run splitText(start offset) on start node and set
// start node to the returned node. Set start offset to 0."
@@ -173,26 +227,62 @@
end = endNode;
}
+ // "While node is the first child of its parent and end is not a descendant
+ // of node's parent, set node to its parent."
+ while (node == node.parentNode.firstChild
+ && !(end.compareDocumentPosition(node.parentNode) & Node.DOCUMENT_POSITION_CONTAINS)) {
+ node = node.parentNode;
+ }
+
+ // "While end is the last child of its parent and node is not a descendant
+ // of end's parent, set end to its parent."
+ while (end == end.parentNode.lastChild
+ && !(node.compareDocumentPosition(end.parentNode) & Node.DOCUMENT_POSITION_CONTAINS)) {
+ end = end.parentNode;
+ }
+
// "Let node list be an empty list of Nodes."
var nodeList = [];
// "While node is not after end in tree order:"
- while (node && !(end.compareDocumentPosition(node) & 4)) {
+ while (!(end.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING)) {
// "Append node to node list."
nodeList.push(node);
+
// "Set node to the first Node in tree order that is after node and (if
// applicable) all its descendants. If no such Node exists, break out
// of these substeps."
- //
- // If no such node exists, node will be set to null by this line and
- // we'll break out due to the "node" part of the while condition.
node = nextNodeDescendants(node);
+ if (!node) {
+ break;
+ }
+
+ // "While node is an ancestor of end, set node to its first child."
+ while (end.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_CONTAINS) {
+ node = node.firstChild;
+ }
}
return nodeList;
}
function unstyleElement(element, propertyName, tagList) {
+ // "Let element children be the Element children of element."
+ var elementChildren = [];
+ for (var j = 0; j < element.childNodes.length; j++) {
+ if (element.childNodes[j].nodeType == Node.ELEMENT_NODE) {
+ elementChildren.push(element.childNodes[j]);
+ }
+ }
+
+ // "Unstyle each Element in element children, in order."
+ for (var j = 0; j < elementChildren.length; j++) {
+ unstyleElement(elementChildren[j], propertyName, tagList);
+ }
+
+ // "Let children be an empty list of Nodes."
+ var children = [];
+
// "If either
//
// * element is an HTML element with name either "span" or in tag list, and
@@ -216,15 +306,23 @@
&& tagList.indexOf(element.nodeName.toLowerCase()) != -1
&& element.attributes.length == 0)
) {
- // "While element has children, insert the first child of element as
- // the previous sibling of element."
+ // "While element has children:"
while (element.hasChildNodes()) {
- element.parentNode.insertBefore(element.childNodes[0], element);
+ // "Let child be the first child of element."
+ var child = element.firstChild;
+
+ // "Append child to children."
+ children.push(child);
+
+ // "Insert child as the previous sibling of element."
+ element.parentNode.insertBefore(child, element);
}
+
// "Remove element."
element.parentNode.removeChild(element);
- // "Abort this algorithm."
- return;
+
+ // "Return children and abort this algorithm."
+ return children;
}
// "Unset the CSS property property name of element."
@@ -248,24 +346,24 @@
// element."
element.parentNode.insertBefore(newElement, element);
- // "While element has children, append the first child of element as
- // the last child of new element."
+ // "While element has children:"
while (element.hasChildNodes()) {
- newElement.appendChild(element.childNodes[0]);
+ // "Let child be the first child of element."
+ var child = element.firstChild;
+
+ // "Append child to children."
+ children.push(child);
+
+ // "Append child as the last child of new element."
+ newElement.appendChild(child);
}
+
// "Remove element."
element.parentNode.removeChild(element);
}
-}
-function unstyleElementDescendants(element, propertyName, tagList) {
- for (var i = 0; i < element.childNodes.length; i++) {
- if (element.childNodes[i].nodeType != Node.ELEMENT_NODE) {
- continue;
- }
- unstyleElement(element.childNodes[i], propertyName, tagList);
- unstyleElementDescendants(element.childNodes[i], propertyName, tagList);
- }
+ // "Return children."
+ return children;
}
function styleRange(range, propertyName, propertyValue, tagList) {
@@ -290,18 +388,38 @@
node.style[propertyName] = propertyValue;
}
- // "Unstyle each Element descendant of node."
- unstyleElementDescendants(node, propertyName, tagList);
+ // "Let element children be the Element children of node."
+ var elementChildren = [];
+ for (var j = 0; j < node.childNodes.length; j++) {
+ if (node.childNodes[j].nodeType == Node.ELEMENT_NODE) {
+ elementChildren.push(node.childNodes[j]);
+ }
+ }
+
+ // "Unstyle each Element in element children, in order."
+ for (var j = 0; j < elementChildren.length; j++) {
+ unstyleElement(elementChildren[j], propertyName, tagList);
+ }
// "Otherwise, if node is a Text node:"
} else if (node.nodeType == Node.TEXT_NODE) {
- // "Let new parent be a new HTML element with name equal to the first
- // string in tag list, with no attributes, and ownerDocument the same
- // as node."
- var newParent = node.ownerDocument.createElement(tagList[0]);
-
- // "Append new parent to node's parent as the previous sibling of
- // node."
- node.parentNode.insertBefore(newParent, node);
+ var newParent;
+ // "If the previous sibling of node is an HTML element with local
+ // name in tag list with no attributes, let new parent equal the
+ // previous sibling of node."
+ if (node.previousSibling
+ && node.previousSibling.nodeType == Node.ELEMENT_NODE
+ && node.previousSibling.namespaceURI == htmlNamespace
+ && tagList.indexOf(node.previousSibling.tagName.toLowerCase()) != -1
+ && node.previousSibling.attributes.length == 0) {
+ newParent = node.previousSibling;
+ } else {
+ // "Otherwise, let new parent be a new HTML element with local
+ // name equal to the first string in tag list, with no
+ // attributes, and ownerDocument the same as node. Append new
+ // parent to node's parent as the previous sibling of node."
+ newParent = node.ownerDocument.createElement(tagList[0]);
+ node.parentNode.insertBefore(newParent, node);
+ }
// "Append node to new parent as its last child."
newParent.appendChild(node);
@@ -310,37 +428,65 @@
}
}
+// Note: because browsers are inconsistent about what to return for computed
+// styles for bold, I'm making propertyValue an array in the implementation.
function unstyleRange(range, propertyName, propertyValue, tagList) {
// "Let node list be the result of decomposing 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];
+
// "If node is an Element:"
if (node.nodeType == Node.ELEMENT_NODE) {
- // "Unstyle node."
- unstyleElement(node, propertyName, tagList);
+ // "Let children be the result of unstyling node."
+ var children = unstyleElement(node, propertyName, tagList);
+
+ // "If node no longer has a parent:"
+ if (!node.parentNode) {
+ // "Insert all the Nodes in children into node list immediately
+ // after node, in order."
+ //
+ // splice() would be perfect, but it requires varargs. :(
+ nodeList = nodeList.slice(0, i + 1)
+ .concat(children)
+ .concat(nodeList.slice(i + 1));
+
+ // "Continue with the next Node in node list, if any."
+ continue;
+ }
// "If the computed value of property name for node is not property
// value, set the CSS property property name of node to property
// value."
- if (getComputedStyle(node)[propertyName] != propertyValue) {
- node.style[propertyName] = propertyValue;
+ if (propertyValue.indexOf(getComputedStyle(node)[propertyName]) == -1) {
+ node.style[propertyName] = propertyValue[0];
}
- // "Unstyle each Element descendant of node."
- unstyleElementDescendants(node, propertyName, tagList);
+ // "Let element children be the Element children of node."
+ var elementChildren = [];
+ for (var j = 0; j < node.childNodes.length; j++) {
+ if (node.childNodes[j].nodeType == Node.ELEMENT_NODE) {
+ elementChildren.push(node.childNodes[j]);
+ }
+ }
+
+ // "Unstyle each Element in element children, in order."
+ for (var j = 0; j < elementChildren.length; j++) {
+ unstyleElement(elementChildren[j], propertyName, tagList);
+ }
// "Otherwise, if node is a Text node and the computed value of
// property name for node's parent is not property value:"
} else if (node.nodeType == Node.TEXT_NODE
- && getComputedStyle(node.parentNode)[propertyName] != propertyValue) {
+ && propertyValue.indexOf(getComputedStyle(node.parentNode)[propertyName]) == -1) {
// "Let new parent be a new HTML element with name "span", with no
// attributes, and with ownerDocument equal to node's."
var newParent = node.ownerDocument.createElement("span");
// "Set the CSS property property name of new parent to property
// value."
- newParent.style[propertyName] = propertyValue;
+ newParent.style[propertyName] = propertyValue[0];
// "Insert new parent as node's previous sibling."
node.parentNode.insertBefore(newParent, node);
@@ -355,10 +501,12 @@
function bold() {
var selection = getSelection();
for (var i = 0; i < selection.rangeCount; i++) {
- if (getComputedStyle(beginningElement(selection.getRangeAt(i))).fontWeight != "bold") {
+ var fontWeight = getComputedStyle(beginningElement(selection.getRangeAt(i))).fontWeight;
+ if (fontWeight != "bold"
+ && (!/^[0-9]+$/.test(fontWeight) || fontWeight < 700)) {
styleRange(selection.getRangeAt(i), "fontWeight", "bold", ["b", "strong"]);
} else {
- styleRange(selection.getRangeAt(i), "fontWeight", "normal", ["b", "strong"]);
+ unstyleRange(selection.getRangeAt(i), "fontWeight", ["normal", "400"], ["b", "strong"]);
}
}
}
--- a/xrefs.json Sun Feb 20 15:11:49 2011 -0700
+++ b/xrefs.json Mon Feb 21 14:25:51 2011 -0700
@@ -4,7 +4,7 @@
"decompose a range": "decompose-a-range",
"execcommand()": "execcommand()",
"first node": "first-node",
- "html element with name": "html-element-with-name",
+ "html element": "html-element",
"style a range": "style-a-range",
"unstyle a range": "unstyle-a-range",
"unstyle an element": "unstyle-an-element"