--- a/editing.html Thu Jan 12 10:17:39 2012 -0700
+++ b/editing.html Thu Jan 12 11:44:11 2012 -0700
@@ -792,6 +792,9 @@
forwards (including if the user didn't create the <a href=#concept-selection title=concept-selection>selection</a>, created it by
selecting an entire part of the page using a keyboard shortcut, etc.).
+<p class=XXX>Wouldn't it make more sense if addRange()/removeRange() reset
+direction?
+
<p><a href=#concept-selection title=concept-selection>Selections</a> also have an <dfn id=anchor>anchor</dfn> and a <dfn id=focus>focus</dfn>. If
the <a href=#concept-selection title=concept-selection>selection</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> is null, its <a href=#anchor>anchor</a> and
<a href=#focus>focus</a> are both null. If the <a href=#concept-selection title=concept-selection>selection</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> is not null
@@ -807,14 +810,14 @@
readonly attribute unsigned long <a href=#dom-selection-focusoffset title=dom-Selection-focusOffset>focusOffset</a>;
readonly attribute boolean <a href=#dom-selection-iscollapsed title=dom-Selection-isCollapsed>isCollapsed</a>;
- void <a href=#dom-selection-collapse title=dom-Selection-collapse>collapse</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> parentNode, unsigned long offset);
+ void <a href=#dom-selection-collapse title=dom-Selection-collapse>collapse</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> node, unsigned long offset);
void <a href=#dom-selection-collapsetostart title=dom-Selection-collapseToStart>collapseToStart</a>();
void <a href=#dom-selection-collapsetoend title=dom-Selection-collapseToEnd>collapseToEnd</a>();
- void <a href=#dom-selection-extend title=dom-Selection-extend>extend</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> parentNode, unsigned long offset);
+ void <a href=#dom-selection-extend title=dom-Selection-extend>extend</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> node, unsigned long offset);
void <a href=#dom-selection-modify title=dom-Selection-modify>modify</a>(DOMString alter, DOMString direction, DOMString granularity);
- void <a href=#dom-selection-selectallchildren title=dom-Selection-selectAllChildren>selectAllChildren</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> parentNode);
+ void <a href=#dom-selection-selectallchildren title=dom-Selection-selectAllChildren>selectAllChildren</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> node);
void <a href=#dom-selection-deletefromdocument title=dom-Selection-deleteFromDocument>deleteFromDocument</a>();
readonly attribute unsigned long <a href=#dom-selection-rangecount title=dom-Selection-rangeCount>rangeCount</a>;
@@ -912,12 +915,14 @@
<p>Returns true if there's no selection or if the selection is empty.
Otherwise, returns false.
- <dt><var title="">selection</var> . <code title=dom-Selection-collapse><a href=#dom-selection-collapse>collapse</a></code>(<var title="">parentNode</var>, <var title="">offset</var>)
+ <dt><var title="">selection</var> .
+ <code title=dom-Selection-collapse><a href=#dom-selection-collapse>collapse</a></code>(<var title="">node</var>,
+ <var title="">offset</var>)
<dd>
<p>Replaces the selection with a collapsed one at the given position.
<p>Throws an <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#indexsizeerror>IndexSizeError</a></code> exception if <var title="">offset</var> is negative
- or longer than <var title="">parentNode</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>.
+ or longer than <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>.
<dt><var title="">selection</var> . <code title=dom-Selection-collapseToStart><a href=#dom-selection-collapsetostart>collapseToStart</a></code>()
<dd>
@@ -933,14 +938,17 @@
<p>Throws an <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidstateerror>InvalidStateError</a></code> exception if there is no selection.
- <dt><var title="">selection</var> . <code title=dom-Selection-extend><a href=#dom-selection-extend>extend</a></code>(<var title="">parentNode</var>, <var title="">offset</var>)
+ <dt><var title="">selection</var> .
+ <code title=dom-Selection-extend><a href=#dom-selection-extend>extend</a></code>(<var title="">node</var>,
+ <var title="">offset</var>)
<dd>
<p>Changes the <a href=#focus>focus</a> while leaving the <a href=#anchor>anchor</a> in
place.
- <p>Throws an <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidstateerror>InvalidStateError</a></code> if there's no selection, and an
+ <p>Throws an <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidstateerror>InvalidStateError</a></code> if there's no selection, an
+ <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidnodetypeerror>InvalidNodeTypeError</a></code> if <var title="">node</var> is a <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-doctype title=concept-doctype>doctype</a>, and an
<code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#indexsizeerror>IndexSizeError</a></code> exception if <var title="">offset</var> is negative or longer
- than <var title="">parentNode</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>.
+ than <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>.
<dt><var title="">selection</var> . <code title=dom-Selection-modify><a href=#dom-selection-modify>modify</a></code>(<var title="">alter</var>, <var title="">direction</var>, <var title="">granularity</var>)
<dd>
@@ -962,11 +970,11 @@
attribute must return true if the <a href=#anchor>anchor</a> and <a href=#focus>focus</a>
are the same (including if both are null). Otherwise it must return false.
-<p>The <dfn id=dom-selection-collapse title=dom-Selection-collapse><code>collapse(<var title="">parentNode</var>,
+<p>The <dfn id=dom-selection-collapse title=dom-Selection-collapse><code>collapse(<var title="">node</var>,
<var title="">offset</var>)</code></dfn> method must create a new <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>,
<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-set title=concept-range-bp-set>set</a> both its <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a> and <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a> to
-(<var title="">parentNode</var>, <var title="">offset</var>), and set the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s
-<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> to the newly-created <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>.
+(<var title="">node</var>, <var title="">offset</var>), and set the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>
+to the newly-created <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>.
<p class=comments>For collapseToStart/End, IE9 mutates the existing range,
while Firefox 9.0a2 and Chrome 15 dev replace it with a new one. The spec
@@ -992,11 +1000,9 @@
(implemented extend() in 2007). I'm mostly ignoring Opera, because gsnedders
tells me its implementation isn't compatible.
-<p>The <dfn id=dom-selection-extend title=dom-Selection-extend><code>extend(<var title="">parentNode</var>,
+<p>The <dfn id=dom-selection-extend title=dom-Selection-extend><code>extend(<var title="">node</var>,
<var title="">offset</var>)</code></dfn> method must run these steps:
-<p class=XXX>Does this mutate the existing range or make a new one?
-
<ol>
<li>
<p class=comments>Gecko raises a nonstandard exception, WebKit initializes to
@@ -1006,38 +1012,38 @@
<p>If the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> is null, <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-throw title=concept-throw>throw</a> an
<code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidstateerror>InvalidStateError</a></code> exception and abort these steps.
- <li>Let <var title="">range</var> be the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>.
-
- <li>
- <p class=comments>Gecko does this. I can't work out what WebKit does, but it
- seems weird. Why backwards? I don't know, it's what Gecko seems to do.
- (Direction in WebKit does not appear to be black-box detectable in this
- case.)
-
- <p>If <var title="">parentNode</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-root title=concept-tree-root>root</a> is not the same as <var title="">range</var>'s
- <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-root title=concept-range-root>root</a>, <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-set title=concept-range-bp-set>set</a> <var title="">range</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a> and
- <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a> to (<var title="">parentNode</var>, <var title="">offset</var>), set the
- <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s <a href=#concept-selection-dir title=concept-selection-dir>direction</a> to backwards, and abort these steps.
-
<li>Let <var title="">anchor</var> and <var title="">focus</var> be the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s
- <a href=#anchor>anchor</a> and <a href=#focus>focus</a>, and let <var title="">newFocus</var> be
- the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a> given by <var title="">parentNode</var> and <var title="">offset</var>.
-
- <li>
- <p class=comments>Gecko actually seems to set the direction to forwards if
- the selection was collapsed. But this doesn't make any sense, since it
- doesn't appear to change the direction otherwise, so I'm just going to call
- it a bug. (WebKit's direction here does not seem to be black-box
- detectable.)
-
- <p>If <var title="">focus</var> and <var title="">newFocus</var> are the same, abort these
- steps.
-
- <li><a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-set title=concept-range-bp-set>Set</a> <var title="">range</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a> to <var title="">anchor</var> and
- its <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a> to <var title="">newFocus</var>, if <var title="">anchor</var> is <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-before title=concept-range-bp-before>before</a>
- or equal to <var title="">newFocus</var>; or vice versa, if it's <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-after title=concept-range-bp-after>after</a>.
-
- <li>If <var title="">newFocus</var> is <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-before title=concept-range-bp-before>before</a> <var title="">anchor</var>, set the
+ <a href=#anchor>anchor</a> and <a href=#focus>focus</a>, and let <var title="">new focus</var> be
+ the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a> (<var title="">node</var>, <var title="">offset</var>).
+
+ <li>
+ <p class=comments>Firefox 12.0a1 seems to mutate the existing range. IE9
+ doesn't support extend(), and it's impossible to tell whether Chrome 17 dev
+ or Opera Next 12.00 alpha mutate or replace, because getRangeAt() returns a
+ copy anyway. Nevertheless, I go against Gecko here, to be consistent with
+ collapse().
+
+ <p>Let <var title="">new range</var> be a new <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>.
+
+ <li>
+ <p class=comments>Gecko sets the direction backwards here. Why backwards? I
+ don't know. I'm ignoring direction for collapsed selections for now.
+
+ <p>If <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-root title=concept-tree-root>root</a> is not the same as the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s
+ <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-root title=concept-range-root>root</a>, <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-set title=concept-range-bp-set>set</a> <var title="">new range</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a>
+ and <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a> to (<var title="">node</var>, <var title="">offset</var>).
+
+ <li>Otherwise, if <var title="">anchor</var> is <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-before title=concept-range-bp-before>before</a> or equal to
+ <var title="">new focus</var>, <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-set title=concept-range-bp-set>set</a> <var title="">new range</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a> to
+ <var title="">anchor</var>, then <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-set title=concept-range-bp-set>set</a> its <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a> to
+ <var title="">new focus</var>.
+
+ <li>Otherwise, <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-set title=concept-range-bp-set>set</a> <var title="">new range</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a> to <var title="">new
+ focus</var>, then <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-set title=concept-range-bp-set>set</a> its <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a> to <var title="">anchor</var>.
+
+ <li>Set the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> to <var title="">new range</var>.
+
+ <li>If <var title="">new focus</var> is <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-before title=concept-range-bp-before>before</a> <var title="">anchor</var>, set the
<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#context-object>context object</a>'s <a href=#concept-selection-dir title=concept-selection-dir>direction</a> to backwards. Otherwise, set it to forwards.
</ol>
@@ -1131,7 +1137,7 @@
<hr>
<dl class=domintro>
- <dt><var title="">selection</var> . <code title=dom-Selection-selectAllChildren><a href=#dom-selection-selectallchildren>selectAllChildren</a></code>(<var title="">parentNode</var>)
+ <dt><var title="">selection</var> . <code title=dom-Selection-selectAllChildren><a href=#dom-selection-selectallchildren>selectAllChildren</a></code>(<var title="">node</var>)
<dd>
<p>Replaces the selection with one that contains all the contents of the
given element.
--- a/preprocess Thu Jan 12 10:17:39 2012 -0700
+++ b/preprocess Thu Jan 12 11:44:11 2012 -0700
@@ -41,6 +41,7 @@
'dd': '<code data-anolis-spec=html title="the dd element">dd</code>',
'dl': '<code data-anolis-spec=html title="the dl element">dl</code>',
'dt': '<code data-anolis-spec=html title="the dt element">dt</code>',
+ 'doctype': '<span data-anolis-spec=dom title=concept-doctype>doctype</span>',
'document': '<span data-anolis-spec=dom title=concept-document>document</span>',
'documentfragment': '<code data-anolis-spec=dom>DocumentFragment</code>',
'documenttype': '<code data-anolis-spec=dom>DocumentType</code>',
--- a/selecttest/extend.html Thu Jan 12 10:17:39 2012 -0700
+++ b/selecttest/extend.html Thu Jan 12 11:44:11 2012 -0700
@@ -6,232 +6,142 @@
<script src=common.js></script>
<div id=log></div>
<script>
-/**
- * Returns "forwards" if the selection direction is forwards, "backwards" if
- * it's backwards. This appears not to work in WebKit at all, because there
- * seems to be no way of adding a range or replacing the current range without
- * calling removeAllRanges(), which resets the direction. So we're nice and
- * look at the current range if possible; otherwise we do some stuff that
- * involves calling removeRange(), which doesn't exist in WebKit, so it will
- * fail the test.
- */
-function getSelectionDirection() {
- if (selection.anchorNode != selection.focusNode
- || selection.anchorOffset != selection.focusOffset) {
- var range = selection.getRangeAt(selection.rangeCount - 1);
- // We can determine the direction without mangling anything.
- if (selection.anchorNode == range.startContainer
- && selection.anchorOffset == range.startOffset) {
- return "forwards";
- }
- if (selection.anchorNode == range.endContainer
- && selection.anchorOffset == range.endOffset) {
- return "backwards";
- }
- throw "Something buggy with directions";
- }
+"use strict";
- var range = document.createRange();
- range.setStart(paras[0].firstChild, 0);
- range.setEnd(paras[0].firstChild, 1);
- selection.addRange(range);
- if (selection.anchorOffset == range.startOffset) {
- selection.removeRange(range);
- return "forwards";
- }
- if (selection.anchorOffset == range.endOffset) {
- selection.removeRange(range);
- return "backwards";
- }
-}
+// Also test a selection with no ranges
+testRanges.unshift("[]");
/**
* We test Selections that go both forwards and backwards here. In the latter
* case we need to use extend() to force it to go backwards, which is fair
- * enough, since that's what we're testing.
+ * enough, since that's what we're testing. We test collapsed selections only
+ * once.
*/
-
-var originalSelectionDirection;
-
-function testExtendForwards(initialRanges, extendTarget) {
- originalSelectionDirection = "forwards";
- selection.removeAllRanges();
-
- for (var i = 0; i < initialRanges.length; i += 4) {
- var range = ownerDocument(initialRanges[i]).createRange();
- range.setStart(initialRanges[i], initialRanges[i + 1]);
- range.setEnd(initialRanges[i + 2], initialRanges[i + 3]);
- selection.addRange(range);
- }
+for (var i = 0; i < testRanges.length; i++) {
+ var endpoints = eval(testRanges[i]);
+ for (var j = 0; j < testPoints.length; j++) {
+ if (endpoints[0] == endpoints[2]
+ && endpoints[1] == endpoints[3]) {
+ // Test collapsed selections only once
+ test(function() {
+ setSelectionForwards(endpoints);
+ testExtend(endpoints, eval(testPoints[j]));
+ }, "extend() with range " + i + " " + testRanges[i]
+ + " and point " + j + " " + testPoints[j]);
+ } else {
+ test(function() {
+ setSelectionForwards(endpoints);
+ testExtend(endpoints, eval(testPoints[j]));
+ }, "extend() forwards with range " + i + " " + testRanges[i]
+ + " and point " + j + " " + testPoints[j]);
- testExtend(extendTarget, initialRanges.length/4);
-}
-
-function testExtendBackwards(initialRanges, extendTarget) {
- originalSelectionDirection = "backwards";
- selection.removeAllRanges();
-
- for (var i = 0; i < initialRanges.length; i += 4) {
- // To get a backwards selection, we add ranges by appending a
- // zero-length range at the end, then extend()ing backwards to the
- // start. This fails in Opera, since Opera ignores addRange() on a
- // collapsed range. FIXME: This doesn't actually make the initial
- // selection backwards, if the range we're given is collapsed.
- var range = ownerDocument(initialRanges[i]).createRange();
- range.setStart(initialRanges[i + 2], initialRanges[i + 3]);
- range.setEnd(initialRanges[i + 2], initialRanges[i + 3]);
- selection.addRange(range);
- selection.extend(initialRanges[i], initialRanges[i + 1]);
+ test(function() {
+ setSelectionBackwards(endpoints);
+ testExtend(endpoints, eval(testPoints[j]));
+ }, "extend() backwards with range " + i + " " + testRanges[i]
+ + " and point " + j + " " + testPoints[j]);
+ }
}
-
- testExtend(extendTarget, initialRanges.length/4);
}
-function testExtend(extendTarget, numRanges) {
- assert_equals(selection.rangeCount, numRanges,
- "Failed sanity check: selection.rangeCount is wrong. Perhaps addRange() failed.");
+function testExtend(endpoints, target) {
+ assert_equals(getSelection().rangeCount, endpoints.length/4,
+ "Sanity check: rangeCount must be correct");
- var node = extendTarget[0];
- var offset = extendTarget[1];
+ var node = target[0];
+ var offset = target[1];
- if (selection.rangeCount == 0) {
+ // "If the context object's range is null, throw an InvalidStateError
+ // exception and abort these steps."
+ if (getSelection().rangeCount == 0) {
assert_throws("INVALID_STATE_ERR", function() {
selection.extend(node, offset);
- }, "extend() when rangeCount is 0 must throw INVALID_STATE_ERR");
- return;
- }
-
- if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
- assert_throws("INVALID_NODE_TYPE_ERR", function() {
- selection.extend(node, offset);
- }, "extend() to a doctype must throw INVALID_NODE_TYPE_ERR");
- return;
- }
-
- if (offset < 0 || offset > getNodeLength(node)) {
- assert_throws("INDEX_SIZE_ERR", function() {
- selection.extend(node, offset);
- }, "extend() to an offset that's negative or greater than node length (" + getNodeLength(node) + ") must throw INDEX_SIZE_ERR");
- return;
- }
-
- var range = selection.getRangeAt(selection.rangeCount - 1);
- var rangeRoot = furthestAncestor(range.startContainer);
- var nodeRoot = furthestAncestor(node);
-
- assert_equals(rangeRoot, furthestAncestor(range.endContainer),
- "The furthest ancestor of a Range's start and end must always be the same (I think)");
-
- if (rangeRoot != nodeRoot) {
- selection.extend(node, offset);
- assert_equals(selection.anchorNode, node,
- "If the furthest ancestors of the range and extend() target differ, anchorNode must be set to the target node");
- assert_equals(selection.anchorOffset, offset,
- "If the furthest ancestors of the range and extend() target differ, anchorOffset must be set to the target offset");
- assert_equals(selection.focusNode, node,
- "If the furthest ancestors of the range and extend() target differ, focusNode must be set to the target node");
- assert_equals(selection.focusOffset, offset,
- "If the furthest ancestors of the range and extend() target differ, focusOffset must be set to the target offset");
- assert_equals(getSelectionDirection(), "backwards",
- "If the furthest ancestors of the range and extent() target differ, the new selection must be backwards");
+ }, "extend() when rangeCount is 0 must throw InvalidStateError");
return;
}
- if (selection.focusNode == node && selection.focusOffset == offset) {
- // extend() must do nothing.
- var oldFocusNode = selection.focusNode;
- var oldFocusOffset = selection.focusOffset;
- var oldAnchorNode = selection.anchorNode;
- var oldAnchorOffset = selection.anchorOffset;
- var oldRanges = [];
- for (var i = 0; i < selection.rangeCount; i++) {
- oldRanges.push(selection.getRangeAt(i));
- }
- selection.extend(node, offset);
- assert_equals(selection.focusNode, oldFocusNode,
- "extend() to the current focus must not change focusNode");
- assert_equals(selection.focusOffset, oldFocusOffset,
- "extend() to the current focus must not change focusOffset");
- assert_equals(selection.anchorNode, oldAnchorNode,
- "extend() to the current focus must not change anchorNode");
- assert_equals(selection.anchorOffset, oldAnchorOffset,
- "extend() to the current focus must not change anchorOffset");
- assert_equals(selection.rangeCount, oldRanges.length,
- "extend() to the current focus must not change rangeCount");
- for (var i = 0; i < oldRanges.length; i++) {
- assert_equals(selection.getRangeAt(i), oldRanges[i],
- "extend() to the current focus must not change any Ranges");
- }
- assert_equals(getSelectionDirection(), originalSelectionDirection,
- "extend() of a selection to the current focus must not change direction");
+ assert_equals(getSelection().getRangeAt(0).startContainer, endpoints[0],
+ "Sanity check: startContainer must be correct");
+ assert_equals(getSelection().getRangeAt(0).startOffset, endpoints[1],
+ "Sanity check: startOffset must be correct");
+ assert_equals(getSelection().getRangeAt(0).endContainer, endpoints[2],
+ "Sanity check: endContainer must be correct");
+ assert_equals(getSelection().getRangeAt(0).endOffset, endpoints[3],
+ "Sanity check: endOffset must be correct");
+
+ // "Let anchor and focus be the context object's anchor and focus, and let
+ // new focus be the boundary point (node, offset)."
+ var anchorNode = getSelection().anchorNode;
+ var anchorOffset = getSelection().anchorOffset;
+ var focusNode = getSelection().focusNode;
+ var focusOffset = getSelection().focusOffset;
+
+ // "Let new range be a new range."
+ //
+ // We'll always be setting either new range's start or its end to new
+ // focus, so we'll always throw at some point. Test that now.
+ //
+ // From DOM4's "set the start or end of a range": "If node is a doctype,
+ // throw an "InvalidNodeTypeError" exception and terminate these steps."
+ if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
+ assert_throws("INVALID_NODE_TYPE_ERR", function() {
+ selection.extend(node, offset);
+ }, "extend() to a doctype must throw InvalidNodeTypeError");
return;
}
- var oldAnchorNode = selection.anchorNode;
- var oldAnchorOffset = selection.anchorOffset;
- var oldFocusNode = selection.focusNode;
- var oldFocusOffset = selection.focusOffset;
- var oldRanges = [];
- for (var i = 0; i < selection.rangeCount; i++) {
- oldRanges.push(selection.getRangeAt(i));
+ // From DOM4's "set the start or end of a range": "If offset is greater
+ // than node's length, throw an "IndexSizeError" exception and terminate
+ // these steps."
+ //
+ // FIXME: We should be casting offset to an unsigned int per WebIDL. Until
+ // we do, we need the offset < 0 check too.
+ if (offset < 0 || offset > getNodeLength(node)) {
+ assert_throws("INDEX_SIZE_ERR", function() {
+ selection.extend(node, offset);
+ }, "extend() to an offset that's greater than node length (" + getNodeLength(node) + ") must throw IndexSizeError");
+ return;
}
- selection.extend(node, offset);
- assert_equals(selection.anchorNode, oldAnchorNode,
- "extend() must not change anchorNode in the usual case");
- assert_equals(selection.anchorOffset, oldAnchorOffset,
- "extend() must not change anchorOffset in the usual case");
- assert_equals(selection.rangeCount, oldRanges.length,
- "extend() must not change rangeCount in the usual case");
- for (var i = 0; i < oldRanges.length - 1; i++) {
- assert_equals(selection.getRangeAt(i), oldRanges[i],
- "extend() must not change any Range but the last in the usual case");
+
+ // Now back to the editing spec.
+ var originalRange = getSelection().getRangeAt(0);
+
+ // "If node's root is not the same as the context object's range's root,
+ // set new range's start and end to (node, offset)."
+ //
+ // "Otherwise, if anchor is before or equal to new focus, set new range's
+ // start to anchor, then set its end to new focus."
+ //
+ // "Otherwise, set new range's start to new focus, then set its end to
+ // anchor."
+ //
+ // "Set the context object's range to new range."
+ //
+ // "If new focus is before anchor, set the context object's direction to
+ // backwards. Otherwise, set it to forwards."
+ //
+ // The upshot of all these is summed up by just testing the anchor and
+ // offset.
+ getSelection().extend(node, offset);
+
+ if (furthestAncestor(anchorNode) == furthestAncestor(node)) {
+ assert_equals(getSelection().anchorNode, anchorNode,
+ "anchorNode must not change if the node passed to extend() has the same root as the original range");
+ assert_equals(getSelection().anchorOffset, anchorOffset,
+ "anchorOffset must not change if the node passed to extend() has the same root as the original range");
+ } else {
+ assert_equals(getSelection().anchorNode, node,
+ "anchorNode must be the node passed to extend() if it has a different root from the original range");
+ assert_equals(getSelection().anchorOffset, offset,
+ "anchorOffset must be the offset passed to extend() if the node has a different root from the original range");
}
- assert_equals(selection.focusNode, node,
- "extend() must update focusNode to the target node in the usual case");
- assert_equals(selection.focusOffset, offset,
- "extend() must update focusOffset to the target offset in the usual case");
-
- var expectedDirection;
- var range = document.createRange();
- range.setStart(oldAnchorNode, oldAnchorOffset);
- range.setEnd(oldAnchorNode, oldAnchorOffset);
- if (range.comparePoint(node, offset) >= 0) {
- expectedDirection = "forwards";
- } else {
- expectedDirection = "backwards";
- }
- assert_equals(getSelectionDirection(), expectedDirection,
- "extend() must set direction appropriately in the usual case");
+ assert_equals(getSelection().focusNode, node,
+ "focusNode must be the node passed to extend()");
+ assert_equals(getSelection().focusOffset, offset,
+ "focusOffset must be the offset passed to extend()");
+ assert_not_equals(getSelection().getRangeAt(0), originalRange,
+ "extend() must replace any existing range with a new one, not mutate the existing one");
}
-// Also test a selection with no ranges
-testRanges.unshift("[]");
-
-var tests = [];
-for (var i = 0; i < testRanges.length; i++) {
- for (var j = 0; j < testPoints.length; j++) {
- tests.push([
- "extend() forwards with range " + i + " " + testRanges[i] + " and point " + j + " " + testPoints[j],
- eval(testRanges[i]),
- eval(testPoints[j])
- ]);
- }
-}
-generate_tests(testExtendForwards, tests);
-
-// Copy-pasted with "forwards" changed to "backwards" :/
-var tests = [];
-for (var i = 0; i < testRanges.length; i++) {
- for (var j = 0; j < testPoints.length; j++) {
- tests.push([
- "extend() backwards with range " + i + " " + testRanges[i] + " and point " + j + " " + testPoints[j],
- eval(testRanges[i]),
- eval(testPoints[j])
- ]);
- }
-}
-generate_tests(testExtendBackwards, tests);
-
-// Let's be tidy.
testDiv.style.display = "none";
</script>
--- a/source.html Thu Jan 12 10:17:39 2012 -0700
+++ b/source.html Thu Jan 12 11:44:11 2012 -0700
@@ -736,6 +736,9 @@
forwards (including if the user didn't create the [[selection]], created it by
selecting an entire part of the page using a keyboard shortcut, etc.).
+<p class=XXX>Wouldn't it make more sense if addRange()/removeRange() reset
+direction?
+
<p>[[Selections]] also have an <dfn>anchor</dfn> and a <dfn>focus</dfn>. If
the [[selection]]'s [[range]] is null, its <span>anchor</span> and
<span>focus</span> are both null. If the [[selection]]'s [[range]] is not null
@@ -751,14 +754,14 @@
readonly attribute unsigned long <span title=dom-Selection-focusOffset>focusOffset</span>;
readonly attribute boolean <span title=dom-Selection-isCollapsed>isCollapsed</span>;
- void <span title=dom-Selection-collapse>collapse</span>(<span data-anolis-spec=dom>Node</span> parentNode, unsigned long offset);
+ void <span title=dom-Selection-collapse>collapse</span>(<span data-anolis-spec=dom>Node</span> node, unsigned long offset);
void <span title=dom-Selection-collapseToStart>collapseToStart</span>();
void <span title=dom-Selection-collapseToEnd>collapseToEnd</span>();
- void <span title=dom-Selection-extend>extend</span>(<span data-anolis-spec=dom>Node</span> parentNode, unsigned long offset);
+ void <span title=dom-Selection-extend>extend</span>(<span data-anolis-spec=dom>Node</span> node, unsigned long offset);
void <span title=dom-Selection-modify>modify</span>(DOMString alter, DOMString direction, DOMString granularity);
- void <span title=dom-Selection-selectAllChildren>selectAllChildren</span>(<span data-anolis-spec=dom>Node</span> parentNode);
+ void <span title=dom-Selection-selectAllChildren>selectAllChildren</span>(<span data-anolis-spec=dom>Node</span> node);
void <span title=dom-Selection-deleteFromDocument>deleteFromDocument</span>();
readonly attribute unsigned long <span title=dom-Selection-rangeCount>rangeCount</span>;
@@ -858,12 +861,14 @@
<p>Returns true if there's no selection or if the selection is empty.
Otherwise, returns false.
- <dt><var>selection</var> . <code title=dom-Selection-collapse>collapse</code>(<var>parentNode</var>, <var>offset</var>)
+ <dt><var>selection</var> .
+ <code title=dom-Selection-collapse>collapse</code>(<var>node</var>,
+ <var>offset</var>)
<dd>
<p>Replaces the selection with a collapsed one at the given position.
<p>Throws an [[IndexSizeError]] exception if <var>offset</var> is negative
- or longer than <var>parentNode</var>'s [[length]].
+ or longer than <var>node</var>'s [[length]].
<dt><var>selection</var> . <code title=dom-Selection-collapseToStart>collapseToStart</code>()
<dd>
@@ -879,14 +884,17 @@
<p>Throws an [[InvalidStateError]] exception if there is no selection.
- <dt><var>selection</var> . <code title=dom-Selection-extend>extend</code>(<var>parentNode</var>, <var>offset</var>)
+ <dt><var>selection</var> .
+ <code title=dom-Selection-extend>extend</code>(<var>node</var>,
+ <var>offset</var>)
<dd>
<p>Changes the <span>focus</span> while leaving the <span>anchor</span> in
place.
- <p>Throws an [[InvalidStateError]] if there's no selection, and an
+ <p>Throws an [[InvalidStateError]] if there's no selection, an
+ [[InvalidNodeTypeError]] if <var>node</var> is a [[doctype]], and an
[[IndexSizeError]] exception if <var>offset</var> is negative or longer
- than <var>parentNode</var>'s [[length]].
+ than <var>node</var>'s [[length]].
<dt><var>selection</var> . <code title=dom-Selection-modify>modify</code>(<var>alter</var>, <var>direction</var>, <var>granularity</var>)
<dd>
@@ -908,11 +916,11 @@
attribute must return true if the <span>anchor</span> and <span>focus</span>
are the same (including if both are null). Otherwise it must return false.
-<p>The <dfn title=dom-Selection-collapse><code>collapse(<var>parentNode</var>,
+<p>The <dfn title=dom-Selection-collapse><code>collapse(<var>node</var>,
<var>offset</var>)</code></dfn> method must create a new [[range]],
[[rangeset]] both its [[rangestart]] and [[rangeend]] to
-(<var>parentNode</var>, <var>offset</var>), and set the [[contextobject]]'s
-[[range]] to the newly-created [[range]].
+(<var>node</var>, <var>offset</var>), and set the [[contextobject]]'s [[range]]
+to the newly-created [[range]].
<p class=comments>For collapseToStart/End, IE9 mutates the existing range,
while Firefox 9.0a2 and Chrome 15 dev replace it with a new one. The spec
@@ -940,11 +948,9 @@
(implemented extend() in 2007). I'm mostly ignoring Opera, because gsnedders
tells me its implementation isn't compatible.
-<p>The <dfn title=dom-Selection-extend><code>extend(<var>parentNode</var>,
+<p>The <dfn title=dom-Selection-extend><code>extend(<var>node</var>,
<var>offset</var>)</code></dfn> method must run these steps:
-<p class=XXX>Does this mutate the existing range or make a new one?
-
<ol>
<li>
<p class=comments>Gecko raises a nonstandard exception, WebKit initializes to
@@ -954,38 +960,38 @@
<p>If the [[contextobject]]'s [[range]] is null, [[throw]] an
[[InvalidStateError]] exception and abort these steps.
- <li>Let <var>range</var> be the [[contextobject]]'s [[range]].
-
- <li>
- <p class=comments>Gecko does this. I can't work out what WebKit does, but it
- seems weird. Why backwards? I don't know, it's what Gecko seems to do.
- (Direction in WebKit does not appear to be black-box detectable in this
- case.)
-
- <p>If <var>parentNode</var>'s [[root]] is not the same as <var>range</var>'s
- [[rangeroot]], [[rangeset]] <var>range</var>'s [[rangestart]] and
- [[rangeend]] to (<var>parentNode</var>, <var>offset</var>), set the
- [[contextobject]]'s [[seldir]] to backwards, and abort these steps.
-
<li>Let <var>anchor</var> and <var>focus</var> be the [[contextobject]]'s
- <span>anchor</span> and <span>focus</span>, and let <var>newFocus</var> be
- the [[boundarypoint]] given by <var>parentNode</var> and <var>offset</var>.
-
- <li>
- <p class=comments>Gecko actually seems to set the direction to forwards if
- the selection was collapsed. But this doesn't make any sense, since it
- doesn't appear to change the direction otherwise, so I'm just going to call
- it a bug. (WebKit's direction here does not seem to be black-box
- detectable.)
-
- <p>If <var>focus</var> and <var>newFocus</var> are the same, abort these
- steps.
-
- <li>[[Rangeset]] <var>range</var>'s [[rangestart]] to <var>anchor</var> and
- its [[rangeend]] to <var>newFocus</var>, if <var>anchor</var> is [[bpbefore]]
- or equal to <var>newFocus</var>; or vice versa, if it's [[bpafter]].
-
- <li>If <var>newFocus</var> is [[bpbefore]] <var>anchor</var>, set the
+ <span>anchor</span> and <span>focus</span>, and let <var>new focus</var> be
+ the [[boundarypoint]] (<var>node</var>, <var>offset</var>).
+
+ <li>
+ <p class=comments>Firefox 12.0a1 seems to mutate the existing range. IE9
+ doesn't support extend(), and it's impossible to tell whether Chrome 17 dev
+ or Opera Next 12.00 alpha mutate or replace, because getRangeAt() returns a
+ copy anyway. Nevertheless, I go against Gecko here, to be consistent with
+ collapse().
+
+ <p>Let <var>new range</var> be a new [[range]].
+
+ <li>
+ <p class=comments>Gecko sets the direction backwards here. Why backwards? I
+ don't know. I'm ignoring direction for collapsed selections for now.
+
+ <p>If <var>node</var>'s [[root]] is not the same as the [[contextobject]]'s
+ [[range]]'s [[rangeroot]], [[rangeset]] <var>new range</var>'s [[rangestart]]
+ and [[rangeend]] to (<var>node</var>, <var>offset</var>).
+
+ <li>Otherwise, if <var>anchor</var> is [[bpbefore]] or equal to
+ <var>new focus</var>, [[rangeset]] <var>new range</var>'s [[rangestart]] to
+ <var>anchor</var>, then [[rangeset]] its [[rangeend]] to
+ <var>new focus</var>.
+
+ <li>Otherwise, [[rangeset]] <var>new range</var>'s [[rangestart]] to <var>new
+ focus</var>, then [[rangeset]] its [[rangeend]] to <var>anchor</var>.
+
+ <li>Set the [[contextobject]]'s [[range]] to <var>new range</var>.
+
+ <li>If <var>new focus</var> is [[bpbefore]] <var>anchor</var>, set the
[[contextobject]]'s [[seldir]] to backwards. Otherwise, set it to forwards.
</ol>
@@ -1080,7 +1086,7 @@
<hr>
<dl class=domintro>
- <dt><var>selection</var> . <code title=dom-Selection-selectAllChildren>selectAllChildren</code>(<var>parentNode</var>)
+ <dt><var>selection</var> . <code title=dom-Selection-selectAllChildren>selectAllChildren</code>(<var>node</var>)
<dd>
<p>Replaces the selection with one that contains all the contents of the
given element.