├── W3CTRMANIFEST ├── .pr-preview.json ├── tidyconfig.txt ├── w3c.json ├── LICENSE.md ├── CODE_OF_CONDUCT.md ├── README.md ├── .github ├── workflows │ ├── tidy.yml │ └── auto-publish.yml └── PULL_REQUEST_TEMPLATE.md ├── CONTRIBUTING.md ├── index.html └── publish ├── FPWD-selection-api-20141007.html └── WD-selection-api-2015-Oct.html /W3CTRMANIFEST: -------------------------------------------------------------------------------- 1 | index.html?specStatus=WD&shortName=selection-api respec 2 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.html", 3 | "type": "respec" 4 | } 5 | -------------------------------------------------------------------------------- /tidyconfig.txt: -------------------------------------------------------------------------------- 1 | char-encoding: utf8 2 | indent: yes 3 | indent-spaces: 2 4 | wrap: 80 5 | tidy-mark: no 6 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [ 3 | "131776" 4 | ], 5 | "contacts": [ 6 | "siusin" 7 | ], 8 | "shortName": "selection-api", 9 | "repo-type": "rec-track" 10 | } 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All documents in this Repository are licensed by contributors 2 | under the 3 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). 4 | 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | selection-api 2 | ============= 3 | 4 | [Selection API Specification](http://w3c.github.io/selection-api/) defines APIs for selection, 5 | which allows users and authors to select a portion of 6 | a document or specify a point of interest for copy, paste, and other editing operations. 7 | -------------------------------------------------------------------------------- /.github/workflows/tidy.yml: -------------------------------------------------------------------------------- 1 | name: Tidy document 2 | on: 3 | workflow_dispatch: {} 4 | push: 5 | branches: 6 | - gh-pages 7 | 8 | jobs: 9 | tidy: 10 | name: Tidy up 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Install tidy/html5 15 | run: sudo apt-get install -y tidy 16 | - run: tidy -config tidyconfig.txt -o index.html index.html 17 | - uses: peter-evans/create-pull-request@v5 18 | with: 19 | title: "Tidied up document using tidy-html5" 20 | commit-message: "chore: tidy up index.html" 21 | branch: html-tidy 22 | -------------------------------------------------------------------------------- /.github/workflows/auto-publish.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - gh-pages 7 | pull_request: {} 8 | 9 | jobs: 10 | validate-and-publish: 11 | name: Validate and Publish 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: w3c/spec-prod@v2 16 | with: 17 | TOOLCHAIN: respec 18 | W3C_ECHIDNA_TOKEN: ${{ secrets.ECHIDNA_TOKEN }} 19 | W3C_WG_DECISION_URL: "https://lists.w3.org/Archives/Public/public-webapps/2014JulSep/0627.html" 20 | W3C_NOTIFICATIONS_CC: "${{ secrets.CC }}" 21 | W3C_BUILD_OVERRIDE: | 22 | specStatus: WD 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | For normative changes, the following tasks have been completed: 4 | * [ ] Editing WG resolution on the proposed changes, with at least two implementers participating and not objecting: 5 | * [ ] WebKit 6 | * [ ] Chromium 7 | * [ ] Gecko 8 | 9 | * [ ] For browsers that are shipping the feature, implementation bugs are filed for the proposed changes (link to bug, or write "Not Implementing"): 10 | * [ ] WebKit (https://bugs.webkit.org/show_bug.cgi?id=) 11 | * [ ] Chromium (https://bugs.chromium.org/p/chromium/issues/detail?id=) 12 | * [ ] Gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=) -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributions to this repository are intended to become part of Recommendation-track documents 2 | governed by the [W3C Patent Policy](https://www.w3.org/Consortium/Patent-Policy/) and 3 | [Document License](https://www.w3.org/Consortium/Legal/copyright-documents). To contribute, you must 4 | either participate in the relevant W3C Working Group or make a non-member patent licensing 5 | commitment. 6 | 7 | If you are not the sole contributor to a contribution (pull request), please identify all 8 | contributors in the pull request's body or in subsequent comments. 9 | 10 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 11 | 12 | ``` 13 | +@github_username 14 | ``` 15 | 16 | If you added a contributor by mistake, you can remove them in a comment with: 17 | 18 | ``` 19 | -@github_username 20 | ``` 21 | 22 | If you are making a pull request on behalf of someone else but you had no part in designing the 23 | feature, you can remove yourself with the above syntax. 24 | 25 | ## Tests 26 | For normative changes, a corresponding 27 | [web-platform-tests](https://github.com/web-platform-tests/wpt) PR should be included. Typically, 28 | both PRs will be merged at the same time. Note that a test change that contradicts the spec should 29 | not be merged before the corresponding spec change. If testing is not practical, please explain why 30 | and if appropriate [file an issue](https://github.com/web-platform-tests/wpt/issues/new) to follow 31 | up later. Add the `type:untestable` or `type:missing-coverage` label as appropriate. 32 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |34 | This document is a preliminary draft of a specification for the 35 | Selection API and selection related functionality. It replaces a couple 36 | of old sections of the HTML 37 | specification, the selection part of the old 39 | DOM Range specification. 40 |
41 |42 | This document defines APIs for selection, which allows users and 43 | authors to select a portion of a document or specify a point of 44 | interest for copy, paste, and other editing operations. 45 |
46 |49 | This is work in progress. 50 |
51 |57 | IE9 and Firefox 6.0a2 allow arbitrary ranges in the selection, which 58 | follows what this spec originally said. However, this leads to 59 | unpleasant corner cases that authors, implementers, and spec writers 60 | all have to deal with, and they don't make any real sense. Chrome 14 61 | dev and Opera 11.11 aggressively normalize selections, like not letting 62 | them lie inside empty elements and things like that, but this is also 63 | viewed as a bad idea, because it takes flexibility away from authors. 64 |
65 |66 | So I changed the spec to a made-up compromise that allows some 67 | simplification but doesn't constrain authors much. See 69 | discussion. Basically it would throw exceptions in some places to 70 | try to stop the selection from containing a range that had a 71 | boundary point other than an Element or Text node, or a boundary 72 | point that didn't descend from a Document. 73 |
74 |75 | But this meant getRangeAt() had to start returning a copy, not a 76 | reference. Also, it would be prone to things failing weirdly in corner 77 | cases. Perhaps most significantly, all sorts of problems might arise 78 | when DOM mutations transpire, like if a boundary point's node is 79 | removed from its parent and the mutation rules would place the new 80 | boundary point inside a non-Text/Element node. And finally, the 81 | previously-specified behavior had the advantage of matching two major 82 | implementations, while the new behavior matched no one. So I changed it 83 | back. 84 |
85 |87 | See bug 15470. 89 | IE9, Firefox 12.0a1, Chrome 17 dev, and Opera Next 12.00 alpha all 90 | make the range initially null. 91 |
92 |99 | Every document with a [=Document/browsing context=] has a unique 100 | selection associated with it. 101 |
102 |103 | This is a requirement of the HTML spec. IE9 and Opera Next 12.00 alpha 104 | seem to follow it, while Firefox 12.0a1 and Chrome 17 dev seem not to. 105 | See Mozilla bug, 107 | WebKit bug. 108 |
109 |110 | This one selection must be shared by all the content of the 111 | document (though not by nested documents), including any 112 | [=editing hosts=] in the document. 113 |
114 |115 | Each selection can be associated with a single range. 116 | When there is no range associated with the selection, the 117 | selection is empty. The selection must be initially 118 | empty. 119 |
120 |
121 | A document's selection is a singleton object associated
122 | with that document, so it gets replaced with a new object when
123 | Document.open() is called. See bug 15470.
125 | IE9 and Opera Next 12.00 alpha allow the user to reset the range to
126 | null after the fact by clicking somewhere; Firefox 12.0a1 and Chrome 17
127 | dev do not. We follow Gecko/WebKit, because it lessens the chance of
128 | getRangeAt(0) throwing.
129 |
131 | Once a selection is associated with a given range, it 132 | must continue to be associated with that same range until this 133 | specification requires otherwise. 134 |
135 |136 | For instance, if the DOM changes in a way that changes the range's 137 | boundary points, or a script modifies the boundary points of the range, 138 | the same range object must continue to be associated with the 139 | selection. However, if the user changes the selection or a script calls 140 | {{addRange()}}, the selection must be associated with a new range 141 | object, as required elsewhere in this specification. 142 |
143 |144 | If the selection's range is not null and is 145 | [=range/collapsed=], then the caret position must be at that 146 | range's boundary point. When the selection is not 147 | [=range/collapsed=], this specification does not define the caret 148 | position; user agents should follow platform conventions in deciding 149 | whether the caret is at the start of the selection, the end of 150 | the selection, or somewhere else. 151 |
152 |153 | Each selection has a direction: forwards, 154 | backwards, or directionless. If the user creates 155 | a selection by indicating first one boundary point of the 156 | range and then the other (such as by clicking on one point and 157 | dragging to another), and the first indicated boundary point is 158 | [=boundary point/after=] the second, then the corresponding 159 | selection must initially be backwards. If the first 160 | indicated boundary point is [=boundary point/before=] the 161 | second, then the corresponding selection must initially be 162 | forwards. Otherwise, it must be directionless. 163 |
164 |165 | When the selection's range is mutated by scripts, e.g. 166 | via {{Range/selectNode(node)}}, direction of the 167 | selection must be preserved. 168 |
169 |170 | Each selections also have an anchor and a 171 | focus. If the selection's range is null, its 172 | anchor and focus are both null. If the selection's 173 | range is not null and its direction is forwards, 174 | its anchor is the range's [=range/start=], and its 175 | focus is the [=range/end=]. Otherwise, its focus is the 176 | [=range/start=] and its anchor is the [=range/end=]. 177 |
178 |179 | anchor and focus of selection need not to be in 180 | the [=document tree=]. It could be in a [=shadow tree=] of the same 181 | [=document=]. 182 |
183 |184 | Each document, input element, and textarea element 185 | has a boolean has scheduled selectionchange event, which is 186 | initially false. 187 |
188 |194 | Selection interface provides a way to interact with the 195 | selection associated with each document. 196 |
197 |
198 | [Exposed=Window]
199 | interface Selection {
200 | readonly attribute Node? anchorNode;
201 | readonly attribute unsigned long anchorOffset;
202 | readonly attribute Node? focusNode;
203 | readonly attribute unsigned long focusOffset;
204 | readonly attribute boolean isCollapsed;
205 | readonly attribute unsigned long rangeCount;
206 | readonly attribute DOMString type;
207 | readonly attribute DOMString direction;
208 | Range getRangeAt(unsigned long index);
209 | undefined addRange(Range range);
210 | undefined removeRange(Range range);
211 | undefined removeAllRanges();
212 | undefined empty();
213 | sequence<StaticRange> getComposedRanges(optional GetComposedRangesOptions options = {});
214 | undefined collapse(Node? node, optional unsigned long offset = 0);
215 | undefined setPosition(Node? node, optional unsigned long offset = 0);
216 | undefined collapseToStart();
217 | undefined collapseToEnd();
218 | undefined extend(Node node, optional unsigned long offset = 0);
219 | undefined setBaseAndExtent(Node anchorNode, unsigned long anchorOffset, Node focusNode, unsigned long focusOffset);
220 | undefined selectAllChildren(Node node);
221 | undefined modify(optional DOMString alter, optional DOMString direction, optional DOMString granularity);
222 | [CEReactions] undefined deleteFromDocument();
223 | boolean containsNode(Node node, optional boolean allowPartialContainment = false);
224 | stringifier;
225 | };
226 |
227 | dictionary GetComposedRangesOptions {
228 | sequence<ShadowRoot> shadowRoots = [];
229 | };
230 |
231 | 237 | The attribute must return the anchor [=boundary point/node=] 238 | of [=this=], or `null` if the anchor is null or 239 | anchor is not in the [=document tree=]. 240 |
241 |
247 | The attribute must return the anchor [=boundary
248 | point/offset=] of [=this=], or 0 if the anchor
249 | is null or anchor is not in the [=document tree=].
250 |
257 | The attribute must return the focus [=boundary point/node=] 258 | of [=this=], or `null` if the focus is null or focus 259 | is not in the [=document tree=]. 260 |
261 |
267 | The attribute must return the focus [=boundary
268 | point/offset=] of [=this=], or 0 if the focus
269 | is null or focus is not in the [=document tree=].
270 |
277 | The attribute must return true if and only if the 278 | anchor and focus are the same (including 279 | if both are null). Otherwise it must return false. 280 |
281 |
287 | The attribute must return 0 if [=this=] is
288 | empty or either focus or anchor is not in the
289 | [=document tree=], and must return 1 otherwise.
290 |
297 | The attribute must return `"None"` if [=this=] is empty or 298 | either focus or anchor is not in the [=document 299 | tree=], `"Caret"` if [=this=]'s range is 300 | [=range/collapsed=], and `"Range"` otherwise. 301 |
302 |308 | The attribute must return `"none"` if [=this=] is empty or 309 | this selection is directionless. `"forward"` if this 310 | selection's direction is forwards and `"backward"` if this 311 | selection's direction is backwards. 312 |
313 |
319 | The method must throw an {{IndexSizeError}} exception if
320 | index is not 0, or if [=this=] is
321 | empty or either focus or anchor is not in the
322 | [=document tree=]. Otherwise, it must return a reference to (not a
323 | copy of) [=this=]'s range.
324 |
326 | Thus subsequent calls of this method returns the same range
327 | object if nothing has removed [=this=]'s range in the meantime. In
328 | particular, getSelection().getRangeAt(0) ===
329 | getSelection().getRangeAt(0) evaluates to true
330 | if the selection is not empty.
331 |
338 | The method must follow these steps: 339 |
340 |rangeCount is not 0, abort these
346 | steps.
347 |
353 | Since range is added by reference, subsequent calls to
354 | getRangeAt(0) returns the same object, and any changes
355 | that a script makes to range after it is added must be
356 | reflected in the selection, until something else removes or
357 | replaces [=this=]'s range. In particular, the
358 | selection will contain b as opposed to
359 | a after running the following code: var r =
360 | document.createRange(); r.selectNode(a);
361 | getSelection().addRange(r); r.selectNode(b);
362 |
365 | At Step 2, Chrome 58 and Edge 25 do nothing. Firefox 51 gives you 366 | a multi-range selection. At least they keep the exisiting 367 | range. 368 |
369 |370 | At Step 3, Chrome 58 and Firefox 51 store a reference, as 371 | described here. Edge 25 stores a copy. Firefox 51 changes its 372 | selection if the range is modified. 373 |
374 |381 | The method must make [=this=] empty by disassociating its 382 | range if [=this=]'s range is range. 383 | Otherwise, it must throw a {{NotFoundError}}. 384 |
385 |391 | The method must make [=this=] empty by disassociating its 392 | range if [=this=] has an associated range. 393 |
394 |
400 | The method must be an alias, and behave identically, to
401 | removeAllRanges().
402 |
462 | The method must follow these steps: 463 |
464 |removeAllRanges() and abort these steps.
467 |
494 | The method must be an alias, and behave identically, to
495 | collapse().
496 |
503 | The method must throw {{InvalidStateError}} exception if the 504 | [=this=] is empty. Otherwise, it must create a new 505 | range, [=Range/set the start=] both its [=range/start=] and 506 | [=range/end=] to the [=range/start=] of [=this=]'s range, 507 | and then set [=this=]'s range to the newly-created 508 | range. 509 |
510 |511 | For collapseToStart/End, IE9 mutates the existing range, while 512 | Firefox 9.0a2 and Chrome 15 dev replace it with a new one. The spec 513 | follows the majority and replaces it with a new one, leaving the 514 | old Range object unchanged. 515 |
516 |522 | The method must throw {{InvalidStateError}} exception if the 523 | [=this=] is empty. Otherwise, it must create a new 524 | range, [=Range/set the start=] both its [=range/start=] and 525 | [=range/end=] to the [=range/end=] of [=this=]'s range, and 526 | then set [=this=]'s range to the newly-created range. 527 |
528 |534 | The method must follow these steps: 535 |
536 |573 | Reverse-engineered circa January 2011. IE doesn't support it, so 574 | I'm relying on Firefox (implemented extend() sometime before 2000) 575 | and WebKit (implemented extend() in 2007). I'm mostly ignoring 576 | Opera, because gsnedders tells me its implementation isn't 577 | compatible. Firefox 12.0a1 seems to mutate the existing range. IE9 578 | doesn't support extend(), and it's impossible to tell whether 579 | Chrome 17 dev or Opera Next 12.00 alpha mutate or replace, because 580 | getRangeAt() returns a copy anyway. Nevertheless, I go against 581 | Gecko here, to be consistent with collapse(). 582 |
583 |589 | The method must follow these steps: 590 |
591 |628 | The method must follow these steps: 629 |
630 |0).
643 | 654 | Based mostly on Firefox 9.0a2. It has a bug that I didn't 655 | reproduce, namely that if you pass a Document as the argument, 656 | the end offset becomes 1 instead of the number of children it 657 | has. It also throws a RangeException instead of DOMException, 658 | because its implementation predated their merging. 659 |
660 |661 | IE9 behaves similarly but with glitches. It throws "Unspecified 662 | error." if the node is detached or display:none, and apparently 663 | in some random other cases too. It throws "Invalid argument." for 664 | detached comments (only!). Finally, if you pass it a comment, it 665 | seems to select the whole comment, unlike with text nodes. 666 |
667 |668 | Chrome 16 dev behaves as you'd expect given its Selection 669 | implementation. It refuses to select anything that's not visible, 670 | so it's almost always wrong. Opera 11.50 just does nothing in all 671 | my tests, as usual. 672 |
673 |674 | The new range replaces any existing one, doesn't mutate it. This 675 | matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 676 | 12.00 alpha can't be tested, because getRangeAt() returns a copy 677 | anyway.) 678 |
679 |686 | The method must follow these steps: 687 |
688 |735 | We need to more precisely define what it means to extend or move 736 | selection by each granularity. 737 |
738 |744 | The method must invoke {{Range/deleteContents()}} on [=this=]'s 745 | range if [=this=] is not empty and both focus 746 | and anchor are in the [=document tree=]. Otherwise the 747 | method must do nothing. 748 |
749 |750 | This is the one method that actually mutates the range instead of 751 | replacing it. This matches IE9 and Firefox 12.0a1. (Chrome 17 dev 752 | and Opera Next 12.00 alpha can't be tested, because getRangeAt() 753 | returns a copy anyway.) 754 |
755 |
761 | The method must return false if [=this=] is
762 | empty or if node's [=tree/root=] is not the
763 | document associated with [=this=].
764 |
766 | Otherwise, if allowPartialContainment is
767 | false, the method must return true if and
768 | only if [=range/start=] of its range is [=boundary
769 | point/before=] or visually equivalent to the first boundary
770 | point in the node and [=range/end=]
771 | of its range is [=boundary point/after=] or visually
772 | equivalent to the last boundary point in the
773 | node.
774 |
776 | If allowPartialContainment is true, the
777 | method must return true if and only if [=range/start=]
778 | of its range is [=boundary point/before=] or visually
779 | equivalent to the last boundary point in the node
780 | and [=range/end=] of its range is
781 | [=boundary point/after=] or visually equivalent to the first
782 | boundary point in the node.
783 |
790 | The stringification must return the string, which is the 791 | concatenation of the rendered text if there is a [=range=] 792 | associated with [=this=]. 793 |
794 |795 | If the selection is within a textarea or input 796 | element, it must return the selected substring in its value. 797 |
798 |801 | See also 803 | nsISelection.idl from Gecko. This spec doesn't have everything from 804 | there yet, in particular selectionLanguageChange() and containsNode() 805 | are missing. They are missing because I couldn't work out how to define 806 | them in terms of Ranges. 807 |
808 |810 | Originally, the Selection interface was a Netscape feature. The 811 | original implementation was carried on into Gecko (Firefox), and the 812 | feature was later implemented independently by other browser engines. 813 | The Netscape implementation always allowed multiple ranges in a 814 | single selection, for instance so the user could select a column of a 815 | table However, multi-range selections proved to be an unpleasant 816 | corner case that web developers didn't know about and even Gecko 817 | developers rarely handled correctly. Other browser engines never 818 | implemented the feature, and clamped selections to a single range in 819 | various incompatible fashions. 820 |
821 |
822 | This specification follows non-Gecko engines in restricting
823 | selections to at most one range, but the API was still originally
824 | designed for selections with arbitrary numbers of ranges. This
825 | explains oddities like the coexistence of removeRange()
826 | and removeAllRanges(), and a getRangeAt()
827 | method that takes an integer argument that must always be zero.
828 |
831 | All of the members of the {{Selection}} interface are defined in terms
832 | of operations on the range object (if any)
833 | represented by the object. These operations can raise exceptions, as
834 | defined for the {{Range}} interface; this can therefore result in the
835 | members of the Selection interface raising exceptions as well,
836 | in addition to any explicitly called out above.
837 |
844 | This specification extends several interfaces to provide entry points 845 | to the interfaces defined in this specification. 846 |
847 |Document interface
850 |
852 | The Document
853 | interface is defined in [[HTML]].
854 |
856 | partial interface Document {
857 | Selection? getSelection();
858 | };
859 |
860 | 866 | The method must return the selection associated with 867 | [=this=] if [=this=] has an associated [=Document/browsing 868 | context=], and it must return `null` otherwise. 869 |
870 |
878 | The Window interface is
880 | defined in [[HTML]].
881 |
883 | partial interface Window {
884 | Selection? getSelection();
885 | };
886 |
887 | 893 | The method must invoke and return the result of 894 | {{Document/getSelection()}} on [=this=]'s {{Window.document}} 895 | attribute. 896 |
897 |
905 | The GlobalEventHandlers
907 | interface is defined in [[HTML]].
908 |
910 | partial interface mixin GlobalEventHandlers {
911 | attribute EventHandler onselectstart;
912 | attribute EventHandler onselectionchange;
913 | };
914 |
915 | 921 | The attribute must be an event handler IDL attribute for 922 | the selectstart event supported by all HTML 923 | elements, {{Document}} objects, and {{Window}} objects. 924 |
925 |931 | The attribute must be an event handler IDL attribute for 932 | the selectionchange event supported by all HTML 933 | elements, {{Document}} objects, and {{Window}} objects. 934 |
935 |944 | When the user agent is to [=replace data=] or [=CharacterData/substring 945 | data=] on {{CharacterData}}, the user agent must update the 946 | range associated with selection of the [=Node/node 947 | document=] of the {{CharacterData}} as if it's a live range. 948 |
949 |950 | When the user agent is to split a {{Text}} [=node=], the user agent 951 | must update the range associated with selection of the 952 | [=Node/node document=] of the {{Text}} as if it's a live range. 953 |
954 |
955 | When the user agent is to run steps for normalize()
956 | method, the user agent must update the range associated with
957 | selection of the [=Node/node document=] of [=this=] as if it's a
958 | live range.
959 |
961 | When the user agent is to [=remove=] or [=insert=] a [=node=], the user 962 | agent must update the range associated with selection of 963 | the [=Node/node document=] of the [=node=] as if it's a live 964 | range. 965 |
966 |972 | The user agent should allow the user to change the selection 973 | associated with the [=navigable/active document=]. If the user makes 974 | any modification to a selection, the user agent must create a 975 | new range with suitable [=range/start=] and [=range/end=] of the 976 | range and associate the selection with this new 977 | range (not modify the existing range), and set update 978 | selection's direction to forwards if the 979 | [=range/start=] is [=boundary point/before=] or equal to the 980 | [=range/end=], backwards if if the [=range/end=] is [=boundary 981 | point/before=] the [=range/start=], or directionless if the 982 | [=range/start=] and the [=range/end=] cannot be ordered due to the 983 | platform convention. 984 |
985 |986 | The user agent must not make a selection empty if it was 987 | not already empty in response to any user actions (e.g. clicking 988 | on a non-editable region). 989 |
990 |991 | See bug 992 | 15470. IE9 and Opera Next 12.00 alpha allow the user to reset the 993 | range to null after the fact by clicking somewhere; Firefox 12.0a1 and 994 | Chrome 17 dev do not. I follow Gecko/WebKit, because it lessens the 995 | chance of getRangeAt(0) throwing. 996 |
997 |selectstart event
1000 |
1002 | When the user agent is about to associate a new range
1003 | newRange to the selection in response to a user
1004 | initiated action, the user agent must fire an event named
1005 | selectstart, which bubbles and is cancelable, at the
1006 | [=boundary point/node=] associated with the boundary point of
1007 | newRange's [=range/start=] prior to changing the selection
1008 | if the selection was previously empty or the previously
1009 | associated range was [=range/collapsed=].
1010 |
1012 | If the event is canceled, the user agent must not change the 1013 | selection. 1014 |
1015 |1016 | The user agent must not fire an event when the user agent sets 1017 | the selection empty. 1018 |
1019 |selectionchange event
1023 | 1025 | When the selection is dissociated with its range, 1026 | associated with a new range, or the associated range's 1027 | boundary point is mutated either by the user or the content 1028 | script, the user agent must schedule a selectionchange event 1029 | on document. 1030 |
1031 |1032 | When an [^input^] or [^textarea^] element provide a text selection 1033 | and its selection changes (in either extent or [=direction=]), the 1034 | user agent must schedule a selectionchange event on the 1035 | element. 1036 |
1037 |selectionchange event
1040 | 1042 | To schedule a selectionchange event on a node 1043 | target, run these steps: 1044 |
1045 |selectionchange event
1058 | 1060 | To fire a selectionchange event on a node 1061 | target, run these steps: 1062 |
1063 |selectionchange, which bubbles and not cancelable, at
1069 | target.
1070 | selectionchange, which does not bubble
1073 | and not cancelable, at target.
1074 | 1081 | This specification defines conformance criteria that apply to a single 1082 | product: the user agent that implements the interfaces that it 1083 | contains. 1084 |
1085 |1091 | There are no known security considerations for this standard. 1092 |
1093 |1094 | To mitigate potential privacy risks of exposing user's use of assistive 1095 | technologies, for example, user agent may elect to emulate mouse 1096 | and keyboard events typically associated with selectstart or 1097 | selectionchange events when the user opts to modify the 1098 | selection of a document. 1099 |
1100 |1106 | Many thanks to 1107 |
1108 |
394 |
395 |
396 |
397 |
398 |
399 |
474 | Copyright © 475 | 2014 476 | 477 | W3C® 478 | (MIT, 479 | ERCIM, 480 | Keio, Beihang), 481 | 482 | All Rights Reserved. 483 | 484 | W3C liability, 485 | trademark and 486 | 487 | document use 488 | 489 | rules apply. 490 |
491 | 492 | 493 |497 | This document is a preliminary draft of a specification for the Selection API and selection related functionality. 498 | It replaces a couple of old sections of the HTML specification, 499 | the selection part of the old DOM Range specification. 500 |
501 |502 |
503 |508 | This section describes the status of this document at the time of its publication. 509 | Other documents may supersede this document. A list of current W3C publications and the 510 | latest revision of this technical report can be found in the W3C technical reports index at 511 | http://www.w3.org/TR/. 512 |
513 | 514 |Since this specification is intended to be charted by the Web Applications Working Group, 515 | any feedback or discussion of this specification should be posted to 516 | public-webapps mailing list 517 | with "[Selection API]" in the subject.
518 | 519 |520 | This specification is based on the HTML Editing API specification 521 | edited by Aryeh Gregor and published by the W3C Editing APIs Community Group. 522 | Copyright © 2011-2014 the Contributors to the HTML Editing APIs Specification, 523 | published by the W3C Editing APIs Community Group under the 524 | W3C Community Contributor License Agreement (CLA). 525 |
526 | 527 |528 | This document was published by the Web Applications Working Group as a First Public Working Draft. 529 | 530 | This document is intended to become a W3C Recommendation. 531 | 532 | 533 | If you wish to make comments regarding this document, please send them to 534 | public-webapps@w3.org 535 | (subscribe, 536 | archives). 537 | 538 | 539 | 540 | 541 | All comments are welcome. 542 | 543 |
544 | 545 | 546 |547 | Publication as a First Public Working Draft does not imply endorsement by the W3C 548 | Membership. This is a draft document and may be updated, replaced or obsoleted by other 549 | documents at any time. It is inappropriate to cite this document as other than work in 550 | progress. 551 |
552 | 553 | 554 | 555 |556 | 557 | This document was produced by a group operating under the 558 | 5 February 2004 W3C Patent 559 | Policy. 560 | 561 | 562 | 563 | 564 | W3C maintains a public list of any patent 565 | disclosures 566 | 567 | made in connection with the deliverables of the group; that page also includes 568 | instructions for disclosing a patent. An individual who has actual knowledge of a patent 569 | which the individual believes contains 570 | Essential 571 | Claim(s) must disclose the information in accordance with 572 | section 573 | 6 of the W3C Patent Policy. 574 | 575 | 576 |
577 | 578 |This document is governed by the 14 October 2005W3C Process Document. 579 |
580 | 581 | 582 | 583 | 584 | 585 |This section is non-normative.
591 | 592 |IE9 and Firefox 6.0a2 allow arbitrary ranges in the selection, which follows what this spec originally said. 593 | However, this leads to unpleasant corner cases that authors, implementers, and spec writers all have to deal with, 594 | and they don't make any real sense. Chrome 14 dev and Opera 11.11 aggressively normalize selections, 595 | like not letting them lie inside empty elements and things like that, but this is also viewed as a bad idea, 596 | because it takes flexibility away from authors.
597 | 598 |So I changed the spec to a made-up compromise that allows some simplification but doesn't constrain authors much. 599 | See discussion. 600 | Basically it would throw exceptions in some places to try to stop the selection from containing a range that had 601 | a boundary point other than an Element or Text node, or a boundary point that didn't descend from a Document.
602 | 603 |But this meant getRangeAt() had to start returning a copy, not a reference. 604 | Also, it would be prone to things failing weirdly in corner cases. Perhaps most significantly, all sorts of problems 605 | might arise when DOM mutations transpire, like if a boundary point's node is removed from its parent and 606 | the mutation rules would place the new boundary point inside a non-Text/Element node. 607 | And finally, the previously-specified behavior had the advantage of matching two major implementations, 608 | while the new behavior matched no one. So I changed it back.
609 | 610 |See bug 15470. IE9, Firefox 12.0a1, Chrome 17 dev, 612 | and Opera Next 12.00 alpha all make the range initially null.
613 |Every document ([DOM4]) with
620 | a browsing context ([HTML5])
621 | has a unique Selection object associated with it.
622 | Selection objects are known as selections.
This is a requirement of the HTML spec. 625 | IE9 and Opera Next 12.00 alpha seem to follow it, while Firefox 12.0a1 and Chrome 17 dev seem not to. 626 | See Mozilla bug, 627 | WebKit bug.
This one selection must be shared by all the content of the document 630 | (though not by nested documents), including any editing hosts in the document. 631 | Editing hosts (defined in [HTML5]) that are not 632 | inside a document cannot have a selection
633 | 634 |Each selection can be associated with a single range (defined in [DOM4]). 635 | When there is no range associated with the selection, the selection is empty. 636 | The selection must be initially empty.
637 | 638 |A document's selection is a singleton object associated with that document,
639 | so it gets replaced with a new object when Document.open() is called.
640 | See bug 15470.
641 | IE9 and Opera Next 12.00 alpha allow the user to reset the range to null after the fact by clicking somewhere;
642 | Firefox 12.0a1 and Chrome 17 dev do not.
643 | We follow Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.
Once a selection is associated with a given range, 646 | it must continue to be associated with that same range until this specification requires otherwise.
647 | 648 |For instance, if the DOM changes in a way that changes the range's boundary points,
649 | or a script modifies the boundary points of the range, the same range object must continue to be associated with the selection.
650 | However, if the user changes the selection or a script calls addRange(),
651 | the selection must be associated with a new range object, as required elsewhere in this specification.
If the selection's range is not null and is 654 | collapsed ([DOM4]), 655 | then the caret position must be at that range's boundary point. 656 | 657 | When the selection is not empty, this specification does not define the caret position; 658 | user agents should follow platform conventions in deciding whether the caret is at the start of the selection, 659 | the end of the selection, or somewhere else. 660 | 661 |
This short-changes Mac users. See bug 13909. 662 | 663 |
Each selection has a direction, forwards, backwards, or directionless. 664 | If the user creates a selection by indicating first one boundary point of the range 665 | and then the other (such as by clicking on one point and dragging to another), 666 | and the first indicated boundary point is after ([DOM4]) the second, 667 | then the corresponding selection must initially be backwards. 668 | If the first indicated boundary point is before ([DOM4]) the second, 669 | then the corresponding selection must initially be forwards. 670 | Otherwise, it must be directionless.
671 | 672 |Selections also have an anchor and a focus.
673 | If the selection's range is null, its anchor and focus are both null.
674 | If the selection's range is not null and its direction is forwards, its anchor is the range's
675 | start, and its focus is the end.
676 | Otherwise, its focus is the start and its anchor is the end.
interface Selection {
679 | readonly attribute Node? anchorNode;
680 | readonly attribute unsigned long anchorOffset;
681 | readonly attribute Node? focusNode;
682 | readonly attribute unsigned long focusOffset;
683 | readonly attribute boolean isCollapsed;
684 | readonly attribute unsigned long rangeCount;
685 | Range getRangeAt (unsigned long index);
686 | void addRange (Range range);
687 | void removeRange (Range range);
688 | void removeAllRanges ();
689 | void collapse (Node node, unsigned long offset);
690 | void collapseToStart ();
691 | void collapseToEnd ();
692 | void extend (Node node, unsigned long offset);
693 | void setBaseAndExtent (Node anchorNode, unsigned long anchorOffset, Node focusNode, unsigned long focusOffset);
694 | void selectAllChildren (Node node);
695 | void deleteFromDocument ();
696 | boolean containsNode (Node node, boolean allowPartialContainment);
697 | stringifier DOMString ();
698 | };anchorNode of type Node, readonly , nullableThe attribute must return the anchor node ([DOM4])
700 | of the context object ([DOM4]),
701 | or null if the anchor is null.
anchorOffset of type unsigned long, readonly The attribute must return the anchor offset ([DOM4])
704 | of the context object, or 0 if the anchor is null.
focusNode of type Node, readonly , nullableThe attribute must return the focus node of the context object,
707 | or null if the anchor is null.
focusOffset of type unsigned long, readonly The attribute must return the focus offset of the context object,
710 | or 0 if the focus is null.
isCollapsed of type boolean, readonly The attribute must return true if and only if the anchor and focus are the same (including if both are null). 713 | Otherwise it must return false.
714 |rangeCount of type unsigned long, readonly The attribute must return 0 if the context object's range is empty,
716 | and must return 1 otherwise.
DOMStringstringifieraddRangeThe method must set the context object's range to range by a strong reference (not by making a copy) 721 | if the root ([DOM4]) 722 | of the range's boundary points are the document associated with context object. 723 | Otherwise, this method must do nothing.
724 | 725 |Since range is added by reference, subsequent calls to getRangeAt(0) returns the same object,
726 | and any changes that a script makes to range after it is added must be reflected in the selection,
727 | until something else removes or replaces the context object's range.
728 | In particular, the selection will contain b as opposed to a after running the following code:
729 | var r = document.createRange(); r.selectNode(a); getSelection().addRange(r); r.selectNode(b);
IE9 and Firefox 4.0 store a reference, as described here. 733 | Chrome 12 dev and Opera 11.10 appear to store a copy, so changes don't affect the selection.
734 | 735 |Chrome 15 dev seems to ignore addRange() if there's already a range. 736 | IE9 replaces the existing range. 737 | Firefox 9.0a2, of course, just gives you a multi-range selection. 738 | IE is likely to behave closest to Firefox, and is also more useful than silent failure, so the spec goes with that.
739 || Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| range | Range | ✘ | ✘ |
voidcollapseThe method must follow these steps:
742 |IndexSizeError exception if if offset is negative or longer than node's
744 | length ([DOM4]) and abort these steps.| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ | |
| offset | unsigned long | ✘ | ✘ |
voidcollapseToEndThe method must throw InvalidStateError exception if the context object is empty.
753 | Otherwise, it must create a new range, set both its start and end
754 | to the end of the context object's range,
755 | and then set the context object's range to the newly-created range.
voidcollapseToStartThe method must throw InvalidStateError ([DOM4]) exception
758 | if the context object is empty.
759 | Otherwise, it must create a new range, set both its start and end
760 | to the start of the context object's range,
761 | and then set the context object's range to the newly-created range.
For collapseToStart/End, IE9 mutates the existing range, while Firefox 9.0a2 and Chrome 15 dev replace it with a new one. 764 | The spec follows the majority and replaces it with a new one, leaving the old Range object unchanged.
voidcontainsNodeThe method must return false if the context object is empty
767 | or if node's root is not the document associated with the context object.
Otherwise, if allowPartialContainment is false,
770 | the method must return true if and only if
771 | start of its range is before or visually equivalent to
772 | the first boundary point in the node
773 | and end of its range is after or visually equivalent to
774 | the last boundary point in the node.
If allowPartialContainment is true,
777 | the method must return true if and only if
778 | start of its range is before or visually equivalent to
779 | the first boundary point in the node
780 | or end of its range is after or visually equivalent to
781 | the last boundary point in the node.
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ | |
| allowPartialContainment | boolean | ✘ | ✘ |
booleandeleteFromDocumentThe method must invoke deleteContents() ([DOM4])
785 | on the context object's range if the context object is not empty.
786 | Otherwise the method must do nothing.
This is the one method that actually mutates the range instead of replacing it. 789 | This matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 12.00 alpha can't be tested, 790 | because getRangeAt() returns a copy anyway.)
voidextendThe method must follow these steps:
794 |InvalidStateError exception and abort these steps.Reverse-engineered circa January 2011. 813 | IE doesn't support it, so I'm relying on Firefox (implemented extend() sometime before 2000) and WebKit (implemented extend() in 2007). 814 | I'm mostly ignoring Opera, because gsnedders tells me its implementation isn't compatible. 815 | 816 | Firefox 12.0a1 seems to mutate the existing range. 817 | IE9 doesn't support extend(), and it's impossible to tell whether Chrome 17 dev or Opera Next 12.00 alpha mutate or replace, 818 | because getRangeAt() returns a copy anyway. 819 | Nevertheless, I go against Gecko here, to be consistent with collapse().
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ | |
| offset | unsigned long | ✘ | ✘ |
voidgetRangeAtThe method must throw an IndexSizeError ([DOM4]) exception
822 | if index is not 0, or if the context object is empty.
823 | Otherwise, it must return a reference to (not a copy of) the context object's range.
Thus subsequent calls of this method returns the same range object
826 | if nothing has removed the context object's range in the meantime.
827 | In particular, getSelection().getRangeAt(0) === getSelection().getRangeAt(0) evaluates to true
828 | if the selection is not empty.
IE9 and Firefox 4.0 return the same object every time, as the spec says. 831 | Chrome 12 dev and Opera 11.10 return a different object every time.
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| index | unsigned long | ✘ | ✘ |
RangeremoveAllRangesThe method must make the context object empty by disassociating its range 834 | if the context object's range is range. 835 | Otherwise, it must do nothing.
836 |voidremoveRangeThe method must make the context object empty by disassociating its range 838 | if the context object's range is range. 839 | Otherwise, it must do nothing.
840 || Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| range | Range | ✘ | ✘ |
voidselectAllChildrenThe method must follow these steps:
842 |0).Based mostly on Firefox 9.0a2. It has a bug that I didn't reproduce, namely 853 | that if you pass a Document as the argument, the end offset becomes 1 instead 854 | of the number of children it has. It also throws a RangeException instead of 855 | DOMException, because its implementation predated their merging. 856 | 857 |
IE9 behaves similarly but with glitches. It throws "Unspecified error." if 858 | the node is detached or display:none, and apparently in some random other cases 859 | too. It throws "Invalid argument." for detached comments (only!). Finally, if 860 | you pass it a comment, it seems to select the whole comment, unlike with text 861 | nodes. 862 | 863 |
Chrome 16 dev behaves as you'd expect given its Selection implementation. 864 | It refuses to select anything that's not visible, so it's almost always wrong. 865 | Opera 11.50 just does nothing in all my tests, as usual. 866 | 867 |
The new range replaces any existing one, doesn't mutate it. 868 | This matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 12.00 869 | alpha can't be tested, because getRangeAt() returns a copy anyway.) 870 |
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ |
voidsetBaseAndExtentThe method must follow these steps:
873 |IndexSizeError exception and abort these steps.| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| anchorNode | Node | ✘ | ✘ | |
| anchorOffset | unsigned long | ✘ | ✘ | |
| focusNode | Node | ✘ | ✘ | |
| focusOffset | unsigned long | ✘ | ✘ |
voidSee also nsISelection.idl from Gecko. 892 | This spec doesn't have everything from there yet, in particular selectionLanguageChange() and containsNode() are missing. 893 | They are missing because I couldn't work out how to define them in terms of Ranges.
Originally, the Selection interface was a Netscape feature. 897 | The original implementation was carried on into Gecko (Firefox), and the feature was later implemented independently by other browser engines. 898 | The Netscape implementation always allowed multiple ranges in a single selection, for instance so the user could select a column of a table 899 | However, multi-range selections proved to be an unpleasant corner case 900 | that web developers didn't know about and even Gecko developers rarely handled correctly. 901 | Other browser engines never implemented the feature, and clamped selections to a single range in various incompatible fashions.
902 | 903 |This specification follows non-Gecko engines in restricting selections to at most one range,
904 | but the API was still originally designed for selections with arbitrary numbers of ranges.
905 | This explains oddities like the coexistence of removeRange() and removeAllRanges(),
906 | and a getRangeAt() method that takes an integer argument that must always be zero.
All of the members of the Selection interface are defined
910 | in terms of operations on the range object (if any) represented by the object.
911 | These operations can raise exceptions, as defined for the Range ([DOM4]) interface;
912 | this can therefore result in the members of the Selection interface raising exceptions as well,
913 | in addition to any explicitly called out below.
This specification extends several interfaces to provide entry points to the 920 | interfaces defined in this specification.
921 | 922 |Document interfacepartial interface Document {
925 | Selection? getSelection ();
926 | };getSelectionThe method must return the selection associated with context object
928 | if the context object has an associated browsing context,
929 | and it must return null otherwise.
Selection, nullable
932 | If we create a Document object with no browsing context
933 | (say via document.implementation.createHTMLDocument("") and call getSelection() on it),
934 | IE9 seems to return a different Selection object.
935 | Firefox 12.0a1 and Opera Next 12.00 alpha return the same object as for the current window.
936 | Chrome 17 dev returns null.
937 | See discussion.
938 | There's no meaningful selection associated with such a document, so we follow WebKit and require returning null.
Window interfacepartial interface Window {
944 | Selection? getSelection ();
945 | };getSelectionThe method must invoke and return the result of getSelection() on the context object's
947 | document ([HTML5]) property.
Selection, nullableThe user agent should allow the user to change the selection associated with the active document 957 | (defined in [HTML5]). 958 | If the user makes any modification to a selection, the user agent must create a new range with suitable 959 | start and 960 | end of the range ([DOM4]) 961 | and associate the selection with this new range (not modify the existing range), 962 | and set update selection's direction to forwards if the start is before or equal to the end, 963 | backwards if if the end is before the start, 964 | or directionless if the start and the end cannot be ordered due to the platform convention.
965 | 966 |The user agent must not make a selection empty if it was not already empty 967 | in response to any user actions (e.g. clicking on a non-editable region).
968 | 969 |See bug 15470. 970 | IE9 and Opera Next 12.00 alpha allow the user to reset the range to null after the fact by clicking somewhere; 971 | Firefox 12.0a1 and Chrome 17 dev do not. 972 | I follow Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.
selectstart eventWhen the user agent is about to associate a new range newRange to the selection in response to a user initiated action,
978 | the user agent must fire ([DOM4])
979 | an event with the name selectstart, which bubbles and is cancelable,
980 | at the node associated with the boundary point of newRange's start
981 | prior to changing the selection.
If the event is canceled, the user agent must not change the selection.
984 | 985 |The user agent must not fire the event when the user agent sets the selection empty.
986 |selectionchange eventWhen the selection is changed either by the user or the content script,
992 | the user agent must queue a task ([HTML5])
993 | to fire an event with the name selectionchange, which does not bubble and is not cancelable,
994 | at the document associated with the selection.
Many thanks to
1002 |Aryeh Gregor, who is the original author of this specification as well as HTML Editing API specification.
Contributors to the HTML Editing API specification - 1005 | Ehsan Akhgari, Tab Atkins, Mathias Bynens, Tim Down, Markus Ernst, Daniel Glazman, Tali Gregor (née Fuss), 1006 | Stig Halvorsen, Jeff Harris, Ian Hickson, Cameron Heavon-Jones, Anne van Kesteren, Alfonso Martínez de Lizarrondo, 1007 | Glenn Maynard, Ms2ger, Robert O'Callahan, Julie Parent, Simon Pieters, Michael A. Puls II, 1008 | Rich Schwerdtfeger, Jonas Sicking, Henri Sivonen, Smylers, Hallvord R. M. Steen, Roland Steiner, Annie Sullivan, 1009 | timeless, Ojan Vafai, Brett Zamir, and Boris Zbarsky for their feedback, participation, or other helpful contributions
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
558 | Copyright © 559 | 2015 560 | 561 | W3C® 562 | (MIT, 563 | ERCIM, 564 | Keio, Beihang). 565 | 566 | W3C liability, 567 | trademark and 568 | 569 | document use 570 | 571 | rules apply. 572 |
573 | 574 | 575 |579 | This document is a preliminary draft of a specification for the Selection API and selection related functionality. 580 | It replaces a couple of old sections of the HTML specification, 581 | the selection part of the old DOM Range specification. 582 |
583 |584 | This document defines APIs for selection, which allows users and authors to select a portion of a document or specify a point of interest for copy, paste, and other editing operations. 585 |
586 |591 | This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/. 592 |
593 | 594 | 595 | 596 |This document was published by the Web Applications Working Group, 597 | any feedback or discussion of this specification should be posted to 598 | public-webapps mailing list 599 | with "[selection-api]" in the subject (archive). 600 |
601 | 602 |603 | This specification is based on the HTML Editing API specification 604 | edited by Aryeh Gregor and published by the W3C Editing APIs Community Group. 605 | Copyright © 2011-2014 the Contributors to the HTML Editing APIs Specification, 606 | published by the W3C Editing APIs Community Group under the 607 | W3C Community Contributor License Agreement (CLA). 608 |
609 | 610 | 611 |612 | This document was published by the Web Applications Working Group as a Working Draft. 613 | 614 | This document is intended to become a W3C Recommendation. 615 | 616 | 617 | If you wish to make comments regarding this document, please send them to 618 | public-webapps@w3.org 619 | (subscribe, 620 | archives). 621 | 622 | 623 | 624 | 625 | 626 | 627 | All comments are welcome. 628 | 629 | 630 |
631 | 632 | 633 | 634 |635 | Publication as a Working Draft does not imply endorsement by the W3C 636 | Membership. This is a draft document and may be updated, replaced or obsoleted by other 637 | documents at any time. It is inappropriate to cite this document as other than work in 638 | progress. 639 |
640 | 641 | 642 | 643 |644 | 645 | This document was produced by 646 | 647 | a group 648 | operating under the 649 | 5 February 2004 W3C Patent 650 | Policy. 651 | 652 | 653 | 654 | 655 | W3C maintains a public list of any patent 656 | disclosures 657 | 658 | made in connection with the deliverables of 659 | 660 | the group; that page also includes 661 | 662 | instructions for disclosing a patent. An individual who has actual knowledge of a patent 663 | which the individual believes contains 664 | Essential 665 | Claim(s) must disclose the information in accordance with 666 | section 667 | 6 of the W3C Patent Policy. 668 | 669 | 670 |
671 | 672 |This document is governed by the 1 September 2015 W3C Process Document. 673 |
674 | 675 | 676 | 677 | 678 | 679 | 680 |This section is non-normative.
686 | 687 |IE9 and Firefox 6.0a2 allow arbitrary ranges in the selection, which follows what this spec originally said. 688 | However, this leads to unpleasant corner cases that authors, implementers, and spec writers all have to deal with, 689 | and they don't make any real sense. Chrome 14 dev and Opera 11.11 aggressively normalize selections, 690 | like not letting them lie inside empty elements and things like that, but this is also viewed as a bad idea, 691 | because it takes flexibility away from authors.
692 | 693 |So I changed the spec to a made-up compromise that allows some simplification but doesn't constrain authors much. 694 | See discussion. 695 | Basically it would throw exceptions in some places to try to stop the selection from containing a range that had 696 | a boundary point other than an Element or Text node, or a boundary point that didn't descend from a Document.
697 | 698 |But this meant getRangeAt() had to start returning a copy, not a reference. 699 | Also, it would be prone to things failing weirdly in corner cases. Perhaps most significantly, all sorts of problems 700 | might arise when DOM mutations transpire, like if a boundary point's node is removed from its parent and 701 | the mutation rules would place the new boundary point inside a non-Text/Element node. 702 | And finally, the previously-specified behavior had the advantage of matching two major implementations, 703 | while the new behavior matched no one. So I changed it back.
704 | 705 |See bug 15470. IE9, Firefox 12.0a1, Chrome 17 dev, 707 | and Opera Next 12.00 alpha all make the range initially null.
708 |Every document ([DOM4]) with
715 | a browsing context ([HTML5])
716 | has a unique Selection object associated with it.
717 | Selection objects are known as selections.
This is a requirement of the HTML spec. 720 | IE9 and Opera Next 12.00 alpha seem to follow it, while Firefox 12.0a1 and Chrome 17 dev seem not to. 721 | See Mozilla bug, 722 | WebKit bug.
This one selection must be shared by all the content of the document 725 | (though not by nested documents), including any editing hosts in the document. 726 | Editing hosts (defined in [HTML5]) that are not 727 | inside a document cannot have a selection
728 | 729 |Each selection can be associated with a single range (defined in [DOM4]). 730 | When there is no range associated with the selection, the selection is empty. 731 | The selection must be initially empty.
732 | 733 |A document's selection is a singleton object associated with that document,
734 | so it gets replaced with a new object when Document.open() is called.
735 | See bug 15470.
736 | IE9 and Opera Next 12.00 alpha allow the user to reset the range to null after the fact by clicking somewhere;
737 | Firefox 12.0a1 and Chrome 17 dev do not.
738 | We follow Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.
Once a selection is associated with a given range, 741 | it must continue to be associated with that same range until this specification requires otherwise.
742 | 743 |For instance, if the DOM changes in a way that changes the range's boundary points,
744 | or a script modifies the boundary points of the range, the same range object must continue to be associated with the selection.
745 | However, if the user changes the selection or a script calls addRange(),
746 | the selection must be associated with a new range object, as required elsewhere in this specification.
If the selection's range is not null and is 749 | collapsed ([DOM4]), 750 | then the caret position must be at that range's boundary point. 751 | 752 | When the selection is not empty, this specification does not define the caret position; 753 | user agents should follow platform conventions in deciding whether the caret is at the start of the selection, 754 | the end of the selection, or somewhere else. 755 | 756 |
This short-changes Mac users. See bug 13909. 757 | 758 |
Each selection has a direction, forwards, backwards, or directionless. 759 | If the user creates a selection by indicating first one boundary point of the range 760 | and then the other (such as by clicking on one point and dragging to another), 761 | and the first indicated boundary point is after ([DOM4]) the second, 762 | then the corresponding selection must initially be backwards. 763 | If the first indicated boundary point is before ([DOM4]) the second, 764 | then the corresponding selection must initially be forwards. 765 | Otherwise, it must be directionless.
766 | 767 |Selections also have an anchor and a focus.
768 | If the selection's range is null, its anchor and focus are both null.
769 | If the selection's range is not null and its direction is forwards, its anchor is the range's
770 | start, and its focus is the end.
771 | Otherwise, its focus is the start and its anchor is the end.
interface Selection {
774 | readonly attribute Node? anchorNode;
775 | readonly attribute unsigned long anchorOffset;
776 | readonly attribute Node? focusNode;
777 | readonly attribute unsigned long focusOffset;
778 | readonly attribute boolean isCollapsed;
779 | readonly attribute unsigned long rangeCount;
780 | readonly attribute DOMString type;
781 | Range getRangeAt (unsigned long index);
782 | void addRange (Range range);
783 | void removeRange (Range range);
784 | void removeAllRanges ();
785 | void empty ();
786 | void collapse (Node node, unsigned long offset);
787 | void setPosition (Node node, unsigned long offset);
788 | void collapseToStart ();
789 | void collapseToEnd ();
790 | void extend (Node node, unsigned long offset);
791 | void setBaseAndExtent (Node anchorNode, unsigned long anchorOffset, Node focusNode, unsigned long focusOffset);
792 | void selectAllChildren (Node node);
793 | void deleteFromDocument ();
794 | boolean containsNode (Node node, boolean allowPartialContainment);
795 | stringifier DOMString ();
796 | };anchorNode of type Node, readonly , nullableThe attribute must return the anchor node ([DOM4])
798 | of the context object ([DOM4]),
799 | or null if the anchor is null.
anchorOffset of type unsigned long, readonly The attribute must return the anchor offset ([DOM4])
802 | of the context object, or 0 if the anchor is null.
focusNode of type Node, readonly , nullableThe attribute must return the focus node of the context object,
805 | or null if the anchor is null.
focusOffset of type unsigned long, readonly The attribute must return the focus offset of the context object,
808 | or 0 if the focus is null.
isCollapsed of type boolean, readonly The attribute must return true if and only if the anchor and focus are the same (including if both are null). 811 | Otherwise it must return false.
812 |rangeCount of type unsigned long, readonly The attribute must return 0 if the context object is empty,
814 | and must return 1 otherwise.
type of type DOMString, readonly The attribute must return "None" if the context object is empty,
817 | "Caret" if the context object's range is collapsed,
818 | and "Range" otherwise.
DOMStringstringifieraddRangeThe method must set the context object's range to range by a strong reference (not by making a copy) 823 | if the root ([DOM4]) 824 | of the range's boundary points are the document associated with context object. 825 | Otherwise, this method must do nothing.
826 | 827 |Since range is added by reference, subsequent calls to getRangeAt(0) returns the same object,
828 | and any changes that a script makes to range after it is added must be reflected in the selection,
829 | until something else removes or replaces the context object's range.
830 | In particular, the selection will contain b as opposed to a after running the following code:
831 | var r = document.createRange(); r.selectNode(a); getSelection().addRange(r); r.selectNode(b);
IE9 and Firefox 4.0 store a reference, as described here. 835 | Chrome 12 dev and Opera 11.10 appear to store a copy, so changes don't affect the selection.
836 | 837 |Chrome 15 dev seems to ignore addRange() if there's already a range. 838 | IE9 replaces the existing range. 839 | Firefox 9.0a2, of course, just gives you a multi-range selection. 840 | IE is likely to behave closest to Firefox, and is also more useful than silent failure, so the spec goes with that.
841 || Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| range | Range | ✘ | ✘ |
voidcollapseThe method must follow these steps:
844 |IndexSizeError exception if offset is longer than node's
846 | length ([DOM4]) and abort these steps.| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ | |
| offset | unsigned long | ✘ | ✘ |
voidcollapseToEndThe method must throw InvalidStateError exception if the context object is empty.
855 | Otherwise, it must create a new range, set both its start and end
856 | to the end of the context object's range,
857 | and then set the context object's range to the newly-created range.
voidcollapseToStartThe method must throw InvalidStateError ([DOM4]) exception
860 | if the context object is empty.
861 | Otherwise, it must create a new range, set both its start and end
862 | to the start of the context object's range,
863 | and then set the context object's range to the newly-created range.
For collapseToStart/End, IE9 mutates the existing range, while Firefox 9.0a2 and Chrome 15 dev replace it with a new one. 866 | The spec follows the majority and replaces it with a new one, leaving the old Range object unchanged.
voidcontainsNodeThe method must return false if the context object is empty
869 | or if node's root is not the document associated with the context object.
Otherwise, if allowPartialContainment is false,
872 | the method must return true if and only if
873 | start of its range is before or visually equivalent to
874 | the first boundary point in the node
875 | and end of its range is after or visually equivalent to
876 | the last boundary point in the node.
If allowPartialContainment is true,
879 | the method must return true if and only if
880 | start of its range is before or visually equivalent to
881 | the first boundary point in the node
882 | or end of its range is after or visually equivalent to
883 | the last boundary point in the node.
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ | |
| allowPartialContainment | boolean | ✘ | ✘ |
booleandeleteFromDocumentThe method must invoke deleteContents() ([DOM4])
886 | on the context object's range if the context object is not empty.
887 | Otherwise the method must do nothing.
This is the one method that actually mutates the range instead of replacing it. 890 | This matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 12.00 alpha can't be tested, 891 | because getRangeAt() returns a copy anyway.)
voidemptyThe method must be an alias, and behave identically, to removeAllRanges().
voidextendThe method must follow these steps:
896 |InvalidStateError exception and abort these steps.Reverse-engineered circa January 2011. 915 | IE doesn't support it, so I'm relying on Firefox (implemented extend() sometime before 2000) and WebKit (implemented extend() in 2007). 916 | I'm mostly ignoring Opera, because gsnedders tells me its implementation isn't compatible. 917 | 918 | Firefox 12.0a1 seems to mutate the existing range. 919 | IE9 doesn't support extend(), and it's impossible to tell whether Chrome 17 dev or Opera Next 12.00 alpha mutate or replace, 920 | because getRangeAt() returns a copy anyway. 921 | Nevertheless, I go against Gecko here, to be consistent with collapse().
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ | |
| offset | unsigned long | ✘ | ✘ |
voidgetRangeAtThe method must throw an IndexSizeError ([DOM4]) exception
924 | if index is not 0, or if the context object is empty.
925 | Otherwise, it must return a reference to (not a copy of) the context object's range.
Thus subsequent calls of this method returns the same range object
928 | if nothing has removed the context object's range in the meantime.
929 | In particular, getSelection().getRangeAt(0) === getSelection().getRangeAt(0) evaluates to true
930 | if the selection is not empty.
IE9 and Firefox 4.0 return the same object every time, as the spec says. 933 | Chrome 12 dev and Opera 11.10 return a different object every time.
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| index | unsigned long | ✘ | ✘ |
RangeremoveAllRangesThe method must make the context object empty by disassociating its range 936 | if the context object has an associated range.
937 |voidremoveRangeThe method must make the context object empty by disassociating its range 939 | if the context object's range is range. 940 | Otherwise, it must do nothing.
941 || Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| range | Range | ✘ | ✘ |
voidselectAllChildrenThe method must follow these steps:
943 |0).Based mostly on Firefox 9.0a2. It has a bug that I didn't reproduce, namely 954 | that if you pass a Document as the argument, the end offset becomes 1 instead 955 | of the number of children it has. It also throws a RangeException instead of 956 | DOMException, because its implementation predated their merging. 957 | 958 |
IE9 behaves similarly but with glitches. It throws "Unspecified error." if 959 | the node is detached or display:none, and apparently in some random other cases 960 | too. It throws "Invalid argument." for detached comments (only!). Finally, if 961 | you pass it a comment, it seems to select the whole comment, unlike with text 962 | nodes. 963 | 964 |
Chrome 16 dev behaves as you'd expect given its Selection implementation. 965 | It refuses to select anything that's not visible, so it's almost always wrong. 966 | Opera 11.50 just does nothing in all my tests, as usual. 967 | 968 |
The new range replaces any existing one, doesn't mutate it. 969 | This matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 12.00 970 | alpha can't be tested, because getRangeAt() returns a copy anyway.) 971 |
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ |
voidsetBaseAndExtentThe method must follow these steps:
974 |IndexSizeError exception and abort these steps.| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| anchorNode | Node | ✘ | ✘ | |
| anchorOffset | unsigned long | ✘ | ✘ | |
| focusNode | Node | ✘ | ✘ | |
| focusOffset | unsigned long | ✘ | ✘ |
voidsetPositionThe method must be an alias, and behave identically, to collapse().
| Parameter | Type | Nullable | Optional | Description |
|---|---|---|---|---|
| node | Node | ✘ | ✘ | |
| offset | unsigned long | ✘ | ✘ |
voidSee also nsISelection.idl from Gecko. 995 | This spec doesn't have everything from there yet, in particular selectionLanguageChange() and containsNode() are missing. 996 | They are missing because I couldn't work out how to define them in terms of Ranges.
Originally, the Selection interface was a Netscape feature. 1000 | The original implementation was carried on into Gecko (Firefox), and the feature was later implemented independently by other browser engines. 1001 | The Netscape implementation always allowed multiple ranges in a single selection, for instance so the user could select a column of a table 1002 | However, multi-range selections proved to be an unpleasant corner case 1003 | that web developers didn't know about and even Gecko developers rarely handled correctly. 1004 | Other browser engines never implemented the feature, and clamped selections to a single range in various incompatible fashions.
1005 | 1006 |This specification follows non-Gecko engines in restricting selections to at most one range,
1007 | but the API was still originally designed for selections with arbitrary numbers of ranges.
1008 | This explains oddities like the coexistence of removeRange() and removeAllRanges(),
1009 | and a getRangeAt() method that takes an integer argument that must always be zero.
All of the members of the Selection interface are defined
1013 | in terms of operations on the range object (if any) represented by the object.
1014 | These operations can raise exceptions, as defined for the Range ([DOM4]) interface;
1015 | this can therefore result in the members of the Selection interface raising exceptions as well,
1016 | in addition to any explicitly called out below.
This specification extends several interfaces to provide entry points to the 1023 | interfaces defined in this specification.
1024 | 1025 |Document interfacepartial interface Document {
1028 | Selection? getSelection ();
1029 | };getSelectionThe method must return the selection associated with context object
1031 | if the context object has an associated browsing context,
1032 | and it must return null otherwise.
Selection, nullable
1035 | If we create a Document object with no browsing context
1036 | (say via document.implementation.createHTMLDocument("") and call getSelection() on it),
1037 | IE9 seems to return a different Selection object.
1038 | Firefox 12.0a1 and Opera Next 12.00 alpha return the same object as for the current window.
1039 | Chrome 17 dev returns null.
1040 | See discussion.
1041 | There's no meaningful selection associated with such a document, so we follow WebKit and require returning null.
Window interfacepartial interface Window {
1047 | Selection? getSelection ();
1048 | };getSelectionThe method must invoke and return the result of getSelection() on the context object's
1050 | document ([HTML5]) property.
Selection, nullableThe user agent should allow the user to change the selection associated with the active document 1060 | (defined in [HTML5]). 1061 | If the user makes any modification to a selection, the user agent must create a new range with suitable 1062 | start and 1063 | end of the range ([DOM4]) 1064 | and associate the selection with this new range (not modify the existing range), 1065 | and set update selection's direction to forwards if the start is before or equal to the end, 1066 | backwards if if the end is before the start, 1067 | or directionless if the start and the end cannot be ordered due to the platform convention.
1068 | 1069 |The user agent must not make a selection empty if it was not already empty 1070 | in response to any user actions (e.g. clicking on a non-editable region).
1071 | 1072 |See bug 15470. 1073 | IE9 and Opera Next 12.00 alpha allow the user to reset the range to null after the fact by clicking somewhere; 1074 | Firefox 12.0a1 and Chrome 17 dev do not. 1075 | I follow Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.
selectstart eventWhen the user agent is about to associate a new range newRange to the selection in response to a user initiated action,
1081 | the user agent must fire ([DOM4])
1082 | an event with the name selectstart, which bubbles and is cancelable,
1083 | at the node associated with the boundary point of newRange's start
1084 | prior to changing the selection if the selection was previously empty
1085 | or the previously associated range was collapsed.
If the event is canceled, the user agent must not change the selection.
1088 | 1089 |The user agent must not fire the event when the user agent sets the selection empty.
1090 |selectionchange eventWhen the selection is dissociated with its range, associated with a new range
1096 | or the associated range's boundary point is mutated either by the user or the content script,
1097 | the user agent must queue a task ([HTML5])
1098 | to fire an event with the name selectionchange, which does not bubble and is not cancelable,
1099 | at the document associated with the selection.
Many thanks to
1107 |Aryeh Gregor, who is the original author of this specification as well as HTML Editing API specification.
Contributors to the HTML Editing API specification - 1110 | Ehsan Akhgari, Tab Atkins, Mathias Bynens, Tim Down, Markus Ernst, Daniel Glazman, Tali Gregor (née Fuss), 1111 | Stig Halvorsen, Jeff Harris, Ian Hickson, Cameron Heavon-Jones, Anne van Kesteren, Alfonso Martínez de Lizarrondo, 1112 | Glenn Maynard, Ms2ger, Robert O'Callahan, Julie Parent, Simon Pieters, Michael A. Puls II, 1113 | Rich Schwerdtfeger, Jonas Sicking, Henri Sivonen, Smylers, Hallvord R. M. Steen, Roland Steiner, Annie Sullivan, 1114 | timeless, Ojan Vafai, Brett Zamir, and Boris Zbarsky for their feedback, participation, or other helpful contributions