Redefine document.getSelection() again
authorAryeh Gregor <ayg@aryeh.name>
Tue, 17 Jan 2012 10:30:26 -0700
changeset 693 4dc4d65cc87e
parent 692 bf41eff7558d
child 694 c158d3920e41
Redefine document.getSelection() again

See links to discussion added to spec comments. This re-adds three
tests, which now pass in Chrome 17 dev, fail in IE9 and Opera Next 12.00
alpha, and 1/3 pass in Firefox 12.0a1. (Interestingly,
document.getSelection() in Gecko usually returns the window's selection,
but in an iframe returns null.)
editing.html
selecttest/getSelection.html
source.html
--- a/editing.html	Thu Jan 12 12:02:26 2012 -0700
+++ b/editing.html	Tue Jan 17 10:30:26 2012 -0700
@@ -67,7 +67,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-12-january-2012>Work in Progress &mdash; Last Update 12 January 2012</h2>
+<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-17-january-2012>Work in Progress &mdash; Last Update 17 January 2012</h2>
 <dl>
  <dt>Editor
  <dd>Aryeh Gregor &lt;<a href=mailto:[email protected]>[email protected]</a>&gt;
@@ -724,15 +724,21 @@
 <p>See <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=15470">bug
 15470</a>.  IE9, Firefox 12.0a1, Chrome 17 dev, and Opera Next 12.00 alpha all
 make the range initially null.
+
+<p>For the stuff about <code title="">defaultView</code>, see the comments on
+<code title=dom-Document-getSelection><a href=#dom-document-getselection>document.getSelection()</a></code>.
 </div>
 
-<p>Every <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a> has a unique <code><a href=#selection>Selection</a></code> object associated
-with it.  <code><a href=#selection>Selection</a></code> objects are known as <dfn id=concept-selection title=concept-selection>selections</dfn>.  Each <a href=#concept-selection title=concept-selection>selection</a> is associated
-with a single <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>, which may be null and is initially null.  This one
-<a href=#concept-selection title=concept-selection>selection</a> must be shared by all the content of the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a> (though not
-by nested <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>documents</a>), including any editing hosts in the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a>.
-<a href=#editing-host title="editing host">Editing hosts</a> that are not inside a
-<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a> cannot have a <a href=#concept-selection title=concept-selection>selection</a>.
+<p>Every <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a> with a non-null
+<code class=external data-anolis-spec=html title=dom-Document-defaultView><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#dom-document-defaultview>defaultView</a></code>
+has a unique <code><a href=#selection>Selection</a></code> object associated with it.
+<code><a href=#selection>Selection</a></code> objects are known as
+<dfn id=concept-selection title=concept-selection>selections</dfn>.  Each <a href=#concept-selection title=concept-selection>selection</a> is
+associated with a single <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>, which may be null and is initially null.
+This one <a href=#concept-selection title=concept-selection>selection</a> must be shared by all the content of the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a>
+(though not by nested <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>documents</a>), including any editing hosts in the
+<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a>.  <a href=#editing-host title="editing host">Editing hosts</a> that are not
+inside a <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a> cannot have a <a href=#concept-selection title=concept-selection>selection</a>.
 
 <p class=comments>This is a requirement of the HTML spec.  IE9 and Opera Next
 12.00 alpha seem to follow it, while Firefox 12.0a1 and Chrome 17 dev seem not
@@ -1178,22 +1184,30 @@
   <a href=#selection>Selection</a> <a href=#dom-document-getselection title=dom-Document-getSelection>getSelection</a>();
 };</pre>
 
-<p class=comments>Originally Gecko returned the stringification here (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=636512">bug 636512</a> fixed
-that).  Now, what happens if you create a Document object with no defaultView
+<div class=comments>
+<p>Originally Gecko returned the stringification here (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=636512">bug 636512</a> fixed
+that).
+
+<p>Now, what happens if you create a Document object with no defaultView
 (say via <code title="">document.implementation.createHTMLDocument("")</code>) and call
 <code title="">getSelection()</code> on it?  IE9 seems to return a different Selection
 object.  Firefox 12.0a1 and Opera Next 12.00 alpha return the same object as
-for the current window.  Chrome 17 dev returns null.  We go with IE9 for now,
-because it's the simplest to spec and understand -- we don't have to
-distinguish between different kinds of documents.  But maybe this isn't
-desired.
+for the current window.  Chrome 17 dev returns null.  See
+<a href=http://lists.w3.org/Archives/Public/public-webapps/2012JanMar/0159.html>discussion</a>.
+There's no meaningful selection associated with such a document, so we follow
+WebKit and require returning null.
+
+<p>This leaves open the question of which documents should actually return
+null.  We somewhat cheat by deferring the question to the definition of
+<code title="">defaultView</code>, even though at the time of this writing that's
+<a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=15548">underdefined and
+not very interoperable</a>.
+</div>
 
 <p>The <dfn id=dom-document-getselection title=dom-Document-getSelection><code>getSelection()</code></dfn>
 method on the <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#document>Document</a></code> interface must return
-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 title=concept-selection>selection</a>.
-
-<p class=XXX>Browsers other than IE don't actually give every document a
-selection.  Consider changing this to match Gecko or WebKit.
+null 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 <code class=external data-anolis-spec=html title=dom-Document-defaultView><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#dom-document-defaultview>defaultView</a></code> is null, and 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 title=concept-selection>selection</a> otherwise.
 
 <pre class=idl>partial interface <a class=external data-anolis-spec=html href=http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#window>Window</a> {
   <a href=#selection>Selection</a> <a href=#dom-window-getselection title=dom-Window-getSelection>getSelection</a>();
@@ -1201,7 +1215,9 @@
 
 <p>The <dfn id=dom-window-getselection title=dom-Window-getSelection><code>getSelection()</code></dfn>
 method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#window>Window</a></code> interface must return
-the the <a href=#concept-selection title=concept-selection>selection</a> of the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a> returned by 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
+the same thing as calling
+<code title=dom-Document-getSelection><a href=#dom-document-getselection>getSelection()</a></code> on the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-document title=concept-document>document</a>
+returned by 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
 <code class=external data-anolis-spec=html title=dom-document-0><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#dom-document-0>document</a></code> property.
 
 
--- a/selecttest/getSelection.html	Thu Jan 12 12:02:26 2012 -0700
+++ b/selecttest/getSelection.html	Tue Jan 17 10:30:26 2012 -0700
@@ -6,10 +6,14 @@
 <script>
 "use strict";
 
+// TODO: Figure out more places where defaultView is or is not guaranteed to be
+// null, and test whether getSelection() is null.
+
 test(function() {
 	// Sanity checks like this are to flag known browser bugs with clearer
 	// error messages, instead of throwing inscrutable exceptions.
-	assert_true("Selection" in window, "window must have Selection property");
+	assert_true("Selection" in window,
+		"Sanity check: window must have Selection property");
 
 	assert_true(window.getSelection() instanceof Selection);
 }, "window.getSelection() instanceof Selection");
@@ -19,16 +23,27 @@
 }, "window.getSelection() === window.getSelection()");
 
 test(function() {
-	assert_true("Selection" in window, "window must have Selection property");
+	assert_true("Selection" in window,
+		"Sanity check: window must have Selection property");
+	// This sanity check (which occurs a number of times below, too) is because
+	// document.getSelection() is supposed to return null if defaultView is
+	// null, so we need to figure out whether defaultView is null or not before
+	// we can make correct assertions about getSelection().
+	assert_not_equals(document.defaultView, null,
+		"Sanity check: document.defaultView must not be null");
 
 	assert_true(document.getSelection() instanceof Selection);
 }, "document.getSelection() instanceof Selection");
 
 test(function() {
+	assert_not_equals(document.defaultView, null,
+		"Sanity check: document.defaultView must not be null");
 	assert_equals(document.getSelection(), document.getSelection());
 }, "document.getSelection() === document.getSelection()");
 
 test(function() {
+	assert_not_equals(document.defaultView, null,
+		"Sanity check: document.defaultView must not be null");
 	assert_equals(window.getSelection(), document.getSelection());
 }, "window.getSelection() === document.getSelection()");
 
@@ -44,38 +59,35 @@
 		"document.getSelection().rangeCount must initially be 0");
 }, "Selection's range must initially be null");
 
-// Commented out pending decision on what the correct behavior is
-/*
 test(function() {
-	assert_true("Selection" in window, "window must have Selection property");
-
 	var doc = document.implementation.createHTMLDocument("");
-	assert_true(doc.getSelection() instanceof Selection,
-		"getSelection() on HTML document with no browsing context must be instanceof Selection");
-	assert_equals(doc.getSelection(), document.getSelection(),
-		"getSelection() on HTML document with no browsing context must be same as the window");
+	assert_equals(doc.defaultView, null,
+		"Sanity check: defaultView of created HTML document must be null");
+	assert_equals(doc.getSelection(), null,
+		"getSelection() on HTML document with null defaultView must be null");
 }, "HTML document with no browsing context");
 
 test(function() {
 	var xmlDoc = document.implementation.createDocument(null, "", null);
 
 	assert_true("getSelection" in xmlDoc, "XML document must have getSelection()");
-	assert_true("Selection" in window, "window must have Selection property");
 
-	assert_true(xmlDoc.getSelection() instanceof Selection,
-		"getSelection() on XML document with no browsing context must be instanceof Selection");
-	assert_equals(xmlDoc.getSelection(), document.getSelection(),
-		"getSelection() on XML document with no browsing context must be same as the window");
+	assert_equals(xmlDoc.defaultView, null,
+		"Sanity check: defaultView of created XML document must be null");
+	assert_equals(xmlDoc.getSelection(), null,
+		"getSelection() on XML document with null defaultView must be null");
 }, "XML document with no browsing context");
-*/
 
 var iframe = document.createElement("iframe");
 document.body.appendChild(iframe);
 test(function() {
-	assert_true("Selection" in iframe.contentWindow, "window must have Selection property");
+	assert_true("Selection" in iframe.contentWindow,
+		"Sanity check: window must have Selection property");
 
 	assert_true(iframe.contentWindow.getSelection() instanceof iframe.contentWindow.Selection,
 		"window.getSelection() instanceof Selection");
+	assert_not_equals(iframe.contentDocument.defaultView, null,
+		"Sanity check: document.defaultView must not be null");
 	assert_true(iframe.contentDocument.getSelection() instanceof iframe.contentWindow.Selection,
 		"document.getSelection() instanceof Selection");
 	assert_equals(iframe.contentWindow.getSelection(), iframe.contentDocument.getSelection(),
@@ -84,16 +96,12 @@
 		"getSelection() inside and outside iframe must return different objects");
 }, "In an iframe");
 
-/*
 test(function() {
-	assert_true("Selection" in iframe.contentWindow, "window must have Selection property");
-
 	var doc = iframe.contentDocument.implementation.createHTMLDocument("");
-	assert_true(doc.getSelection() instanceof iframe.contentWindow.Selection,
-		"getSelection() on HTML document with no browsing context must be instanceof Selection");
-	assert_equals(doc.getSelection(), iframe.contentDocument.getSelection(),
-		"getSelection() on HTML document with no browsing context must be same as the window");
+	assert_equals(doc.defaultView, null,
+		"Sanity check: defaultView of created HTML document must be null");
+	assert_equals(doc.getSelection(), null,
+		"getSelection() on HTML document with null defaultView must be null");
 }, "HTML document with no browsing context inside an iframe");
-*/
 document.body.removeChild(iframe);
 </script>
--- a/source.html	Thu Jan 12 12:02:26 2012 -0700
+++ b/source.html	Tue Jan 17 10:30:26 2012 -0700
@@ -662,16 +662,21 @@
 <p>See <a href=https://www.w3.org/Bugs/Public/show_bug.cgi?id=15470>bug
 15470</a>.  IE9, Firefox 12.0a1, Chrome 17 dev, and Opera Next 12.00 alpha all
 make the range initially null.
+
+<p>For the stuff about {{code|defaultView}}, see the comments on
+<code title=dom-Document-getSelection>document.getSelection()</code>.
 </div>
 
-<p>Every [[document]] has a unique <code>Selection</code> object associated
-with it.  <code>Selection</code> objects are known as <dfn
-title=concept-selection>selections</dfn>.  Each [[selection]] is associated
-with a single [[range]], which may be null and is initially null.  This one
-[[selection]] must be shared by all the content of the [[document]] (though not
-by nested [[documents]]), including any editing hosts in the [[document]].
-<span title="editing host">Editing hosts</span> that are not inside a
-[[document]] cannot have a [[selection]].
+<p>Every [[document]] with a non-null
+<code data-anolis-spec=html title=dom-Document-defaultView>defaultView</code>
+has a unique <code>Selection</code> object associated with it.
+<code>Selection</code> objects are known as
+<dfn title=concept-selection>selections</dfn>.  Each [[selection]] is
+associated with a single [[range]], which may be null and is initially null.
+This one [[selection]] must be shared by all the content of the [[document]]
+(though not by nested [[documents]]), including any editing hosts in the
+[[document]].  <span title="editing host">Editing hosts</span> that are not
+inside a [[document]] cannot have a [[selection]].
 
 <p class=comments>This is a requirement of the HTML spec.  IE9 and Opera Next
 12.00 alpha seem to follow it, while Firefox 12.0a1 and Chrome 17 dev seem not
@@ -1133,23 +1138,32 @@
   <span>Selection</span> <span title=dom-Document-getSelection>getSelection</span>();
 };</pre>
 
-<p class=comments>Originally Gecko returned the stringification here (<a
+<div class=comments>
+<p>Originally Gecko returned the stringification here (<a
 href=https://bugzilla.mozilla.org/show_bug.cgi?id=636512>bug 636512</a> fixed
-that).  Now, what happens if you create a Document object with no defaultView
+that).
+
+<p>Now, what happens if you create a Document object with no defaultView
 (say via {{code|document.implementation.createHTMLDocument("")}}) and call
 {{code|getSelection()}} on it?  IE9 seems to return a different Selection
 object.  Firefox 12.0a1 and Opera Next 12.00 alpha return the same object as
-for the current window.  Chrome 17 dev returns null.  We go with IE9 for now,
-because it's the simplest to spec and understand -- we don't have to
-distinguish between different kinds of documents.  But maybe this isn't
-desired.
+for the current window.  Chrome 17 dev returns null.  See
+<a href=http://lists.w3.org/Archives/Public/public-webapps/2012JanMar/0159.html>discussion</a>.
+There's no meaningful selection associated with such a document, so we follow
+WebKit and require returning null.
+
+<p>This leaves open the question of which documents should actually return
+null.  We somewhat cheat by deferring the question to the definition of
+{{code|defaultView}}, even though at the time of this writing that's
+<a href=https://www.w3.org/Bugs/Public/show_bug.cgi?id=15548>underdefined and
+not very interoperable</a>.
+</div>
 
 <p>The <dfn title=dom-Document-getSelection><code>getSelection()</code></dfn>
 method on the <code data-anolis-spec=dom>Document</code> interface must return
-the [[contextobject]]'s [[selection]].
-
-<p class=XXX>Browsers other than IE don't actually give every document a
-selection.  Consider changing this to match Gecko or WebKit.
+null if the [[contextobject]]'s <code data-anolis-spec=html
+title=dom-Document-defaultView>defaultView</code> is null, and the
+[[contextobject]]'s [[selection]] otherwise.
 
 <pre class=idl>partial interface <span data-anolis-spec=html>Window</span> {
   <span>Selection</span> <span title=dom-Window-getSelection>getSelection</span>();
@@ -1157,7 +1171,9 @@
 
 <p>The <dfn title=dom-Window-getSelection><code>getSelection()</code></dfn>
 method on the <code data-anolis-spec=html>Window</code> interface must return
-the the [[selection]] of the [[document]] returned by the [[contextobject]]'s
+the same thing as calling
+<code title=dom-Document-getSelection>getSelection()</code> on the [[document]]
+returned by the [[contextobject]]'s
 <code data-anolis-spec=html title=dom-document-0>document</code> property.
 <!-- @} -->