Test selectAllChildren, and fix the spec
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Mon, 24 Oct 2011 14:05:38 -0600
changeset 647 9b344f5db52c
parent 646 ff44f1e1f4b9
child 648 210a670d6227
Test selectAllChildren, and fix the spec

The spec didn't say to throw for doctypes, and it said to set the end to
the node's length instead of the number of children.
editing.html
selecttest/common.js
selecttest/selectAllChildren.html
source.html
--- a/editing.html	Mon Oct 24 13:30:37 2011 -0600
+++ b/editing.html	Mon Oct 24 14:05:38 2011 -0600
@@ -65,7 +65,7 @@
 <body class=draft>
 <div class=head id=head>
 <h1>HTML Editing APIs</h1>
-<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-11-october-2011>Work in Progress &mdash; Last Update 11 October 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-24-october-2011>Work in Progress &mdash; Last Update 24 October 2011</h2>
 <dl>
  <dt>Editor
  <dd>Aryeh Gregor &lt;<a href=mailto:[email protected]>[email protected]</a>&gt;
@@ -1100,11 +1100,30 @@
     <p>Deletes the selection.
 </dl>
 
+<div class=comments>
+<p>Based mostly on Firefox 9.0a2.  It has a bug that I didn't reproduce, namely
+that if you pass a Document as the argument, the end offset becomes 1 instead
+of the number of children it has.  It also throws a RangeException instead of
+DOMException, because its implementation predated their merging.
+
+<p>IE9 behaves similarly but with glitches.  It throws "Unspecified error." if
+the node is detached or display:none, and apparently in some random other cases
+too.  It throws "Invalid argument." for detached comments (only!).  Finally, if
+you pass it a comment, it seems to select the whole comment, unlike with text
+nodes.
+
+<p>Chrome 16 dev behaves as you'd expect given its Selection implementation.
+It refuses to select anything that's not visible, so it's almost always wrong.
+Opera 11.50 just does nothing in all my tests, as usual.
+</div>
+
 <p>The <dfn id=dom-selection-selectallchildren title=dom-Selection-selectAllChildren><code>selectAllChildren(<var title="">parentNode</var>)</code></dfn>
-method must 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 one whose <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>
-is (<var title="">parentNode</var>, 0) and whose <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> is (<var title="">parentNode</var>,
-<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>), then 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 "forwards".
+method must <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#invalidnodetypeerror>InvalidNodeTypeError</a></code> if <var title="">parentNode</var> is a
+<code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#documenttype>DocumentType</a></code>.  Otherwise, it must 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
+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> whose <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start-node title=concept-range-start-node>start node</a> and <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end-node title=concept-range-end-node>end node</a> are <var title="">parentNode</var>,
+whose <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start-offset title=concept-range-start-offset>start offset</a> is 0, and whose <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end-offset title=concept-range-end-offset>end offset</a> is the number of
+<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-child title=concept-tree-child>children</a>; then 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 forwards.
 
 <p>The <dfn id=dom-selection-deletefromdocument title=dom-Selection-deleteFromDocument><code>deleteFromDocument()</code></dfn>
 method must do nothing 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, and
--- a/selecttest/common.js	Mon Oct 24 13:30:37 2011 -0600
+++ b/selecttest/common.js	Mon Oct 24 14:05:38 2011 -0600
@@ -910,3 +910,17 @@
 	throw e;
 }
 
+/**
+ * Given an array of endpoint data [start container, start offset, end
+ * container, end offset], returns a Range with those endpoints.  Uses
+ * addRange, so the range will always be forwards.
+ */
+function rangeFromEndpoints(endpoints) {
+	// If we just use document instead of the ownerDocument of endpoints[0],
+	// WebKit will throw on setStart/setEnd.  This is a WebKit bug, but it's in
+	// range, not selection, so we don't want to fail anything for it.
+	var range = ownerDocument(endpoints[0]).createRange();
+	range.setStart(endpoints[0], endpoints[1]);
+	range.setEnd(endpoints[2], endpoints[3]);
+	return range;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selecttest/selectAllChildren.html	Mon Oct 24 14:05:38 2011 -0600
@@ -0,0 +1,42 @@
+<!doctype html>
+<title>Selection.selectAllChildren tests</title>
+<div id=log></div>
+<script src=http://w3c-test.org/resources/testharness.js></script>
+<script src=common.js></script>
+<script>
+"use strict";
+
+// TODO: Test what happens if there's an existing range in the selection.  Make
+// sure a new range is created, rather than the existing range being replaced.
+
+for (var i = 0; i < testNodes.length; i++) {
+	test(function() {
+		selection.removeAllRanges();
+
+		var node = eval(testNodes[i]);
+
+		if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
+			assert_throws("INVALID_NODE_TYPE_ERR", function() {
+				selection.selectAllChildren(node);
+			}, "selectAllChildren() on a DocumentType must throw InvalidNodeTypeError");
+			return;
+		}
+
+		selection.selectAllChildren(node);
+		// This implicitly tests that the selection is forwards, by using
+		// anchorOffset/focusOffset instead of getRangeAt.
+		assert_equals(selection.rangeCount, 1,
+			"After selectAllChildren, rangeCount must be 1");
+		assert_equals(selection.anchorNode, node,
+			"After selectAllChildren, anchorNode must be the given node");
+		assert_equals(selection.anchorOffset, 0,
+			"After selectAllChildren, anchorOffset must be 0");
+		assert_equals(selection.focusNode, node,
+			"After selectAllChildren, focusNode must be the given node");
+		assert_equals(selection.focusOffset, node.childNodes.length,
+			"After selectAllChildren, focusOffset must be the given node's number of children");
+	}, "Node " + i + " " + testNodes[i]);
+}
+
+testDiv.style.display = "none";
+</script>
--- a/source.html	Mon Oct 24 13:30:37 2011 -0600
+++ b/source.html	Mon Oct 24 14:05:38 2011 -0600
@@ -1046,12 +1046,31 @@
     <p>Deletes the selection.
 </dl>
 
+<div class=comments>
+<p>Based mostly on Firefox 9.0a2.  It has a bug that I didn't reproduce, namely
+that if you pass a Document as the argument, the end offset becomes 1 instead
+of the number of children it has.  It also throws a RangeException instead of
+DOMException, because its implementation predated their merging.
+
+<p>IE9 behaves similarly but with glitches.  It throws "Unspecified error." if
+the node is detached or display:none, and apparently in some random other cases
+too.  It throws "Invalid argument." for detached comments (only!).  Finally, if
+you pass it a comment, it seems to select the whole comment, unlike with text
+nodes.
+
+<p>Chrome 16 dev behaves as you'd expect given its Selection implementation.
+It refuses to select anything that's not visible, so it's almost always wrong.
+Opera 11.50 just does nothing in all my tests, as usual.
+</div>
+
 <p>The <dfn
 title=dom-Selection-selectAllChildren><code>selectAllChildren(<var>parentNode</var>)</code></dfn>
-method must set the [[contextobject]]'s [[range]] to one whose [[rangestart]]
-is (<var>parentNode</var>, 0) and whose [[rangeend]] is (<var>parentNode</var>,
-<var>parentNode</var>'s [[length]]), then set the [[contextobject]]'s
-[[seldir]] to "forwards".
+method must [[throw]] an [[InvalidNodeTypeError]] if <var>parentNode</var> is a
+[[documenttype]].  Otherwise, it must set the [[contextobject]]'s [[range]] to
+a new [[range]] whose [[startnode]] and [[endnode]] are <var>parentNode</var>,
+whose [[startoffset]] is 0, and whose [[endoffset]] is the number of
+<var>parentNode</var>'s [[children]]; then set the [[contextobject]]'s
+[[seldir]] to forwards.
 
 <p>The <dfn
 title=dom-Selection-deleteFromDocument><code>deleteFromDocument()</code></dfn>