--- a/.gitignore Thu Feb 17 15:06:13 2011 -0700
+++ b/.gitignore Sun Feb 20 15:11:49 2011 -0700
@@ -1,2 +1,3 @@
anolis/
data/
+intermediate.html
--- a/Makefile Thu Feb 17 15:06:13 2011 -0700
+++ b/Makefile Sun Feb 20 15:11:49 2011 -0700
@@ -2,9 +2,12 @@
all: editcommands.html xrefs.json
-editcommands.html: source.html data Makefile
+intermediate.html: source.html Makefile
+ ./preprocess
+
+editcommands.html: intermediate.html data Makefile
$(ANOLIS) --output-encoding=ascii --omit-optional-tags --enable=xspecxref \
--enable=refs --use-strict $< $@
-xrefs.json: source.html Makefile
+xrefs.json: intermediate.html Makefile
$(ANOLIS) --dump-xrefs $< /tmp/spec
--- a/editcommands.html Thu Feb 17 15:06:13 2011 -0700
+++ b/editcommands.html Sun Feb 20 15:11:49 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-17-february-2011>Work in Progress — Last Update 17 February 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-—-last-update-20-february-2011>Work in Progress — Last Update 20 February 2011</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <ayg+spec@aryeh.name>
@@ -38,8 +38,11 @@
<li><a href=#introduction><span class=secno>1 </span>Introduction</a></li>
<li><a href=#issues><span class=secno>2 </span>Issues</a></li>
<li><a href=#definitions><span class=secno>3 </span>Definitions</a></li>
- <li><a href=#styling-a-range><span class=secno>4 </span>Styling a Range</a></li>
- <li><a href=#commands><span class=secno>5 </span>Commands</a></li>
+ <li><a href=#decomposing-a-range-into-nodes><span class=secno>4 </span>Decomposing a Range into Nodes</a></li>
+ <li><a href=#unstyling-an-element><span class=secno>5 </span>Unstyling an element</a></li>
+ <li><a href=#styling-a-range><span class=secno>6 </span>Styling a Range</a></li>
+ <li><a href=#unstyling-a-range><span class=secno>7 </span>Unstyling a Range</a></li>
+ <li><a href=#commands><span class=secno>8 </span>Commands</a></li>
<li><a class=no-num href=#references>References</a></ol>
<!--end-toc-->
@@ -63,6 +66,9 @@
<li><p>Need to make CSS terminology more precise, about setting/unsetting CSS
properties. The intent is to modify the style attribute, CSSOM-style.
+ <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
@@ -72,138 +78,181 @@
<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-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 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>.
-<h2 id=styling-a-range><span class=secno>4 </span>Styling a Range</h2>
-<p>When a user agent is to <dfn id=style-a-range>style a <code class=external data-anolis-spec=domrange>Range</code></dfn> <var title="">range</var>, it must
-run the following steps. There are three inputs: a CSS property name <var title="">property name</var>, a new value <var title="">property value</var>, and a
-nonempty list of strings <var title="">tag list</var>.
+<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
+node</a>, if <em>that</em> 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 else null.
-<p class=XXX>This is totally made up and I have no idea yet if it matches
-browsers and/or is even vaguely coherent.
+<p class=XXX>(It will be null only in weird cases, like selecting a comment
+whose parent is a document, or the child of a document fragment, or whatever.
+I'm ignoring those cases for now.)
+
+
+<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.
+
+<p class=note>The algorithm returns a 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 in the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> that
+are not contained in any other <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 <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>. It splits <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 if necessary, but isn't picky about <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment><code class=external data-anolis-spec=domcore>Comment</code></a>s 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>s.
<ol>
- <li><p>Let <var title="">start node</var>, <var title="">start offset</var>, <var title="">end node</var>, and <var title="">end offset</var> be 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> and <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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>nodes</a> and
- <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offsets</a> of <var title="">range</var>,
+ <li><p>Let <var title="">start node</var>, <var title="">start offset</var>, <var title="">end node</var>, and <var title="">end offset</var> be 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>
+ and <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</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>nodes</a> and <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offsets</a> of <var title="">range</var>,
respectively.
- <li><p>Let <var title="">document</var> be 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="">start
- node</var>.
-
<li><p>If <var title="">start node</var> or <var title="">end node</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>, <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#processinginstruction><code class=external data-anolis-spec=domcore>ProcessingInstruction</code></a>, or <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment><code class=external data-anolis-spec=domcore>Comment</code></a> node, or 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> and has no parent, abort
- these steps.
+ <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 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#processinginstruction><code class=external data-anolis-spec=domcore>ProcessingInstruction</code></a>, or <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment><code class=external data-anolis-spec=domcore>Comment</code></a> node, or 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> and has no parent, abort these steps.
<p class=XXX>Figure out something sensible here.
- <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 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 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>.
-
-<!-- Original declarative definition
- <li><p>Let <var title>node list</var> be the list of <code
- data-anolis-spec=domcore>Node</code>s <var title>node</var> in <var
- title>document</var> satisfying all of the following conditions:
-
- <ul>
- <li><p>In <span data-anolis-spec=domcore>tree order</span>, <var
- title>node</var> is after the child of <var title>start node</var> with
- <span data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>start offset</var> (or after <var title>start node</var> itself, if
- <var title>start node</var> is not an <code
- data-anolis-spec=domcore>Element</code>).
+ <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
+ 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>In <span data-anolis-spec=domcore>tree order</span>, <var
- title>node</var> is before the child of <var title>end node</var> with
- <span data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>end offset</var> (or before <var title>end node</var> itself, if <var
- title>end node</var> is not an <code
- data-anolis-spec=domcore>Element</code>).
-
- <li><p><var title>node</var> is not a <span data-anolis-spec=domcore
- title=concept-descendant-node>descendant</span> of any other <code
- data-anolis-spec=domcore>Node</code> that satisfies the previous two
- conditions.
- </ul>
+ <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
+ 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>.
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>start offset</var>
- is 0, add <var title>start node</var> to <var title>node list</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.
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>end offset</var> is
- the <span data-anolis-spec=domrange title=concept-node-length>length</span>
- of <var title>end node</var>, add <var title>end node</var> to <var
- title>node list</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 there is some <code data-anolis-spec=domcore>Element</code> that is
- not in <var title>node list</var> but which has one or more children, and its
- children are all in <var title>node list</var>, add that <code
- data-anolis-spec=domcore>Element</code> to <var title>node list</var> and
- remove all its children from <var title>node list</var>. Repeat until there
- is no such <code data-anolis-spec=domcore>Element</code>.
- -->
+ <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
+ 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>.
+
+ <li><p>If <var title="">end 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> and <var title="">end
+ 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>.
+
+ <li><p>Otherwise, let <var title="">end</var> be <var title="">end node</var>.
<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>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 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 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>, 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 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 0, or 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 no children, let <var title="">node</var> be <var title="">start node</var>.
-
- <li><p>Otherwise, 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>If <var title="">end 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="">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 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>, 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> (or, if
- <var title="">end offset</var> is <var title="">end node</var>'s <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="">end</var> be the last child of <var title="">end node</var>).
-
- <li><p>Otherwise, 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
- 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>,
- or if <var title="">end 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 no children, let <var title="">end</var> be <var title="">end node</var>.
-
- <li><p>Otherwise, let <var title="">end</var> be 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> 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>.
-
<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>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
+ <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.
</ol>
- <!-- Condense the node list for extra tidiness. -->
- <li><p>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> in <var title="">node list</var>.
-
- <li><p>Repeat:
+ <li><p>Return <var title="">node list</var>.
+</ol>
+
+
+<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.
+
+<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.
+
+ <li><p>Let <var title="">property name</var> and <var title="">tag list</var> be as
+ in the invoking algorithm.
+
+ <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
+ 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,
+ </ul>
+
+ <p>then:
<ol>
- <li><p>If <var title="">node</var> has a parent, and its parent 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>, and all the children of <var title="">node</var>'s parent are contained in <var title="">node list</var>, add
- <var title="">node</var>'s parent to <var title="">node list</var> immediately
- before <var title="">node</var>, then remove all children of <var title="">node</var>'s parent from <var title="">node list</var>. Set <var title="">node</var> to <var title="">node</var>'s parent and continue these
- substeps from the beginning.
+ <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>If <var title="">node</var> is 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 <var title="">node list</var>, break
- out of these substeps.
+ <li><p>Remove <var title="">element</var>.
- <li><p>Set <var title="">node</var> to 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>.
+ <li><p>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>:
+
+ <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>
+ 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>Remove <var title="">element</var>.
+ </ol>
+</ol>
+
+
+<h2 id=styling-a-range><span class=secno>6 </span>Styling a Range</h2>
+<p>When a user agent is to <dfn id=style-a-range>style a <code class=external data-anolis-spec=domrange>Range</code></dfn> <var title="">range</var>, it must
+run the following steps. There are three inputs: a CSS property name <var title="">property name</var>, a new value <var title="">property value</var>, and a
+nonempty list of strings <var title="">tag list</var>.
+
+<div class=XXX>
+<p>This description tries to keep the algorithm as simple as possible at the
+expense of producing much more complicated markup in some cases than a slightly
+more sophisticated algorithm. It's similar to what Gecko does in spirit,
+although the details differ. The basic cause of most of the ugly markup is
+that we don't bake in any element nesting restrictions, so <code title=""><em>Abc</em> <em>def</em></code> becomes <code title=""><em
+style=font-weight:bold>Abc</em><b> </b><em
+style=font-weight:bold>def</em></code> instead of just <code title=""><b><em>Abc</em> <em>def</em></b></code>. Otherwise
+we'd have to add content model checks. Maybe this is worth it? IE and WebKit
+seem to do it, Gecko and Opera seem not to (they only wrap text nodes AFAICT).
+
+<p>I did add some complication by saying conflicting inline style needs to be
+removed. This is what WebKit does. Gecko and IE9 leave it alone, which leads
+to stuff like <code title=""><b><span
+style=font-weight:100>Foo</span></b></code> that doesn't actually work.
+Opera avoids the problem by producing code like <code title=""><span
+style=font-weight:100><b>Foo</b></span></code>, but that doesn't work
+with the CSS-based strategy.
+</div>
+
+<ol>
+ <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>:
<ol>
@@ -215,68 +264,24 @@
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>For each <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> <var title="">descendant</var> of <var title="">node</var> 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>:
-
- <ol>
- <li><p>If either
-
- <ul>
- <li><p><var title="">descendant</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
- 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="">descendant</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,
- </ul>
-
- <p>then append all of <var title="">descendant</var>'s children to the
- parent of <var title="">descendant</var> in order immediately before <var title="">descendant</var>, and remove <var title="">descendant</var>.
- Continue with the next descendant.
-
- <li><p>Unset the CSS property <var title="">property name</var> of <var title="">descendant</var>.
- <!-- Only WebKit appears to do this, but it makes sense. Otherwise
- things like <span style=font-weight:normal> won't disappear when you
- apply bold. (Same applies to the places below where we unset the CSS
- property here.) -->
-
- <li><p>If <var title="">descendant</var> is an <a href=#html-element-with-name>HTML element with
- name</a> in <var title="">tag list</var>, let <var title="">new
- descendant</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> as <var title="">descendant</var>. Append <var title="">new descendant</var> to <var title="">descendant</var>'s parent as the previous sibling of <var title="">descendant</var>, then append all of <var title="">descendant</var>'s children to <var title="">new descendant</var> in
- order, then remove <var title="">descendant</var>.
- </ol>
+ <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>.
</ol>
- <li><p>Otherwise:
+ <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>If <var title="">node</var> is not the first child of its parent,
- and its previous sibling is an <a href=#html-element-with-name>HTML element with name</a> equal
- to the first string in <var title="">tag list</var>, append <var title="">node</var> to <var title="">node</var>'s previous sibling as the last
- child. 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>.
- <!-- Thus we merge things together a bit. This could probably use more
- thought. -->
-
- <li><p>If <var title="">node</var> is not 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, or if its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data title=dom-CharacterData-data>data</a> is a
- sequence of zero or more <a class=external data-anolis-spec=html href=http://www.whatwg.org/html/#space-character title="space
- character">space characters</a>, 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>.
- <!-- This avoids wrapping whitespace-only text nodes, which agrees with
- Gecko and WebKit. IE9 and Opera wrap the whitespace-only text nodes,
- which seems pointless. -->
-
<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> set to <var title="">document</var>.
-
+ 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>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>
+
+ <li><p>Otherwise, do nothing.
</ol>
</ol>
@@ -285,263 +290,86 @@
Gecko just adds a style attribute. The latter is simpler, particularly because
you then don't have to worry about making sure you only insert your tags in a
valid place (which you have to so that text/html serialization is possible, if
-nothing else). I originally specced the former approach, retained here in case
-I want to switch back:
+nothing else). I originally specced the former approach, available in git
+history. -->
-<p>When a user agent is to <dfn title=wrap-range-in-tag>wrap a <code
-data-anolis-spec=domrange>Range</code> <var title>range</var> in a tag <var
-title>tag</var></dfn>, treating <var title>tag list</var> as equivalent and
-overriding CSS <var title>property</var>, it must run the following steps:
-<p class=XXX>This is totally made up and I have no idea yet if it matches
-browsers and/or is even vaguely coherent.
+<h2 id=unstyling-a-range><span class=secno>7 </span>Unstyling a Range</h2>
+<p>When a user agent is to <dfn id=unstyle-a-range>unstyle a <code class=external data-anolis-spec=domrange>Range</code></dfn> <var title="">range</var>, it must
+run the following steps. There are three inputs: a CSS property name <var title="">property name</var>, a new value <var title="">property value</var>, and a
+possibly empty list of strings <var title="">tag list</var>.
<ol>
- <li><p>Let <var title>start node</var>, <var title>start offset</var>, <var
- title>end node</var>, and <var title>end offset</var> be the <span
- data-anolis-spec=domrange title=concept-range-start>start</span> and <span
- data-anolis-spec=domrange title=concept-range-end>end</span> <span
- data-anolis-spec=domrange title=concept-boundary-point-node>nodes</span> and
- <span data-anolis-spec=domrange
- title=concept-boundary-point-offset>offsets</span> of <var title>range</var>,
- respectively.
-
- <li><p>Let <var title>document</var> be the <code data-anolis-spec=domcore
- title=dom-Node-ownerDocument>ownerDocument</code> of <var title>start
- node</var>.
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>ProcessingInstruction</code>, or <code
- data-anolis-spec=domcore>Comment</code> node, and it has no parent, abort
- these steps.
-
- <p class=XXX>Figure out something sensible here. Doesn't make sense except
- in IE, since other browsers fail if it's not contentEditable. What does IE
- do? What do we expect?
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>start offset</var>
- is neither 0 nor the <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of <var title>start node</var>, 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 returned node. Set <var title>start
- offset</var> to 0.
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>start offset</var>
- is 0, set <var title>start offset</var> to the <span
- data-anolis-spec=domrange title=concept-indexof>index of</span> <var
- title>start node</var> in its parent, then set <var title>start node</var> to
- its parent.
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>Comment</code>, or <code
- data-anolis-spec=domcore>ProcessingInstruction</code> node, set <var
- title>start offset</var> to one plus the <span data-anolis-spec=domrange
- title=concept-indexof>index of</span> <var title>start node</var> in its
- parent, then set <var title>start node</var> to its parent.
-
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>end offset</var> is
- neither 0 nor the <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of <var title>end node</var>, run
- <code data-anolis-spec=domcore title=dom-Text-splitText>splitText(<var
- title>end offset</var>)</code> 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 <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of the new <var title>end node</var>.
-
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>end offset</var> is
- the <span data-anolis-spec=domrange title=concept-node-length>length</span>
- of <var title>end node</var>, set <var title>end offset</var> to one plus the
- <span data-anolis-spec=domrange title=concept-indexof>index of</span> <var
- title>end node</var> in its parent, then set <var title>end node</var> to its
- parent.
-
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>Comment</code>, or <code
- data-anolis-spec=domcore>ProcessingInstruction</code> node, set <var
- title>end offset</var> to the <span data-anolis-spec=domrange
- title=concept-indexof>index of</span> <var title>end node</var> in its
- parent, then set <var title>end node</var> to its parent.
+ <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>.
- <p class=note>The previous several steps have ensured that <var title>start
- node</var> and <var title>end node</var> are not <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>Comment</code>, or <code
- data-anolis-spec=domcore>ProcessingInstruction</code> nodes, so <var
- title>start offset</var> and <var title>end offset</var> now represent node
- offsets instead of character offsets.
-
- <li><p>Let <var title>node</var> equal <var title>start node</var> and let <var
- title>offset</var> equal <var title>start offset</var>.
-
- <li><p>Repeat the following steps until aborted:
- <ol>
- <li><p><i title id=wrap-algorithm-start>Start</i>: If <var title>node</var> is
- after <var title>end node</var> in <span data-anolis-spec=domcore>tree
- order</span>, or if <var title>node</var> equals <var title>end node</var>
- and <var title>offset</var> is greater than or equal to <var title>end
- offset</var>, abort this subalgorithm.
-
- <li><p>Let <var title>element</var> be a new <code
- data-anolis-spec=domcore>Element</code> with no attributes, <span
- data-anolis-spec=domcore title=concept-element-namespace>namespace</span>
- set to the <span data-anolis-spec=domcore>HTML namespace</span>, <span
- data-anolis-spec=domcore title=concept-element-local-name>local name</span>
- set to <var title>tag</var>, and <code data-anolis-spec=domcore
- title=dom-Node-ownerDocument>ownerDocument</code> set to <var
- title>document</var>.
-
- <li><p>While <var title>node</var> has a child with <span
- data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>offset</var>, and that child meets one of the following conditions,
- take the described action (if any) and increment <var title>offset</var>:
+ <li><p>For each <var title="">node</var> in <var title="">node list</var>, in
+ order:
- <dl class=switch>
- <dt>The child is a <code data-anolis-spec=domcore>Text</code> node whose
- <code data-anolis-spec=domcore title=dom-CharacterData-data>data</code>
- consists of zero or more <span data-anolis-spec=html title="space
- character">space characters</span>
- <!- - This avoids wrapping whitespace-only text nodes, which agrees with
- WebKit. IE9 wraps the whitespace-only text nodes, and Gecko tries to do
- something crazy like add CSS attributes instead of elements. - ->
- <dt>The child is a <code data-anolis-spec=domcore>Comment</code>, <code
- data-anolis-spec=domcore>ProcessingInstruction</code>, or <code
- data-anolis-spec=domcore>DocumentType</code>
- <dd>No action.
+ <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>:
- <dt>The child is an <code data-anolis-spec=domcore>Element</code> whose
- <span data-anolis-spec=domcore
- title=concept-element-namespace>namespace</span> is the <span
- data-anolis-spec=domcore>HTML namespace</span> and whose <span
- data-anolis-spec=domcore title=concept-element-local-name>local
- name</span> is <var title>tag</var>
- <dd><span>Unset the CSS property</span> <var title>property</var> on each
- <span data-anolis-spec=domcore
- title=concept-descendant-node>descendant</span> of the child.
- <!- - Only WebKit appears to do this, but it makes sense. Otherwise
- things like <span style=font-weight:normal> won't disappear when you
- apply bold. (Same applies to the places below where we unset the CSS
- property here.) - ->
- </dl>
+ <ol>
+ <li><p><a href=#unstyle-an-element title="unstyle an element">Unstyle</a> <var title="">node</var>.
- <li><p>If <var title>offset</var> is equal to <var title>node</var>'s <span
- data-anolis-spec=domrange title=concept-node-length>length</span>:
-
- <ol>
- <li><p>If <var title>node</var> is the last <code
- data-anolis-spec=domcore>Node</code> in <var title>document</var>, abort
- this subalgorithm (the one that begins with <i title><a
- href=wrap-algorithm-start>start</a></i>).
+ <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>Let <var title>node</var> equal the first <code
- data-anolis-spec=domcore>Node</code> in <var title>document</var> that is
- after all of <var title>node</var>'s <span data-anolis-spec=domcore
- title=concept-descendant-node>descendants</span> in <span
- data-anolis-spec=domcore>tree order</span>.
-
- <li><p>Let <var title>offset</var> equal zero.
-
- <li><p>Continue from <i title><a
- href=#wrap-algorithm-start>start</a></i>.
+ <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>.
</ol>
- <li><p>Let <var title>child</var> be the child of <var title>node</var> with
- <span data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>offset</var>.
-
- <p class=note><var title>child</var> will always be either an <code
- data-anolis-spec=domcore>Element</code> or a <code
- data-anolis-spec=domcore>Text</code> node.
+ <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>:
- <li><p>If <var title>child</var> is an <code
- data-anolis-spec=domcore>Element</code> which is not part of the <span
- data-anolis-spec=html title="content models">content model</span> of <var
- title>element</var>:
-
<ol>
- <li><p>Create a new <code data-anolis-spec=domrange>Range</code> with <span
- data-anolis-spec=domrange title=concept-range-start>start</span> (<var
- title>child</var>, 0), <span data-anolis-spec=domrange
- title=concept-range-end>end</span> (<var title>child</var>, <span
- data-anolis-spec=domrange title=concept-node-length>length</span> of <Var
- title>child</var>), and <span data-anolis-spec=domrange
- title=concept-range-root>root</span> the same as <var title>range</var>'s
- <span data-anolis-spec=domrange title=concept-range-root>root</span>.
-
- <li><p><span title=wrap-range-in-tag>Wrap that <code
- data-anolis-spec=domrange>Range</code> in <var title>tag</var></span>,
- treating <var title>tag list</var> as equivalent and overriding CSS <var
- title>property</var>.
+ <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>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.
+
+ <li><p>Append <var title="">node</var> to <var title="">new parent</var> as its
+ child.
</ol>
- <li><p>Otherwise, if <var title>child</var> is an <code
- data-anolis-spec=domcore>Element</code> whose <span
- data-anolis-spec=domcore title=concept-element-namespace>namespace</span>
- is the <span data-anolis-spec=domcore>HTML namespace</span> and whose <span
- data-anolis-spec=domcore title=concept-element-local-name>local name</span>
- is <var title>tag</var> or is in <var title>tag list</var>, change <var
- title>child</var>'s <span data-anolis-spec=domcore
- title=concept-element-local-name>local name</span> to <var title>tag</var>
- and <span>unset the CSS property</span> <var title>property</var> on each
- of its <span data-anolis-spec=domcore
- title=concept-descendant-node>descendants</span>.
-
- <li><p>Otherwise:
-
- <p class=note><var title>child</var> is a <code
- data-anolis-spec=domcore>Text</code> node or an <code
- data-anolis-spec=domcore>Element</code> that is part of the <span
- data-anolis-spec=html title="content models">content model</span> of <var
- title>element</var>.
-
- <ol>
- <li><p>Append <var title>element</var> to <var title>node</var> as the
- previous sibling of <var title>child</var>.
-
- <li><p>While <var title>node</var> has a child with <span
- data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>offset</var> + 1, and while that child is not an <code
- data-anolis-spec=domcore>Element</code> or is an <code
- data-anolis-spec=domcore>Element</code> but is part of the <span
- data-anolis-spec=html title="content models">content model</span> of <var
- title>element</var>, append that child to <var title>element</var>.
-
- <p class=note>Since the next sibling of <var title>element</var> is being
- reparented on each iteration of the loop, the same <var
- title>offset</var> will point to a new node every time.
-
- <li><p><span>Unset the CSS property</span> <var title>property</var> on
- each of <var title>element</var>'s descendants.
- </ol>
-
- <li><p>Increment <var title>offset</var>.
-
- <p class=XXX>There appears to be no precise definition of what it means to
- append an existing element to another one. Is it just obvious? Should Web
- DOM Core be clearer?
+ <li><p>Otherwise, do nothing.
</ol>
</ol>
--->
-<h2 id=commands><span class=secno>5 </span>Commands</h2>
+
+<h2 id=commands><span class=secno>8 </span>Commands</h2>
+<p>The <dfn id=execcommand() title=execCommand()><code>execCommand(<var title="">commandId</var>,
+<var title="">showUI</var>, <var title="">value</var>)</code></dfn> method on the
+<a href=http://www.whatwg.org/html/#htmldocument><code class=external data-anolis-spec=html>HTMLDocument</code></a> interface allows scripts to
+perform actions on the current selection or at the current caret position.
+Generally, these commands would be used to implement editor UI, for example
+having a "delete" button on a toolbar.
+
+<p>There are three variants to this method, with one, two, and three arguments
+respectively. The <var title="">showUI</var> and <var title="">value</var>
+parameters, even if specified, are ignored except where otherwise stated.
+
+<p>When <a href=#execcommand()><code>execCommand()</code></a> is invoked, the user agent must run the
+following steps:
+
+<ol>
+ <li>Let <var title="">selection</var> be the result of calling <a href=http://html5.org/specs/dom-range.html#dom-document-getselection><code class=external data-anolis-spec=domrange title=dom-Document-getSelection>getSelection()</code></a> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.
+
+ <li>For each <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> associated with
+ <var title="">selection</var>, in order, take the action from the list below
+ given by <var title="">commandId</var>.
+</ol>
+
<dl>
<dt><code title=""><dfn id=command-bold title=command-bold>bold</dfn></code>
-<dd>The user agent must <a href=#style-a-range title="style a range">style each <code class=external data-anolis-spec=domrange>Range</code></a> of the current <a href=http://html5.org/specs/dom-range.html#selection><code class=external data-anolis-spec=domrange>Selection</code></a> with <var title="">property name</var>
-"font-weight", <var title="">property value</var> "bold", and <var title="">tag
-list</var> ["b", "strong"].
-
-<p class=XXX>Be clearer. What's the "current Selection", and what does it mean
-to wrap "each Range"? What if there are overlapping Ranges?
-
-<p class=XXX>Obviously this doesn't yet even attempt to include the case where
-it's already bold and the bold has to be removed.
+<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
+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"].
</dl>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/preprocess Sun Feb 20 15:11:49 2011 -0700
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+
+# This script is probably evil, but I am unspeakably sick of typing stuff like
+# <span data-anolis-spec=domcore title=concept-element-namespace>namespace</span>.
+
+replace = {
+ "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>",
+ "bpoffsets": "<span data-anolis-spec=domrange title=concept-boundary-point-offset>offsets</span>",
+ "comment": "<code data-anolis-spec=domcore>Comment</code>",
+ "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>",
+ "index": "<span data-anolis-spec=domrange title=concept-indexof>index</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>",
+ "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>",
+ "rangestart": "<span data-anolis-spec=domrange title=concept-range-start>start</span>",
+ "text": "<code data-anolis-spec=domcore>Text</code>",
+ "treeorder": "<span data-anolis-spec=domcore>tree order</span>",
+}
+
+s = open("source.html", "r").read()
+for key in replace:
+ s = s.replace("[[" + key + "]]", replace[key])
+
+if "[[" in s:
+ raise Exception("Something mistyped? " + s[s.find("[["):s.rfind("]]") + 2])
+
+f = open("intermediate.html", "w")
+f.write(s)
+f.close()
--- a/source.html Thu Feb 17 15:06:13 2011 -0700
+++ b/source.html Sun Feb 20 15:11:49 2011 -0700
@@ -54,6 +54,9 @@
<li><p>Need to make CSS terminology more precise, about setting/unsetting CSS
properties. The intent is to modify the style attribute, CSSOM-style.
+ <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
@@ -63,6 +66,9 @@
<h2>Definitions</h2>
+<p class=XXX>This definition is just an ugly workaround for the annoyance of
+xrefs. Fix it sometime.
+
<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
@@ -71,6 +77,155 @@
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 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]].
+
+<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
+node</span>, if <em>that</em> is an [[element]]; or else null.
+
+<p class=XXX>(It will be null only in weird cases, like selecting a comment
+whose parent is a document, or the child of a document fragment, or whatever.
+I'm ignoring those cases for now.)
+
+
+<h2>Decomposing a Range into Nodes</h2>
+<p>When a user agent is to <dfn>decompose a [[range]]</dfn> <var
+title>range</var>, it must run the following steps.
+
+<p class=note>The algorithm returns a list of [[node]]s in the [[range]] that
+are not contained in any other [[node]] in the [[range]]. It splits [[text]]
+nodes if necessary, but isn't picky about [[comment]]s or
+[[processinginstruction]]s.
+
+<ol>
+ <li><p>Let <var title>start node</var>, <var title>start offset</var>, <var
+ title>end node</var>, and <var title>end offset</var> be the [[rangestart]]
+ and [[rangeend]] [[bpnodes]] and [[bpoffsets]] of <var title>range</var>,
+ respectively.
+
+ <li><p>If <var title>start node</var> or <var title>end node</var> is not an
+ [[element]], [[text]], [[processinginstruction]], or [[comment]] node, or is
+ not an [[element]] and has no parent, abort these steps.
+
+ <p class=XXX>Figure out something sensible here.
+
+ <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
+ 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
+ returned node. Set <var title>start offset</var> to 0.
+
+ <li><p>If <var title>end node</var> is a [[text]] node and <var title>end
+ offset</var> is neither 0 nor the [[nodelength]] of <var title>end
+ node</var>, run <code data-anolis-spec=domcore
+ title=dom-Text-splitText>splitText(<var title>end offset</var>)</code> 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
+ [[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>.
+
+ <li><p>Otherwise, if <var title>start node</var> is a [[text]] node and <var
+ title>start offset</var> is its [[nodelength]], let <var title>node</var> be
+ the first [[node]] after <var title>start node</var> in [[treeorder]].
+
+ <li><p>Otherwise, let <var title>node</var> be <var title>start node</var>.
+
+ <li><p>If <var title>end node</var> is an [[element]] and <var title>end
+ offset</var> is not 0, let <var title>end</var> be the child of <var
+ title>end node</var> with [[index]] <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 [[node]] before <var title>end node</var> in
+ [[treeorder]].
+
+ <li><p>Otherwise, let <var title>end</var> be <var title>end node</var>.
+
+ <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>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.
+ </ol>
+
+ <li><p>Return <var title>node list</var>.
+</ol>
+
+
+<h2>Unstyling an element</h2>
+<p>When a user agent is to <dfn>unstyle an element</dfn>, it must run the
+following steps.
+
+<ol>
+ <li><p>Let <var title>element</var> be the <code
+ data-anolis-spec=domcore>Element</code> to be unstyled.
+
+ <li><p>Let <var title>property name</var> and <var title>tag list</var> be as
+ in the invoking algorithm.
+
+ <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
+ 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,
+ </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>Remove <var title>element</var>.
+
+ <li><p>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>:
+
+ <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
+ 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>Remove <var title>element</var>.
+ </ol>
+</ol>
+
<h2>Styling a Range</h2>
<p>When a user agent is to <dfn>style a <code
@@ -79,174 +234,31 @@
title>property name</var>, a new value <var title>property value</var>, and a
nonempty list of strings <var title>tag list</var>.
-<p class=XXX>This is totally made up and I have no idea yet if it matches
-browsers and/or is even vaguely coherent.
+<div class=XXX>
+<p>This description tries to keep the algorithm as simple as possible at the
+expense of producing much more complicated markup in some cases than a slightly
+more sophisticated algorithm. It's similar to what Gecko does in spirit,
+although the details differ. The basic cause of most of the ugly markup is
+that we don't bake in any element nesting restrictions, so <code
+title><em>Abc</em> <em>def</em></code> becomes <code title><em
+style=font-weight:bold>Abc</em><b> </b><em
+style=font-weight:bold>def</em></code> instead of just <code
+title><b><em>Abc</em> <em>def</em></b></code>. Otherwise
+we'd have to add content model checks. Maybe this is worth it? IE and WebKit
+seem to do it, Gecko and Opera seem not to (they only wrap text nodes AFAICT).
+
+<p>I did add some complication by saying conflicting inline style needs to be
+removed. This is what WebKit does. Gecko and IE9 leave it alone, which leads
+to stuff like <code title><b><span
+style=font-weight:100>Foo</span></b></code> that doesn't actually work.
+Opera avoids the problem by producing code like <code title><span
+style=font-weight:100><b>Foo</b></span></code>, but that doesn't work
+with the CSS-based strategy.
+</div>
<ol>
- <li><p>Let <var title>start node</var>, <var title>start offset</var>, <var
- title>end node</var>, and <var title>end offset</var> be the <span
- data-anolis-spec=domrange title=concept-range-start>start</span> and <span
- data-anolis-spec=domrange title=concept-range-end>end</span> <span
- data-anolis-spec=domrange title=concept-boundary-point-node>nodes</span> and
- <span data-anolis-spec=domrange
- title=concept-boundary-point-offset>offsets</span> of <var title>range</var>,
- respectively.
-
- <li><p>Let <var title>document</var> be the <code data-anolis-spec=domcore
- title=dom-Node-ownerDocument>ownerDocument</code> of <var title>start
- node</var>.
-
- <li><p>If <var title>start node</var> or <var title>end node</var> is not an
- <code data-anolis-spec=domcore>Element</code>, <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>ProcessingInstruction</code>, or <code
- data-anolis-spec=domcore>Comment</code> node, or is not an <code
- data-anolis-spec=domcore>Element</code> and has no parent, abort
- these steps.
-
- <p class=XXX>Figure out something sensible here.
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>start offset</var>
- is neither 0 nor the <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of <var title>start node</var>, 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 returned node. Set <var title>start
- offset</var> to 0.
-
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>end offset</var> is
- neither 0 nor the <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of <var title>end node</var>, run
- <code data-anolis-spec=domcore title=dom-Text-splitText>splitText(<var
- title>end offset</var>)</code> 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 <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of the new <var title>end node</var>.
-
-<!-- Original declarative definition
- <li><p>Let <var title>node list</var> be the list of <code
- data-anolis-spec=domcore>Node</code>s <var title>node</var> in <var
- title>document</var> satisfying all of the following conditions:
-
- <ul>
- <li><p>In <span data-anolis-spec=domcore>tree order</span>, <var
- title>node</var> is after the child of <var title>start node</var> with
- <span data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>start offset</var> (or after <var title>start node</var> itself, if
- <var title>start node</var> is not an <code
- data-anolis-spec=domcore>Element</code>).
-
- <li><p>In <span data-anolis-spec=domcore>tree order</span>, <var
- title>node</var> is before the child of <var title>end node</var> with
- <span data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>end offset</var> (or before <var title>end node</var> itself, if <var
- title>end node</var> is not an <code
- data-anolis-spec=domcore>Element</code>).
-
- <li><p><var title>node</var> is not a <span data-anolis-spec=domcore
- title=concept-descendant-node>descendant</span> of any other <code
- data-anolis-spec=domcore>Node</code> that satisfies the previous two
- conditions.
- </ul>
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>start offset</var>
- is 0, add <var title>start node</var> to <var title>node list</var>.
-
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>end offset</var> is
- the <span data-anolis-spec=domrange title=concept-node-length>length</span>
- of <var title>end node</var>, add <var title>end node</var> to <var
- title>node list</var>.
-
- <li><p>If there is some <code data-anolis-spec=domcore>Element</code> that is
- not in <var title>node list</var> but which has one or more children, and its
- children are all in <var title>node list</var>, add that <code
- data-anolis-spec=domcore>Element</code> to <var title>node list</var> and
- remove all its children from <var title>node list</var>. Repeat until there
- is no such <code data-anolis-spec=domcore>Element</code>.
- -->
-
- <li><p>Let <var title>node list</var> be an empty list of <code
- data-anolis-spec=domcore>Node</code>s.
-
- <li><p>If <var title>start node</var> is an <code
- data-anolis-spec=domcore>Element</code> with at least one child, let <var
- title>node</var> be the first <code data-anolis-spec=domcore>Node</code>
- after the child of <var title>start node</var> with <span
- data-anolis-spec=domrange title=concept-indexof>index</span> <var title>start
- offset</var>, in <span data-anolis-spec=domcore>tree order</span>.
-
- <li><p>Otherwise, if <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>start offset</var>
- is 0, or if <var title>start node</var> is an <code
- data-anolis-spec=domcore>Element</code> with no children, let <var
- title>node</var> be <var title>start node</var>.
-
- <li><p>Otherwise, let <var title>node</var> be the first <code
- data-anolis-spec=domcore>Node</code> after <var title>start node</var> in
- <span data-anolis-spec=domcore>tree order</span>.
-
- <li><p>If <var title>end node</var> is an <code
- data-anolis-spec=domcore>Element</code> with at least one child, let <var
- title>end</var> be the first <code data-anolis-spec=domcore>Node</code>
- before the child of <var title>end node</var> with <span
- data-anolis-spec=domrange title=concept-indexof>index</span> <var title>end
- offset</var>, in <span data-anolis-spec=domcore>tree order</span> (or, if
- <var title>end offset</var> is <var title>end node</var>'s <span
- data-anolis-spec=domrange title=concept-node-length>length</span>, let <var
- title>end</var> be the last child of <var title>end node</var>).
-
- <li><p>Otherwise, if <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>end offset</var> is
- its <span data-anolis-spec=domrange title=concept-node-length>length</span>,
- or if <var title>end node</var> is an <code
- data-anolis-spec=domcore>Element</code> with no children, let <var
- title>end</var> be <var title>end node</var>.
-
- <li><p>Otherwise, let <var title>end</var> be the last <code
- data-anolis-spec=domcore>Node</code> before <var title>end node</var> in
- <span data-anolis-spec=domcore>tree order</span>.
-
- <li><p>While <var title>node</var> is not after <var title>end</var> in
- <span data-anolis-spec=domcore>tree order</span>:
-
- <ol>
- <li>Append <var title>node</var> to <var title>node list</var>.
-
- <li>Set <var title>node</var> to the first <code
- data-anolis-spec=domcore>Node</code> in <span data-anolis-spec=domcore>tree
- order</span> that is after <var title>node</var> and (if applicable) all
- its <span data-anolis-spec=domcore
- title=concept-descendant-node>descendants</span>. If no such <code
- data-anolis-spec=domcore>Node</code> exists, break out of these substeps.
- </ol>
-
- <!-- Condense the node list for extra tidiness. -->
- <li><p>Let <var title>node</var> be the first <code
- data-anolis-spec=domcore>Node</code> in <var title>node list</var>.
-
- <li><p>Repeat:
-
- <ol>
- <li><p>If <var title>node</var> has a parent, and its parent is an <code
- data-anolis-spec=domcore>Element</code>, and all the children of <var
- title>node</var>'s parent are contained in <var title>node list</var>, add
- <var title>node</var>'s parent to <var title>node list</var> immediately
- before <var title>node</var>, then remove all children of <var
- title>node</var>'s parent from <var title>node list</var>. Set <var
- title>node</var> to <var title>node</var>'s parent and continue these
- substeps from the beginning.
-
- <li><p>If <var title>node</var> is the last <code
- data-anolis-spec=domcore>Node</code> in <var title>node list</var>, break
- out of these substeps.
-
- <li><p>Set <var title>node</var> to the next <code
- data-anolis-spec=domcore>Node</code> in <var title>node list</var>.
- </ol>
+ <li><p>Let <var title>node list</var> be the result of <span title="decompose
+ a range">decomposing</span> <var title>range</var>.
<li><p>For each <var title>node</var> in <var title>node list</var>, in <span
data-anolis-spec=domcore>tree order</span>:
@@ -262,84 +274,29 @@
<var title>property name</var> of <var title>node</var> to <var
title>property value</var>.
- <li><p>For each <span data-anolis-spec=domcore
- title=concept-descendant-node>descendant</span> <var
- title>descendant</var> of <var title>node</var> that is an <code
- data-anolis-spec=domcore>Element</code>:
-
- <ol>
- <li><p>If either
-
- <ul>
- <li><p><var title>descendant</var> is an <span>HTML element with
- name</span> 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>descendant</var> is an <span>HTML element with
- name</span> in <var title>tag list</var> and it has no attributes,
- </ul>
-
- <p>then append all of <var title>descendant</var>'s children to the
- parent of <var title>descendant</var> in order immediately before <var
- title>descendant</var>, and remove <var title>descendant</var>.
- Continue with the next descendant.
-
- <li><p>Unset the CSS property <var title>property name</var> of <var
- title>descendant</var>.
- <!-- Only WebKit appears to do this, but it makes sense. Otherwise
- things like <span style=font-weight:normal> won't disappear when you
- apply bold. (Same applies to the places below where we unset the CSS
- property here.) -->
-
- <li><p>If <var title>descendant</var> is an <span>HTML element with
- name</span> in <var title>tag list</var>, let <var title>new
- descendant</var> be a new <span>HTML element with name</span> "span",
- with the same attributes and <code data-anolis-spec=domcore
- title=dom-Node-ownerDocument>ownerDocument</code> as <var
- title>descendant</var>. Append <var title>new descendant</var> to <var
- title>descendant</var>'s parent as the previous sibling of <var
- title>descendant</var>, then append all of <var
- title>descendant</var>'s children to <var title>new descendant</var> in
- order, then remove <var title>descendant</var>.
- </ol>
+ <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>.
</ol>
- <li><p>Otherwise:
+ <li><p>Otherwise, if <var title>node</var> is a <code
+ data-anolis-spec=domcore>Text</code> node:
<ol>
- <li><p>If <var title>node</var> is not the first child of its parent,
- and its previous sibling is an <span>HTML element with name</span> equal
- to the first string in <var title>tag list</var>, append <var
- title>node</var> to <var title>node</var>'s previous sibling as the last
- child. Continue with the next <code data-anolis-spec=domcore>Node</code>
- in <var title>node list</var>.
- <!-- Thus we merge things together a bit. This could probably use more
- thought. -->
-
- <li><p>If <var title>node</var> is not a <code
- data-anolis-spec=domcore>Text</code> node, or if its <span
- data-anolis-spec=domcore title=dom-CharacterData-data>data</span> is a
- sequence of zero or more <span data-anolis-spec=html title="space
- character">space characters</span>, continue with the next <code
- data-anolis-spec=domcore>Node</code> in <var title>node list</var>.
- <!-- This avoids wrapping whitespace-only text nodes, which agrees with
- Gecko and WebKit. IE9 and Opera wrap the whitespace-only text nodes,
- which seems pointless. -->
-
<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
- title=dom-Node-ownerDocument>ownerDocument</code> set to <var
- title>document</var>.
-
+ title=dom-Node-ownerDocument>ownerDocument</code> the same as <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>
+
+ <li><p>Otherwise, do nothing.
</ol>
</ol>
@@ -348,265 +305,106 @@
Gecko just adds a style attribute. The latter is simpler, particularly because
you then don't have to worry about making sure you only insert your tags in a
valid place (which you have to so that text/html serialization is possible, if
-nothing else). I originally specced the former approach, retained here in case
-I want to switch back:
+nothing else). I originally specced the former approach, available in git
+history. -->
-<p>When a user agent is to <dfn title=wrap-range-in-tag>wrap a <code
-data-anolis-spec=domrange>Range</code> <var title>range</var> in a tag <var
-title>tag</var></dfn>, treating <var title>tag list</var> as equivalent and
-overriding CSS <var title>property</var>, it must run the following steps:
-<p class=XXX>This is totally made up and I have no idea yet if it matches
-browsers and/or is even vaguely coherent.
+<h2>Unstyling a Range</h2>
+<p>When a user agent is to <dfn>unstyle a <code
+data-anolis-spec=domrange>Range</code></dfn> <var title>range</var>, it must
+run the following steps. There are three inputs: a CSS property name <var
+title>property name</var>, a new value <var title>property value</var>, and a
+possibly empty list of strings <var title>tag list</var>.
<ol>
- <li><p>Let <var title>start node</var>, <var title>start offset</var>, <var
- title>end node</var>, and <var title>end offset</var> be the <span
- data-anolis-spec=domrange title=concept-range-start>start</span> and <span
- data-anolis-spec=domrange title=concept-range-end>end</span> <span
- data-anolis-spec=domrange title=concept-boundary-point-node>nodes</span> and
- <span data-anolis-spec=domrange
- title=concept-boundary-point-offset>offsets</span> of <var title>range</var>,
- respectively.
-
- <li><p>Let <var title>document</var> be the <code data-anolis-spec=domcore
- title=dom-Node-ownerDocument>ownerDocument</code> of <var title>start
- node</var>.
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>ProcessingInstruction</code>, or <code
- data-anolis-spec=domcore>Comment</code> node, and it has no parent, abort
- these steps.
-
- <p class=XXX>Figure out something sensible here. Doesn't make sense except
- in IE, since other browsers fail if it's not contentEditable. What does IE
- do? What do we expect?
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>start offset</var>
- is neither 0 nor the <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of <var title>start node</var>, 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 returned node. Set <var title>start
- offset</var> to 0.
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>start offset</var>
- is 0, set <var title>start offset</var> to the <span
- data-anolis-spec=domrange title=concept-indexof>index of</span> <var
- title>start node</var> in its parent, then set <var title>start node</var> to
- its parent.
-
- <li><p>If <var title>start node</var> is a <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>Comment</code>, or <code
- data-anolis-spec=domcore>ProcessingInstruction</code> node, set <var
- title>start offset</var> to one plus the <span data-anolis-spec=domrange
- title=concept-indexof>index of</span> <var title>start node</var> in its
- parent, then set <var title>start node</var> to its parent.
-
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>end offset</var> is
- neither 0 nor the <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of <var title>end node</var>, run
- <code data-anolis-spec=domcore title=dom-Text-splitText>splitText(<var
- title>end offset</var>)</code> 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 <span data-anolis-spec=domrange
- title=concept-node-length>length</span> of the new <var title>end node</var>.
-
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code> node and <var title>end offset</var> is
- the <span data-anolis-spec=domrange title=concept-node-length>length</span>
- of <var title>end node</var>, set <var title>end offset</var> to one plus the
- <span data-anolis-spec=domrange title=concept-indexof>index of</span> <var
- title>end node</var> in its parent, then set <var title>end node</var> to its
- parent.
-
- <li><p>If <var title>end node</var> is a <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>Comment</code>, or <code
- data-anolis-spec=domcore>ProcessingInstruction</code> node, set <var
- title>end offset</var> to the <span data-anolis-spec=domrange
- title=concept-indexof>index of</span> <var title>end node</var> in its
- parent, then set <var title>end node</var> to its parent.
+ <li><p>Let <var title>node list</var> be the result of <span title="decompose
+ a range">decomposing</span> <var title>range</var>.
- <p class=note>The previous several steps have ensured that <var title>start
- node</var> and <var title>end node</var> are not <code
- data-anolis-spec=domcore>Text</code>, <code
- data-anolis-spec=domcore>Comment</code>, or <code
- data-anolis-spec=domcore>ProcessingInstruction</code> nodes, so <var
- title>start offset</var> and <var title>end offset</var> now represent node
- offsets instead of character offsets.
-
- <li><p>Let <var title>node</var> equal <var title>start node</var> and let <var
- title>offset</var> equal <var title>start offset</var>.
-
- <li><p>Repeat the following steps until aborted:
- <ol>
- <li><p><i title id=wrap-algorithm-start>Start</i>: If <var title>node</var> is
- after <var title>end node</var> in <span data-anolis-spec=domcore>tree
- order</span>, or if <var title>node</var> equals <var title>end node</var>
- and <var title>offset</var> is greater than or equal to <var title>end
- offset</var>, abort this subalgorithm.
-
- <li><p>Let <var title>element</var> be a new <code
- data-anolis-spec=domcore>Element</code> with no attributes, <span
- data-anolis-spec=domcore title=concept-element-namespace>namespace</span>
- set to the <span data-anolis-spec=domcore>HTML namespace</span>, <span
- data-anolis-spec=domcore title=concept-element-local-name>local name</span>
- set to <var title>tag</var>, and <code data-anolis-spec=domcore
- title=dom-Node-ownerDocument>ownerDocument</code> set to <var
- title>document</var>.
-
- <li><p>While <var title>node</var> has a child with <span
- data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>offset</var>, and that child meets one of the following conditions,
- take the described action (if any) and increment <var title>offset</var>:
+ <li><p>For each <var title>node</var> in <var title>node list</var>, in
+ order:
- <dl class=switch>
- <dt>The child is a <code data-anolis-spec=domcore>Text</code> node whose
- <code data-anolis-spec=domcore title=dom-CharacterData-data>data</code>
- consists of zero or more <span data-anolis-spec=html title="space
- character">space characters</span>
- <!- - This avoids wrapping whitespace-only text nodes, which agrees with
- WebKit. IE9 wraps the whitespace-only text nodes, and Gecko tries to do
- something crazy like add CSS attributes instead of elements. - ->
- <dt>The child is a <code data-anolis-spec=domcore>Comment</code>, <code
- data-anolis-spec=domcore>ProcessingInstruction</code>, or <code
- data-anolis-spec=domcore>DocumentType</code>
- <dd>No action.
+ <ol>
+ <li><p>If <var title>node</var> is an <code
+ data-anolis-spec=domcore>Element</code>:
- <dt>The child is an <code data-anolis-spec=domcore>Element</code> whose
- <span data-anolis-spec=domcore
- title=concept-element-namespace>namespace</span> is the <span
- data-anolis-spec=domcore>HTML namespace</span> and whose <span
- data-anolis-spec=domcore title=concept-element-local-name>local
- name</span> is <var title>tag</var>
- <dd><span>Unset the CSS property</span> <var title>property</var> on each
- <span data-anolis-spec=domcore
- title=concept-descendant-node>descendant</span> of the child.
- <!- - Only WebKit appears to do this, but it makes sense. Otherwise
- things like <span style=font-weight:normal> won't disappear when you
- apply bold. (Same applies to the places below where we unset the CSS
- property here.) - ->
- </dl>
+ <ol>
+ <li><p><span title="unstyle an element">Unstyle</span> <var
+ title>node</var>.
- <li><p>If <var title>offset</var> is equal to <var title>node</var>'s <span
- data-anolis-spec=domrange title=concept-node-length>length</span>:
-
- <ol>
- <li><p>If <var title>node</var> is the last <code
- data-anolis-spec=domcore>Node</code> in <var title>document</var>, abort
- this subalgorithm (the one that begins with <i title><a
- href=wrap-algorithm-start>start</a></i>).
+ <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>Let <var title>node</var> equal the first <code
- data-anolis-spec=domcore>Node</code> in <var title>document</var> that is
- after all of <var title>node</var>'s <span data-anolis-spec=domcore
- title=concept-descendant-node>descendants</span> in <span
- data-anolis-spec=domcore>tree order</span>.
-
- <li><p>Let <var title>offset</var> equal zero.
-
- <li><p>Continue from <i title><a
- href=#wrap-algorithm-start>start</a></i>.
+ <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>.
</ol>
- <li><p>Let <var title>child</var> be the child of <var title>node</var> with
- <span data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>offset</var>.
-
- <p class=note><var title>child</var> will always be either an <code
- data-anolis-spec=domcore>Element</code> or a <code
- data-anolis-spec=domcore>Text</code> node.
+ <li><p>Otherwise, if <var title>node</var> is a <code
+ data-anolis-spec=domcore>Text</code> 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>:
- <li><p>If <var title>child</var> is an <code
- data-anolis-spec=domcore>Element</code> which is not part of the <span
- data-anolis-spec=html title="content models">content model</span> of <var
- title>element</var>:
-
<ol>
- <li><p>Create a new <code data-anolis-spec=domrange>Range</code> with <span
- data-anolis-spec=domrange title=concept-range-start>start</span> (<var
- title>child</var>, 0), <span data-anolis-spec=domrange
- title=concept-range-end>end</span> (<var title>child</var>, <span
- data-anolis-spec=domrange title=concept-node-length>length</span> of <Var
- title>child</var>), and <span data-anolis-spec=domrange
- title=concept-range-root>root</span> the same as <var title>range</var>'s
- <span data-anolis-spec=domrange title=concept-range-root>root</span>.
-
- <li><p><span title=wrap-range-in-tag>Wrap that <code
- data-anolis-spec=domrange>Range</code> in <var title>tag</var></span>,
- treating <var title>tag list</var> as equivalent and overriding CSS <var
- title>property</var>.
+ <li><p>Let <var title>new parent</var> be a new <span>HTML element with
+ name</span> "span", with no attributes, and with <code
+ data-anolis-spec=domcore
+ title=dom-Node-ownerDocument>ownerDocument</code> 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>.
+
+ <li><p>Insert <var title>new parent</var> as <var title>node</var>'s
+ previous sibling.
+
+ <li><p>Append <var title>node</var> to <var title>new parent</var> as its
+ child.
</ol>
- <li><p>Otherwise, if <var title>child</var> is an <code
- data-anolis-spec=domcore>Element</code> whose <span
- data-anolis-spec=domcore title=concept-element-namespace>namespace</span>
- is the <span data-anolis-spec=domcore>HTML namespace</span> and whose <span
- data-anolis-spec=domcore title=concept-element-local-name>local name</span>
- is <var title>tag</var> or is in <var title>tag list</var>, change <var
- title>child</var>'s <span data-anolis-spec=domcore
- title=concept-element-local-name>local name</span> to <var title>tag</var>
- and <span>unset the CSS property</span> <var title>property</var> on each
- of its <span data-anolis-spec=domcore
- title=concept-descendant-node>descendants</span>.
-
- <li><p>Otherwise:
-
- <p class=note><var title>child</var> is a <code
- data-anolis-spec=domcore>Text</code> node or an <code
- data-anolis-spec=domcore>Element</code> that is part of the <span
- data-anolis-spec=html title="content models">content model</span> of <var
- title>element</var>.
-
- <ol>
- <li><p>Append <var title>element</var> to <var title>node</var> as the
- previous sibling of <var title>child</var>.
-
- <li><p>While <var title>node</var> has a child with <span
- data-anolis-spec=domrange title=concept-indexof>index</span> <var
- title>offset</var> + 1, and while that child is not an <code
- data-anolis-spec=domcore>Element</code> or is an <code
- data-anolis-spec=domcore>Element</code> but is part of the <span
- data-anolis-spec=html title="content models">content model</span> of <var
- title>element</var>, append that child to <var title>element</var>.
-
- <p class=note>Since the next sibling of <var title>element</var> is being
- reparented on each iteration of the loop, the same <var
- title>offset</var> will point to a new node every time.
-
- <li><p><span>Unset the CSS property</span> <var title>property</var> on
- each of <var title>element</var>'s descendants.
- </ol>
-
- <li><p>Increment <var title>offset</var>.
-
- <p class=XXX>There appears to be no precise definition of what it means to
- append an existing element to another one. Is it just obvious? Should Web
- DOM Core be clearer?
+ <li><p>Otherwise, do nothing.
</ol>
</ol>
--->
+
<h2>Commands</h2>
+<p>The <dfn title=execCommand()><code>execCommand(<var title>commandId</var>,
+<var title>showUI</var>, <var title>value</var>)</code></dfn> method on the
+<code data-anolis-spec=html>HTMLDocument</code> interface allows scripts to
+perform actions on the current selection or at the current caret position.
+Generally, these commands would be used to implement editor UI, for example
+having a "delete" button on a toolbar.
+
+<p>There are three variants to this method, with one, two, and three arguments
+respectively. The <var title>showUI</var> and <var title>value</var>
+parameters, even if specified, are ignored except where otherwise stated.
+
+<p>When <code>execCommand()</code> is invoked, the user agent must run the
+following steps:
+
+<ol>
+ <li>Let <var title>selection</var> be the result of calling <code
+ data-anolis-spec=domrange
+ title=dom-Document-getSelection>getSelection()</code> on the <span
+ data-anolis-spec=domrange>context object</span>.
+
+ <li>For each <code data-anolis-spec=domrange>Range</code> associated with
+ <var title>selection</var>, in order, take the action from the list below
+ given by <var title>commandId</var>.
+</ol>
+
<dl>
<dt><code title><dfn title=command-bold>bold</dfn></code>
-<dd>The user agent must <span title="style a range">style each <code
-data-anolis-spec=domrange>Range</code></span> of the current <code
-data-anolis-spec=domrange>Selection</code> with <var title>property name</var>
-"font-weight", <var title>property value</var> "bold", and <var title>tag
-list</var> ["b", "strong"].
-
-<p class=XXX>Be clearer. What's the "current Selection", and what does it mean
-to wrap "each Range"? What if there are overlapping Ranges?
-
-<p class=XXX>Obviously this doesn't yet even attempt to include the case where
-it's already bold and the bold has to be removed.
+<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
+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"].
</dl>
--- a/test/bold.html Thu Feb 17 15:06:13 2011 -0700
+++ b/test/bold.html Sun Feb 20 15:11:49 2011 -0700
@@ -1,6 +1,6 @@
<!doctype html>
<title>execCommand("bold") tests</title>
-<div id=log></div>
+<button onclick=bold()>Bold</button>
<div contenteditable=true id=test>
<br> <br>
Some simple text<br>
@@ -32,8 +32,6 @@
<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>
</div>
-<script src=support/testharness.js></script>
-<script src=support/testharnessreport.js></script>
<script>
"use strict";
@@ -83,16 +81,50 @@
return "font-weight";
}
-function styleRange(range, propertyName, propertyValue, tagList) {
+
+function firstNode(range) {
+ 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) {
+ return range.startContainer.childNodes[range.startOffset];
+ }
+
+ return range.startContainer;
+}
+
+function beginningElement(range) {
+ var first = firstNode(range);
+ if (first.nodeType == Node.ELEMENT_NODE) {
+ return first;
+ }
+
+ if (first.parentNode.nodeType == Node.ELEMENT_NODE) {
+ return first.parentNode;
+ }
+
+ return null;
+}
+
+function decomposeRange(range) {
+ // "Let start node, start offset, end node, and end offset be the start and
+ // end nodes and offsets of range, respectively."
var startNode = range.startContainer;
var startOffset = range.startOffset;
var endNode = range.endContainer;
var endOffset = range.endOffset;
- var doc = startNode.ownerDocument;
-
+ // "If start node or end node is not an Element, Text,
+ // ProcessingInstruction, or Comment node, or is not an Element and has no
+ // parent, abort these steps."
// Skip the sanity check about node types/detached non-elements
+ // "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."
if (startNode.nodeType == Node.TEXT_NODE
&& startOffset != 0
&& startOffset != startNode.data.length) {
@@ -100,6 +132,10 @@
startOffset = 0;
}
+ // "If end node is a Text node and end offset is neither 0 nor the length
+ // of end node, run splitText(end offset) on end node and set end node to
+ // the previous sibling of the returned node. Set end offset to the length
+ // of the new end node."
if (endNode.nodeType == Node.TEXT_NODE
&& endOffset != 0
&& endOffset != endNode.data.length) {
@@ -107,150 +143,223 @@
endOffset = endNode.data.length;
}
- var nodeList = [];
-
var node;
+ // "If start node is an Element with at least one child, let node be the
+ // child of start node with index start offset."
if (startNode.nodeType == Node.ELEMENT_NODE
&& startNode.hasChildNodes()) {
- node = nextNode(startNode.childNodes[startOffset]);
- } else if (
- (startNode.nodeType == Node.TEXT_NODE && startOffset == 0)
- || (startNode.nodeType == Node.ELEMENT_NODE && !startNode.hasChildNodes())
- ) {
+ node = startNode.childNodes[startOffset];
+ // "Otherwise, if start node is a Text node and start offset is its length,
+ // let node be the first Node after start node in tree order."
+ } else if (startNode.nodeType == Node.TEXT_NODE
+ && startOffset == startNode.data.length) {
+ node = nextNode(startNode);
+ // "Otherwise, let node be start node."
+ } else {
node = startNode;
- } else {
- node = nextNode(startNode);
}
var end;
- if (endNode.nodeType == Node.ELEMENT_NODE
- && endNode.hasChildNodes()) {
- if (endOffset == endNode.childNodes.length) {
- end = endNode.lastChild;
- } else {
- end = previousNode(endNode.childNodes[endOffset]);
- }
- } else if (
- (endNode.nodeType == Node.TEXT_NODE && endOffset == endNode.data.length)
- || (endNode.nodeType == Node.ELEMENT_NODE && !endNode.hasChildNodes())
- ) {
+ // "If end node is an Element and end offset is not 0, let end be the child
+ // of end node with index end offset − 1."
+ if (endNode.nodeType == Node.ELEMENT_NODE && endOffset != 0) {
+ end = endNode.childNodes[endOffset - 1];
+ // "Otherwise, if end offset is 0, let end be the first Node before end
+ // node in tree order."
+ } else if (endOffset == 0) {
+ end = previousNode(endNode);
+ // "Otherwise, let end be end node."
+ } else {
end = endNode;
- } else {
- end = previousNode(endNode);
}
+ // "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)) {
+ // "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);
}
- // FIXME what if nodeList.length == 0?
- for (var i = 0; i < nodeList.length; i++) {
- node = nodeList[i];
- if (node.parentElement) {
- var replace = true;
- for (var j = 0; j < node.parentElement.childNodes.length; j++) {
- if (node.parentElement.childNodes[j] != nodeList[i + j]) {
- replace = false;
- break;
- }
- }
- if (replace) {
- nodeList = nodeList.slice(0, i)
- .concat(node.parentElement)
- .concat(nodeList.slice(i + j));
- continue;
- }
+ return nodeList;
+}
+
+function unstyleElement(element, propertyName, tagList) {
+ // "If either
+ //
+ // * element is an HTML element with name either "span" or in tag list, and
+ // it has only a single attribute, and that attribute is named "style",
+ // and that style attribute sets only the CSS property property name; or
+ //
+ // * element is an HTML element with name in tag list and it has no
+ // attributes,
+ //
+ // then:"
+ if (
+ (element.namespaceURI == htmlNamespace
+ && (element.nodeName == "SPAN" || tagList.indexOf(element.nodeName.toLowerCase()) != -1)
+ && element.attributes.length == 1
+ && element.attributes[0].localName == "style"
+ && element.style.length == 1
+ && element.style.item(0) == convertProperty(propertyName)
+ )
+ ||
+ (element.namespaceURI == htmlNamespace
+ && 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.hasChildNodes()) {
+ element.parentNode.insertBefore(element.childNodes[0], element);
}
+ // "Remove element."
+ element.parentNode.removeChild(element);
+ // "Abort this algorithm."
+ return;
}
+ // "Unset the CSS property property name of element."
+ element.style[propertyName] = '';
+ if (element.getAttribute("style") == "") {
+ element.removeAttribute("style");
+ }
+
+ // "If element is an HTML element with name in tag list:"
+ if (element.namespaceURI == htmlNamespace
+ && tagList.indexOf(element.tagName.toLowerCase()) != -1) {
+ // "Let new element be a new HTML element with name "span", with the
+ // same attributes and ownerDocument as element."
+ var newElement = element.ownerDocument.createElement("span");
+ for (var j = 0; j < element.attributes.length; j++) {
+ // FIXME: Namespaces?
+ newElement.setAttribute(element.attributes[j].localName, element.attributes[j].value);
+ }
+
+ // "Append new element to element's parent as the previous sibling of
+ // 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.hasChildNodes()) {
+ newElement.appendChild(element.childNodes[0]);
+ }
+ // "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);
+ }
+}
+
+function styleRange(range, propertyName, propertyValue, tagList) {
+ // "Let node list be the result of decomposing range."
+ var nodeList = decomposeRange(range);
+
+ // "For each node in node list, in tree order:"
for (var i = 0; i < nodeList.length; i++) {
- node = nodeList[i];
+ var node = nodeList[i];
+ // "If node is an Element:"
if (node.nodeType == Node.ELEMENT_NODE) {
+ // "If node is an HTML element with name in tag list, unset the CSS
+ // property property name of node. Otherwise, set the CSS property
+ // property name of node to property value."
if (node.namespaceURI == htmlNamespace
&& tagList.indexOf(node.tagName.toLowerCase()) != -1) {
node.style[propertyName] = '';
+ if (node.getAttribute("style") == "") {
+ node.removeAttribute("style");
+ }
} else {
node.style[propertyName] = propertyValue;
}
- var desc = nextNode(node);
- var stop = nextNodeDescendants(node);
- while (true) {
- if (desc == stop) {
- break;
- }
-
- if (desc.nodeType != Node.ELEMENT_NODE) {
- desc = nextNode(desc);
- continue;
- }
+ // "Unstyle each Element descendant of node."
+ unstyleElementDescendants(node, 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]);
- if (
- (desc.namespaceURI == htmlNamespace
- && (desc.nodeName == "SPAN" || tagList.indexOf(desc.nodeName.toLowerCase()) != -1)
- && desc.attributes.length == 1
- //&& desc.attributes[0].namespaceURI == htmlNamespace
- && desc.attributes[0].localName == "style"
- && desc.style.length == 1
- && desc.style.item(0) == convertProperty(propertyName)
- )
- ||
- (desc.namespaceURI == htmlNamespace
- && tagList.indexOf(desc.nodeName.toLowerCase()) != -1
- && desc.attributes.length == 0)
- ) {
- var oldDesc = desc;
- desc = nextNode(desc);
- while (oldDesc.hasChildNodes()) {
- oldDesc.parentNode.insertBefore(oldDesc.childNodes[0], oldDesc);
- }
- oldDesc.parentNode.removeChild(oldDesc);
- continue;
- }
- desc.style[propertyName] = '';
- if (desc.getAttribute("style") == "") {
- desc.removeAttribute("style");
- }
- if (desc.namespaceURI == htmlNamespace
- && tagList.indexOf(desc.tagName.toLowerCase()) != -1) {
- var newDesc = doc.createElement("span");
- for (var j = 0; j < desc.attributes.length; j++) {
- // Sick of playing the namespace game, assume
- // everything is in HTML.
- newDesc.setAttribute(desc.attributes[j].localName, desc.attributes[j].value);
- }
- desc.parentNode.insertBefore(newDesc, desc);
- while (desc.hasChildNodes()) {
- newDesc.appendChild(desc.childNodes[0]);
- }
- desc.parentNode.removeChild(desc);
- }
- desc = nextNode(desc);
- }
- continue;
+ // "Append new parent to node's parent as the previous sibling of
+ // node."
+ node.parentNode.insertBefore(newParent, node);
+
+ // "Append node to new parent as its last child."
+ newParent.appendChild(node);
}
-
- if (node.previousSibling
- && node.previousSibling.nodeType == Node.ELEMENT_NODE
- && node.previousSibling.namespaceURI == htmlNamespace
- && node.previousSibling.tagName == tagList[0].toUpperCase()) {
- node.previousSibling.appendChild(node);
- continue;
- }
-
- if (node.nodeType != Node.TEXT_NODE
- || /^[ \t\n\f\r]*$/.test(node.data)) {
- continue;
- }
-
- var newParent = doc.createElement(tagList[0]);
- node.parentNode.insertBefore(newParent, node);
- newParent.appendChild(node);
+ // "Otherwise, do nothing."
}
}
-var range = document.createRange();
-range.selectNodeContents(document.getElementsByTagName("div")[1]);
-styleRange(range, "fontWeight", "bold", ["b", "strong"]);
+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++) {
+ // "If node is an Element:"
+ if (node.nodeType == Node.ELEMENT_NODE) {
+ // "Unstyle node."
+ unstyleElement(node, propertyName, tagList);
+
+ // "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;
+ }
+
+ // "Unstyle each Element descendant of node."
+ unstyleElementDescendants(node, 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) {
+ // "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;
+
+ // "Insert new parent as node's previous sibling."
+ node.parentNode.insertBefore(newParent, node);
+
+ // "Append node to new parent as its child."
+ newParent.appendChild(node);
+ }
+ // "Otherwise, do nothing."
+ }
+}
+
+function bold() {
+ var selection = getSelection();
+ for (var i = 0; i < selection.rangeCount; i++) {
+ if (getComputedStyle(beginningElement(selection.getRangeAt(i))).fontWeight != "bold") {
+ styleRange(selection.getRangeAt(i), "fontWeight", "bold", ["b", "strong"]);
+ } else {
+ styleRange(selection.getRangeAt(i), "fontWeight", "normal", ["b", "strong"]);
+ }
+ }
+}
</script>
--- a/test/editcommands.html Thu Feb 17 15:06:13 2011 -0700
+++ b/test/editcommands.html Sun Feb 20 15:11:49 2011 -0700
@@ -1,40 +1,10 @@
<!doctype html>
<title>execCommand() tests</title>
+<button onclick="document.execCommand('bold', false, null)">Bold</button>
<div contenteditable=true>
- <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>
- <span style=font-weight:bolder>Some more text</span><br>
- <span style=font-weight:lighter>Some more text</span><br>
- <span style=font-weight:900>Some more text</span><br>
- <span style=font-weight:100>Some more text</span><br>
- <i>Some more text</i><br>
- <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>
- <p>Some simple text
- <p><span>Some more text</span>
- <p><b>Some more text</b>
- <p><strong>Some more text</strong>
- <p><span style=font-weight:bold>Some more text</span>
- <p><span style=font-weight:bolder>Some more text</span>
- <p><span style=font-weight:lighter>Some more text</span>
- <p><span style=font-weight:900>Some more text</span>
- <p><span style=font-weight:100>Some more text</span>
- <p><i>Some more text</i>
- <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>Abcdef</b>
+ <p><strong>Abcdef</strong>
+ <p><span style=font-weight:bold>Abcdef</span>
+ <p><span style=font-weight:bolder>Abcdef</span>
+ <p><span style=font-weight:900>Abcdef</span>
</div>
-<script>
-var selection = getSelection();
-selection.selectAllChildren(document.querySelector("div"));
-document.execCommand("bold", false, null);
-//document.execCommand("bold", false, null);
-selection.removeAllRanges();
-</script>
--- a/xrefs.json Thu Feb 17 15:06:13 2011 -0700
+++ b/xrefs.json Sun Feb 20 15:11:49 2011 -0700
@@ -1,5 +1,11 @@
{
+ "beginning element": "beginning-element",
"command-bold": "command-bold",
+ "decompose a range": "decompose-a-range",
+ "execcommand()": "execcommand()",
+ "first node": "first-node",
"html element with name": "html-element-with-name",
- "style a range": "style-a-range"
+ "style a range": "style-a-range",
+ "unstyle a range": "unstyle-a-range",
+ "unstyle an element": "unstyle-an-element"
}