This document is a preliminary draft of a specification for the Selection API and selection related functionality. It replaces a couple of old sections of the HTML specification , the selection part of the old DOM Range specification .

Since this specification is intended to be charted by the Web Applications Working Group, any feedback or discussion of this specification should be posted to public-webapps mailing list with "[Selection API]" in the subject.

This document is merely a public working draft of a potential specification. It has no official standing of any kind and does not represent the support or consensus of any standards organisation.

But this meant getRangeAt() had to start returning a copy, not a reference. Also, it would be prone to things failing weirdly in corner cases. Perhaps most significantly, all sorts of problems might arise when DOM mutations transpire, like if a boundary point's node is removed from its parent and the mutation rules would place the new boundary point inside a non-Text/Element node. And finally, the previously-specified behavior had the advantage of matching two major implementations, while the new behavior matched no one. So I changed it back.

So I changed the spec to a made-up compromise that allows some simplification but doesn't constrain authors much. See discussion . Basically it would throw exceptions in some places to try to stop the selection from containing a range that had a boundary point other than an Element or Text node, or a boundary point that didn't descend from a Document.

IE9 and Firefox 6.0a2 allow arbitrary ranges in the selection, which follows what this spec originally said. However, this leads to unpleasant corner cases that authors, implementers, and spec writers all have to deal with, and they don't make any real sense. Chrome 14 dev and Opera 11.11 aggressively normalize selections, like not letting them lie inside empty elements and things like that, but this is also viewed as a bad idea, because it takes flexibility away from authors.

2. Definition

Every document ([ DOM4 ]) with a browsing context ([ HTML5 ]) has a unique Selection object associated with it. Selection objects are known as selection s.

Note 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 to. See Mozilla bug, WebKit bug.

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. Editing hosts (defined in [ HTML5 ]) that are not inside a document cannot have a selection

Issue 1 We need to define what it means to say editing hosts can't have selection.

Each selection can be associated with a single range (defined in [ DOM4 ]). When there is no range associated with the selection, the selection is empty . The selection must be initially empty.

Note A document's selection is a singleton object associated with that document, so it gets replaced with a new object when Document.open() is called. See bug 15470. IE9 and Opera Next 12.00 alpha allow the user to reset the range to null after the fact by clicking somewhere; Firefox 12.0a1 and Chrome 17 dev do not. We follow Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.

Once a selection is associated with a given range, it must continue to be associated with that same range until this specification requires otherwise.

Note For instance, if the DOM changes in a way that changes the range's boundary points, or a script modifies the boundary points of the range, the same range object must continue to be associated with the selection. However, if the user changes the selection or a script calls addRange() , the selection must be associated with a new range object, as required elsewhere in this specification.

Issue 2 This paragraph is vague. It needs to be replaced by detailed conformance requirements saying exactly what to do for particular keystrokes, like we have for backspace/delete/etc.

If the selection's range is not null and is collapsed ([ DOM4 ]), then the caret position must be at that range's boundary point . When the selection is not empty, this specification does not define the caret position; user agents should follow platform conventions in deciding whether the caret is at the start of the selection, the end of the selection, or somewhere else.

Note This short-changes Mac users. See bug 13909.

Each selection has a direction , forwards , backwards , or directionless . If the user creates a selection by indicating first one boundary point of the range and then the other (such as by clicking on one point and dragging to another), and the first indicated boundary point is after ([ DOM4 ]) the second, then the corresponding selection must initially be backwards. If the first indicated boundary point is before ([ DOM4 ]) the second, then the corresponding selection must initially be forwards. Otherwise, it must be directionless.

Issue 3 Should addRange() and removeAllRanges() reset direction?

Selection s also have an anchor and a focus . If the selection's range is null, its anchor and focus are both null. If the selection's range is not null and its direction is forwards, its anchor is the range's start, and its focus is the end. Otherwise, its focus is the start and its anchor is the end.

Selection { Node? anchorNode readonly attribute unsigned long anchorOffset readonly attribute Node? focusNode readonly attribute unsigned long focusOffset readonly attribute boolean isCollapsed readonly attribute unsigned long rangeCount readonly attribute Range getRangeAt unsigned long index ); ); void addRange Range range ); void removeRange Range range ); void removeAllRanges (); void collapse Node node unsigned long offset ); ); void collapseToStart (); void collapseToEnd (); void extend Node node unsigned long offset ); ); void selectAllChildren Node node ); void deleteFromDocument (); stringifier DOMString (); interface};

Note See also nsISelection.idl from Gecko. This spec doesn't have everything from there yet, in particular selectionLanguageChange() and containsNode() are missing. They are missing because I couldn't work out how to define them in terms of Ranges.

Note Originally, the Selection interface was a Netscape feature. The original implementation was carried on into Gecko (Firefox), and the feature was later implemented independently by other browser engines. The Netscape implementation always allowed multiple ranges in a single selection, for instance so the user could select a column of a table However, multi-range selections proved to be an unpleasant corner case that web developers didn't know about and even Gecko developers rarely handled correctly. Other browser engines never implemented the feature, and clamped selections to a single range in various incompatible fashions. This specification follows non-Gecko engines in restricting selections to at most one range, but the API was still originally designed for selections with arbitrary numbers of ranges. This explains oddities like the coexistence of removeRange() and removeAllRanges() , and a getRangeAt() method that takes an integer argument that must always be zero.

All of the members of the Selection interface are defined in terms of operations on the range object (if any) represented by the object. These operations can raise exceptions, as defined for the Range ([ DOM4 ]) interface; this can therefore result in the members of the Selection interface raising exceptions as well, in addition to any explicitly called out below.