forked from ehsan/editing
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathediting.html
10523 lines (8106 loc) · 810 KB
/
editing.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html><meta charset=utf-8>
<title>HTML Editing APIs</title>
<link href=http://www.whatwg.org/style/specification rel=stylesheet>
<style>
pre, code, xmp { font-family:monospace, sans-serif; }
h2 code, h3 code, h3 code,
h2 :link, h3 :link, h3 :link,
h2 :visited, h3 :visited, h3 :visited
{ font:inherit; color:inherit; font-style:italic; }
@media print {
:not([data-anolis-spec]) > [data-anolis-spec]::after {
content: "[" attr(data-anolis-spec) "]";
font-size: 0.6em;
vertical-align: super;
text-transform: uppercase;
}
}
xmp {
font-size: inherit;
font-variant: normal;
margin-left: 2em;
white-space: pre-wrap;
}
div.note > p:first-child::before,
li.note > p:first-child::before { content: 'Note: ' }
.note var { font-style: normal }
li.note { display: block }
.XXX > :last-child { margin-bottom: 0 }
.XXX li {
margin-top: 0;
margin-bottom: 0;
}
dd .XXX p { margin: 1em 0 }
ol li { margin: 1em 0 }
li li, li li > p { margin: 0 }
li p + * > li:first-child { margin-top: -1em }
li li > p + * > li:first-child { margin-top: 0 }
table { margin: 1em 0 }
.toc, .toc li { list-style-type: disc }
.toc li li { list-style-type: circle }
/* Overwrite the underline so it's orange instead of blue, thus looks less
* silly */
a code { text-decoration: underline }
/* Comments stuff */
.comments { display: none }
.comments-wrapper {
font-size: small;
color: #333;
}
.comments-wrapper > button {
float: right;
margin-left: 0.3em;
}
.comments-expanded {
position: absolute;
z-index: 1;
right: 0;
width: 50%;
background: white;
border: 1px solid gray;
padding: 0.5em;
margin-top: 2em;
}
.comments-expanded :first-child { margin-top: 0 }
.comments-expanded :last-child { margin-bottom: 0 }
</style>
<body class=draft>
<div class=head id=head>
<p><a href=http://www.w3.org/><img alt=W3C height=48 src=http://www.w3.org/Icons/w3c_home width=72></a></p>
<h1>HTML Editing APIs</h1>
<h2 class="no-num no-toc" id=work-in-progress-—-last-update-20-may-2012>Work in Progress — Last Update 20 May 2012</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <<a href=mailto:[email protected]>[email protected]</a>>
<dt>Latest version
<dd><a href=http://dvcs.w3.org/hg/editing/raw-file/tip/editing.html>W3C Mercurial</a>
<dt>Version history
<dd><a href=https://dvcs.w3.org/hg/editing>W3C Mercurial</a>
<dd><a href=https://github.com/ayg/editing>github mirror</a>
<dt>Issue tracker
<dd><a href="http://www.w3.org/Bugs/Public/buglist.cgi?component=HTML+Editing+APIs&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED">All open issues</a>
<dd><a href="http://www.w3.org/Bugs/Public/enter_bug.cgi?product=WebAppsWG&component=HTML+Editing+APIs">File an issue</a>
<dt>Mailing list
<dd><a href="mailto:[email protected][email protected]&subject=%5Bediting%5D%20">public-webapps</a> (<a href=http://lists.w3.org/Archives/Public/public-webapps/>archive</a>;
include "[editing]" in the subject)
<dt>IRC chat
<dd><a href=irc://irc.freenode.net/whatwg>#whatwg on freenode</a>
</dl>
</div>
<h2 class=no-num id=status-of-this-document>Status of this Document</h2>
<p>This document is a preliminary draft of a specification for HTML editing
APIs, mainly defining <a href=#concept-selection title=concept-selection>selections</a>, <code><a href=#execcommand()>execCommand()</a></code> and related
functionality. It replaces a couple of old sections of the <a href=http://www.whatwg.org/html>HTML</a> specification, and the <a href=#concept-selection title=concept-selection>selection</a>
part of the old DOM Range specification. Issues that don't necessarily need
discussion should preferably be <a href="http://www.w3.org/Bugs/Public/enter_bug.cgi?product=WebAppsWG&component=HTML+Editing+APIs">filed
in the issue tracker</a>. Feedback that needs discussion should preferably be
sent to <a href="mailto:[email protected][email protected]&subject=%5Bediting%5D%20">the
public-webapps list</a>, with the string "[editing]" somewhere in the subject,
CC'd to <a href=mailto:[email protected]>[email protected]</a> to make sure I see it.
I will handle all feedback I'm aware of, either addressing it immediately or
filing a bug if it needs longer-term consideration and is not already filed.
<p>Copyright © 2012 the Contributors to the HTML Editing APIs Specification,
published by the <a href=https://www.w3.org/community/editing/>W3C Editing
APIs Community Group</a> under the <a href=https://www.w3.org/community/about/agreements/cla/>W3C Community
Contributor License Agreement (CLA)</a>. A human-readable <a href=http://www.w3.org/community/about/agreements/cla-deed/>summary</a> is
available.
<p>This specification, along with the accompanying JavaScript implementation
and tests, may also be used under the terms of the <a href=http://creativecommons.org/publicdomain/zero/1.0/>CC0 1.0 Universal
License</a>. Thus anyone may reuse, modify, and redistribute them without
restriction.
<p>This specification was published by the <a href=http://www.w3.org/community/editing/>W3C Editing APIs Community Group</a>.
It is not a W3C Standard nor is it on the W3C Standards Track. Please note that
under the <a href=http://www.w3.org/community/about/agreements/cla/>W3C
Community Contributor License Agreement (CLA)</a> there is a limited opt-out
and other conditions apply. Learn more about <a href=http://www.w3.org/community/>W3C Community and Business Groups</a>.
<h2 class=no-num id=table-of-contents>Table of contents</h2>
<!--begin-toc-->
<ol class=toc>
<li><a class=no-num href=#status-of-this-document>Status of this Document</a></li>
<li><a class=no-num href=#table-of-contents>Table of contents</a></li>
<li><a href=#introduction>Introduction</a></li>
<li><a href=#tests>Tests</a>
<ol>
<li><a href=#general-remarks>General remarks</a></li>
<li><a href=#development-tests>Command development tests</a></li>
<li><a href=#conformance-tests>Command conformance tests</a></ol></li>
<li><a href=#issues>Issues</a></li>
<li><a href=#selections>Selections</a></li>
<li><a href=#commands>Commands</a>
<ol>
<li><a href=#properties-of-commands>Properties of commands</a></li>
<li><a href=#supported-commands>Supported commands</a></li>
<li><a href=#enabled-commands>Enabled commands</a></ol></li>
<li><a href=#methods-to-query-and-execute-commands>Methods to query and execute commands</a></li>
<li><a href=#common-definitions>Common definitions</a></li>
<li><a href=#common-algorithms>Common algorithms</a>
<ol>
<li><a href=#assorted-common-algorithms>Assorted common algorithms</a></li>
<li><a href=#wrapping-a-list-of-nodes>Wrapping a list of nodes</a></li>
<li><a href=#allowed-children>Allowed children</a></ol></li>
<li><a href=#inline-formatting-commands>Inline formatting commands</a>
<ol>
<li><a href=#inline-formatting-command-definitions>Inline formatting command definitions</a></li>
<li><a href=#assorted-inline-formatting-command-algorithms>Assorted inline formatting command algorithms</a></li>
<li><a href="#clearing-an-element's-value">Clearing an element's value</a></li>
<li><a href=#pushing-down-values>Pushing down values</a></li>
<li><a href=#forcing-the-value-of-a-node>Forcing the value of a node</a></li>
<li><a href="#setting-the-selection's-value">Setting the selection's value</a></li>
<li><a href=#the-backcolor-command>The <code title="">backColor</code> command</a></li>
<li><a href=#the-bold-command>The <code title="">bold</code> command</a></li>
<li><a href=#the-createlink-command>The <code title="">createLink</code> command</a></li>
<li><a href=#the-fontname-command>The <code title="">fontName</code> command</a></li>
<li><a href=#the-fontsize-command>The <code title="">fontSize</code> command</a></li>
<li><a href=#the-forecolor-command>The <code title="">foreColor</code> command</a></li>
<li><a href=#the-hilitecolor-command>The <code title="">hiliteColor</code> command</a></li>
<li><a href=#the-italic-command>The <code title="">italic</code> command</a></li>
<li><a href=#the-removeformat-command>The <code title="">removeFormat</code> command</a></li>
<li><a href=#the-strikethrough-command>The <code title="">strikethrough</code> command</a></li>
<li><a href=#the-subscript-command>The <code title="">subscript</code> command</a></li>
<li><a href=#the-superscript-command>The <code title="">superscript</code> command</a></li>
<li><a href=#the-underline-command>The <code title="">underline</code> command</a></li>
<li><a href=#the-unlink-command>The <code title="">unlink</code> command</a></ol></li>
<li><a href=#block-formatting-commands>Block formatting commands</a>
<ol>
<li><a href=#block-formatting-command-definitions>Block formatting command definitions</a></li>
<li><a href=#assorted-block-formatting-command-algorithms>Assorted block formatting command algorithms</a></li>
<li><a href=#block-extending-a-range>Block-extending a range</a></li>
<li><a href=#recording-and-restoring-overrides>Recording and restoring overrides</a></li>
<li><a href=#deleting-the-selection>Deleting the selection</a></li>
<li><a href="#splitting-a-node-list's-parent">Splitting a node list's parent</a></li>
<li><a href=#canonical-space-sequences>Canonical space sequences</a></li>
<li><a href=#indenting-and-outdenting>Indenting and outdenting</a></li>
<li><a href=#toggling-lists>Toggling lists</a></li>
<li><a href=#justifying-the-selection>Justifying the selection</a></li>
<li><a href=#automatic-linking>Automatic linking</a></li>
<li><a href=#the-delete-command>The <code title="">delete</code> command</a></li>
<li><a href=#the-formatblock-command>The <code title="">formatBlock</code> command</a></li>
<li><a href=#the-forwarddelete-command>The <code title="">forwardDelete</code> command</a></li>
<li><a href=#the-indent-command>The <code title="">indent</code> command</a></li>
<li><a href=#the-inserthorizontalrule-command>The <code title="">insertHorizontalRule</code> command</a></li>
<li><a href=#the-inserthtml-command>The <code title="">insertHTML</code> command</a></li>
<li><a href=#the-insertimage-command>The <code title="">insertImage</code> command</a></li>
<li><a href=#the-insertlinebreak-command>The <code title="">insertLineBreak</code> command</a></li>
<li><a href=#the-insertorderedlist-command>The <code title="">insertOrderedList</code> command</a></li>
<li><a href=#the-insertparagraph-command>The <code title="">insertParagraph</code> command</a></li>
<li><a href=#the-inserttext-command>The <code title="">insertText</code> command</a></li>
<li><a href=#the-insertunorderedlist-command>The <code title="">insertUnorderedList</code> command</a></li>
<li><a href=#the-justifycenter-command>The <code title="">justifyCenter</code> command</a></li>
<li><a href=#the-justifyfull-command>The <code title="">justifyFull</code> command</a></li>
<li><a href=#the-justifyleft-command>The <code title="">justifyLeft</code> command</a></li>
<li><a href=#the-justifyright-command>The <code title="">justifyRight</code> command</a></li>
<li><a href=#the-outdent-command>The <code title="">outdent</code> command</a></ol></li>
<li><a href=#miscellaneous-commands>Miscellaneous commands</a>
<ol>
<li><a href=#the-copy-command>The <code title="">copy</code> command</a></li>
<li><a href=#the-cut-command>The <code title="">cut</code> command</a></li>
<li><a href=#the-defaultparagraphseparator-command>The <code title="">defaultParagraphSeparator</code> command</a></li>
<li><a href=#the-paste-command>The <code title="">paste</code> command</a></li>
<li><a href=#the-redo-command>The <code title="">redo</code> command</a></li>
<li><a href=#the-selectall-command>The <code title="">selectAll</code> command</a></li>
<li><a href=#the-stylewithcss-command>The <code title="">styleWithCSS</code> command</a></li>
<li><a href=#the-undo-command>The <code title="">undo</code> command</a></li>
<li><a href=#the-usecss-command>The <code title="">useCSS</code> command</a></ol></li>
<li><a href=#additional-requirements>Additional requirements</a></li>
<li><a class=no-num href=#acknowledgements>Acknowledgements</a></ol>
<!--end-toc-->
<h2 id=introduction>Introduction</h2>
<p class=comments>
<a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=16206">Bug 16206</a>.
<p>A piece of software that claims to implement this specification must follow
every <dfn id=normative>normative</dfn> requirement in it. Every requirement in this
specification is <a href=#normative>normative</a> unless stated otherwise.
<p class=comments>These are comments. All comments other than this one are
non-<a href=#normative>normative</a>.
<p class=note>This is a note. All notes other than this one are
non-<a href=#normative>normative</a>.
<p class=XXX>This is an open issue. All issues other than this one are
non-<a href=#normative>normative</a>.
<p>The remainder of this section is not <a href=#normative>normative</a>, and nor is any
preceding section.
<p>This specification defines commands to edit HTML documents programmatically.
The APIs specified here were originally introduced in Microsoft's Internet
Explorer, but have subsequently been copied by other browsers in a haphazard
and imprecise fashion. Although the behavior specified here does not exactly
match any browser at the time of writing, it can serve as a target to converge
to in the future.
<p>Where the reasoning behind the specification is of interest, such as when
major preexisting rendering engines are known not to match it, the reasoning is
available by clicking the "comments" button on the right (requires JavaScript).
If you have questions about why the specification says something, check the
comments first. They're sometimes longer than the specification text itself,
and commonly record what the major browsers do and other essential information.
<p>The principles I've used for writing this specification so far are:
<ul>
<li>If all browsers that implement a particular feature agree on some detail
of how it works, match them unless there's very good reason not to. When
it's not clear what behavior is best, try to follow the implementations with
the most market share. But if one browser's behavior is clearly better than
the others', go with the better behavior.
<li>If a command is issued to format some text in a particular way, we will
format the text that way no matter what. If the user clicks the "bold"
button, they don't care that the text didn't become bold because of an
external CSS rule or for any other reason, they only care that it didn't
work. The only exception (beyond where it's simply impossible, like
propagated text-decorations we can't remove) is that we don't try to override
!important rules from external stylesheets, although we also don't go out of
our way to respect them.
<li>When we're given a presentational command like "bold", don't modify
anything other than presentational markup related to that command. If an
element has non-presentational attributes like id or class, don't split it up
or remove it or anything. At most convert it to a span, if it's some type of
presentational element. ("Presentational" here really means "browsers
produce it in response to execCommand() so we need to treat it as
presentational", so it includes things like <code class=external data-anolis-spec=html title="the strong element"><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-strong-element>strong</a></code> and <code class=external data-anolis-spec=html title="the em element"><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-em-element>em</a></code>.) Of
course, in some cases we have to remove elements, like when merging two
blocks.
<li>Don't interfere with more markup than necessary. If the user modifies
only a small run of text, don't go around simplifying ancestors or siblings
or whatever unless it's necessary to produce simpler markup in the place that
was actually modified.
<li>But if we are already changing around something's style, convert existing
styles to the preferred format. For instance, we use <code title=""><b></code> for bold
(if the CSS styling flag is false), and convert <code title=""><strong></code> and
<code title=""><span style="font-weight: bold"></code> if we happen to be modifying
that node anyway.
<li>Try not to make the document less conforming than it originally was. If
we happen to make it more conforming, good, although we don't have to go out
of our way to do that. In some cases we do make the document less
conforming, generally because there's some clear use-case that requires it or
because it matches existing browsers behavior. (For instance, see the
styleWithCSS = false mode, and the fact that insertImage doesn't add an
alt attribute, etc.)
<li>Keep the markup as concise as possible. (I've received feedback that
this is very important to authors.) Ideally, the markup should look as
simple and neat as what a human would have produced by hand-editing. We do
complicated manipulation to pull styles down from ancestors rather than
having to use inline CSS, and make sure to tidy up any styles on elements
that we happen to be modifying anyway. Previous principles take precedence
over this one, however.
</ul>
<h2 id=tests>Tests</h2>
<p><i title="">This section is not <a href=#normative>normative</a>.</i>
<h3 id=general-remarks>General remarks</h3>
<p>There are two groups of tests currently associated with this document:
selection tests, and command tests. These tests are a
non-<a href=#normative>normative</a> part of this specification. The command tests are
available in two formats, development tests and conformance tests. This has a
lot to do with the history of how the specification was developed: selection
was originally part of the defunct <a href=http://html5.org/specs/dom-range.html>DOM Range</a> spec, while the
command parts were developed on their own. The selection things have been
merged into the command spec, but neither the spec text nor the tests have been
fully unified at the time of this writing.
<p>Thus the selection tests live in their own directory, <a href=selecttest/>selecttest/</a>. They use the standard <a href=http://dvcs.w3.org/hg/html/file/tip/tests/resources/testharness.js>testharness.js</a>
framework developed by James Graham. They're entirely self-contained, sharing
nothing with the command tests (except invoking the testharness.js library).
At the time of this writing, they're not nearly as comprehensive as the command
tests, although they do test some functionality comprehensively.
<p>On the other hand, the command-related part of this specification is
developed in tandem with a more or less complete <a href=implementation.js>JavaScript implementation</a>. The implementation is
used for creating tests, of two different types: development tests and
conformance tests. The two types of test share most of the same code, starting
with the multi-thousand-line implementation itself. The actual tests run are
largely the same in either case, but the way they're run is very different.
<p>The development tests were the original ones, and were designed to assist in
writing the specification from scratch. Given an input, they print out the
spec's and browser's output to allow manual inspection. They can store the
spec's output and will raise an alert if it changed since the last run, as a
form of regression testing, but they don't print out counts of passed/failed
tests. They are not designed to run exactly the same across browsers and are
tolerant of minor variations. Development tests are likely not very useful for
anyone other than the spec's editor.
<p>Conformance tests were added later. They run the same tests as the
development tests, but in an entirely non-interactive format, using the <a href=http://dvcs.w3.org/hg/html/file/tip/tests/resources/testharness.js>testharness.js</a>
framework like the selection tests. They always run the same set of tests,
don't vary behavior between browsers (hopefully), and are unforgiving of any
deviation. However, they're significantly more cumbersome to set up and use,
so they're less useful for developing the specification itself.
<p>There's a suite of predefined tests for each command (~30–300 at the
time of this writing). These are the only tests run for the conformance tests,
and in the regression tests they can be run by clicking the "Run tests" button.
For the regression tests, you can also enter your own tests manually in the box
provided. In any event, the test input is a snippet of HTML, which must have a
selection marked in it. There are three ways to mark a selection's start or
end:
<ol>
<li>Square brackets mark a selection inside a text node, like
<code title=""><b>foo[bar]baz</b></code> for a selection whose start and end nodes are in
the text node <code title="">foobarbaz</code>, with start offset 3 and end offset 6. Do
not use square brackets where there's no text node: <code title=""><b>[]</b></code> is
bad, <code title=""><b>{}</b></code> is correct.
<li>Curly braces mark a selection inside an element, like
<code title=""><b>{foobarbaz</b>}</code> for a selection whose start node is the element
<code title=""><b></code>, whose start offset is 0, whose end node is the root of the
editable region, and whose end offset is 1. Do not use curly braces in the
middle of a text node: <code title="">foo{bar}baz</code> is bad, <code title="">foo[bar]baz</code> is correct.
<li>The <code title="">data-start</code> and <code title="">data-end</code>
attributes mark a selection inside an element if a curly brace can't be put
there in text/html. For instance,
<code title=""><table><tr>{<td>foo</td>}</tr></table></code> doesn't work because when the
fragment is parsed, the curly braces end up outside the table. Instead, you
have to do <code title=""><table><tr data-start=0 data-end=1><td>foo</table></code>.
</ol>
<p>Every input must have exactly one start marker and one end marker, which
will be removed from the DOM before the test is run. You can mix and match
marker types, e.g., <code title="">[foo}</code>.
<p>There is one special test type that behaves differently, "multitest". This
allows running several tests in succession, which is needed at least for
testing the effect of commands' <a href=#state-override>state override</a> or <a href=#value-override>value
override</a>. The syntax is JSON, and looks like
<pre>[<var title="">HTML input</var>,
[<var title="">command name 1</var>, <var title="">command value 1</var>],
[<var title="">command name 2</var>, <var title="">command value 2</var>],
. . .]</pre>
<p>where all the variables are properly-quoted JSON strings. <code title="">queryCommand*()</code> are not run for multitests.
<p>In all cases, prefixing the test string (or the first string in the test
array, for arrays) with "!" has a special effect. The "!" will be stripped,
and the test will be added to an array of bad tests. These tests will be
omitted from the <a href=#conformance-tests>conformance tests</a>. This is
used to mark tests where the reference implementation is known to currently
give bad results, either because of a bug in the reference implementation or a
bug in the spec. Bad tests will still be run as <a href=#development-tests>development tests</a>.
<p>Commands that are expected to vary significantly based on the value of the
<a href=#css-styling-flag>CSS styling flag</a> are run twice. The first time runs
<code title="">execCommand("styleWithCSS", false, "false")</code> before every
command, and the second runs <code title="">execCommand("styleWithCSS", false,
"true")</code> before every command. All other commands other than multitests
run <code title="">execCommand("styleWithCSS", false, "false")</code> before every
command. The extra tests are not run as regression tests, in IE or Opera,
because they don't implement <a href=#the-stylewithcss-command>the <code title="">styleWithCSS</code>
command</a> (but of course the conformance tests always all run).
<p>The implementation is also used for an actual <a href=editor.html>rich-text
editor</a>, but it's currently more of a toy than anything. Significant
functionality is probably broken, especially outside of Gecko/WebKit. I might
spend some more time getting it to work right, but it's certainly not going to
be very useful on real-world sites, since there's no way any of this stuff will
work in IE8.
<h3 id=development-tests>Command development tests</h3>
<p>The development tests are mostly useful for developing the spec itself, not
for use by authors or browser implementers. They consist of a suite of fully
automated tests plus a few separate suites of manual tests. The tests are:
<ul>
<li><a href=autoimplementation.html>autoimplementation.html</a>: Fully
automated tests for pretty much all commands.
<li><a href=deletetest.html>deletetest.html</a>: Manual tests for <a href=#the-delete-command>the
<code title="">delete</code> command</a>.
<li><a href=forwarddeletetest.html>forwarddeletetest.html</a>: Manual tests
for <a href=#the-forwarddelete-command>the <code title="">forwardDelete</code> command</a>.
<li><a href=insertlinebreaktest.html>insertlinebreaktest.html</a>: Manual
tests for <a href=#the-insertlinebreak-command>the <code title="">insertLineBreak</code> command</a>.
<li><a href=insertparagraphtest.html>insertparagraphtest.html</a>: Manual
tests for <a href=#the-insertparagraph-command>the <code title="">insertParagraph</code> command</a>.
<li><a href=inserttexttest.html>inserttexttest.html</a>: Manual tests for
<a href=#the-inserttext-command>the <code title="">insertText</code> command</a>, with <var title="">value</var>
"a".
<li><a href=inserttext2test.html>inserttext2test.html</a>: Manual tests for
<a href=#the-inserttext-command>the <code title="">insertText</code> command</a>, with <var title="">value</var>
" ".
</ul>
<p>The automated tests run the JavaScript implementation of the specification
on a particular input, then run the browser's implementation on the same input
for comparison. The results of running automated tests are placed in a table,
with rows marked as passing or failing based on whether the browser output is
"close enough" to the spec output. Since the tests are designed for debugging
the spec rather than actually testing conformance, minor variations are allowed
to avoid having browsers fail many tests for uninteresting reasons. Passes and
fails are based only on <code><a href=#execcommand()>execCommand()</a></code> output, not <code title="">queryCommand*()</code>: the latter is sanity-checked, and colored green
or red if it's known to be right or wrong on general principle, but spec and
browser output are not compared.
<p>The tests will optionally store the specification's result for each test in
<code title="">localStorage</code>, and will raise an alert for any new test (no
stored output), any test whose spec output is different from the last run, and
any test whose spec output is otherwise clearly bad (e.g., producing a
non-serializable DOM). This is mostly useful for debugging and
regression-testing the spec itself, and is probably not interesting to anyone
other than me.
<p>When a test runs, first the code sets up a contenteditable div with the
given contents and sets the selection as requested. Then it runs
<code><a href=#querycommandindeterm()>queryCommandIndeterm()</a></code>, <code><a href=#querycommandstate()>queryCommandState()</a></code>, and
<code><a href=#querycommandvalue()>queryCommandValue()</a></code>, and their values are noted. Then it runs
<code><a href=#execcommand()>execCommand()</a></code>. Finally, it runs
<code><a href=#querycommandindeterm()>queryCommandIndeterm()</a></code>, <code><a href=#querycommandstate()>queryCommandState()</a></code>, and
<code><a href=#querycommandvalue()>queryCommandValue()</a></code> again. Then it adds the output to the table.
<p>The manual tests are much like the automated tests, with some key
differences. They only test one command each, with one input value (if
applicable). When a test is run, everything proceeds as in the automated case,
but instead of running <code><a href=#execcommand()>execCommand()</a></code> for the browser tests, the
user is asked to hit the appropriate key (backspace, delete, enter, etc.).
Thus when running the tests for the first time, the user has to hit a key
repeatedly, perhaps a few hundred times. The browser's result is then cached
in <code title="">localStorage</code> so no manual intervention is required on
subsequent runs except for newly-added tests, but the cached entries can be
cleared if necessary.
<p>The development tests have been tested and largely work in the latest
versions (at the time of this writing) of IE, Firefox, Chrome, and Opera.
Since the implementation of the spec is in JavaScript, it's vulnerable to bugs
in browsers' JavaScript implementations. I work around or warn about some of
these, but not all. The most correct results will probably be in Firefox or
Chrome: both IE and Opera have serious known bugs that corrupt spec output for
many tests. The tests are still useful for reviewing the browser output, but
spec output in those browsers should be sanity-checked and compared against
another browser's spec output in case of doubt.
<h3 id=conformance-tests>Command conformance tests</h3>
<p>The conformance tests operate more like one would expect from tests. Once
generated, they consist of a single page, <a href=conformancetest/runtest.html>conformancetest/runtest.html</a>, which runs
all the tests and prints out a table of passes and fails. Like many other
recent web standards suites, they use the <a href=http://dvcs.w3.org/hg/html/file/tip/tests/resources/testharness.js>testharness.js</a>
framework, and browser implementers should be able to make them part of their
automated regression test frameworks.
<p>For manual inspection, a version of the conformance tests is also available
that runs only some of the tests at once: <a href=conformancetest/splitruntest.html>conformancetest/splitruntest.html</a>.
This runs only one group of tests at a time, which takes only a few seconds
instead of a minute or more. This makes debugging particular tests much
faster. In all other respects, it should behave identically to runtest.html.
<p>Unlike the development tests, the conformance tests don't run the JavaScript
implementation as part of the test. Instead, the tests' expected values are
generated by a separate page, <a href=conformancetest/gentest.html>conformancetest/gentest.html</a>. That page
will output the expected values for all tests in a format to be copied to <a href=conformancetest/data.js>conformancetest/data.js</a>, where it will be used
by runtest.html.
<p>This separation has a few benefits. First of all, it means the conformance
tests take a long time to generate, but run <em>much</em> faster than the
development tests: on the order of one minute instead of five or more.
(Browser implementations of <code title="">execCommand()</code> are currently much faster
than the spec's JS reference implementation, it seems.) Second of all, it
means that all browsers are running against the same expected results. Third
of all, the fact that all expected results are saved in a file allows much more
systematic regression testing of the spec and the reference implementation.
Changes in expected results will be recorded in the spec's version history and
can be matched up to changes in the reference implementation or the spec,
instead of being stored transiently in the spec editor's <code title="">localStorage</code>
and then lost.
<p>There are a couple of disadvantages as well. For one thing, new tests can't
easily be added live, so the conformance tests aren't useful for experimenting
with how implementations work. For another thing, the tests' expected results
can only be generated all at once (not per-command), which takes minutes. A
third issue is that they provide no useful feedback at all about user actions
such as hitting Enter: they tell you what <a href=#the-insertparagraph-command>the <code title="">insertParagraph</code> command</a> does in the browser, but not
whether it matches up to any user action. Commands like <a href=#the-inserttext-command>the <code title="">insertText</code> command</a> just fail all tests in most browsers.
Thus they don't replace the manual development tests at all. (Manual
conformance tests will eventually be added.)
<p>As might be expected, browsers don't generate exactly the same expected
results from the tests. Clearly incorrect expected results (like a DOM that
doesn't round-trip through text/html) are automatically rejected, with a
printed warning, but some discrepancies remain. At the time of this writing,
Firefox 8.0a2 and Chrome 15 dev generate identical results, except that Firefox
omits one test (due to <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=578141">incorrect
serialization of <code title=""><xmp></code></a>) and Chrome gets one test wrong (due to a
<a href="https://bugs.webkit.org/show_bug.cgi?id=67424">style resolution
bug</a>). Thus I generate the tests right now in Firefox, since all its
generated tests are at least correct. IE9 and Opera 11.50 don't yet generate
or run the tests usefully at all in this initial version, but this will be
remedied soon.
<p>Event firing is currently tested in a totally separate file,
<a href=conformancetest/event.html>event.html</a>. In the long term, this will
probably be merged into runtest.html so that it's tested more thoroughly.
<h2 id=issues>Issues</h2>
<p><i title="">This section is not <a href=#normative>normative</a>.</i>
<p>This specification is mostly feature-complete. It's more or less fully
implemented in JavaScript, and has been tested on a fairly significant amount
of artificial input. It has not been tested on real-world sites that use
execCommand(), and has not been thoroughly reviewed by anyone other than me.
It should be considered mostly stable and awaiting implementater review and
feedback.
<p>Significant known issues that I need feedback on, or otherwise am not
planning to fix just yet:
<ul>
<li>Need to make CSS terminology more precise, about setting/unsetting CSS
properties. The intent is to modify the style attribute, CSSOM-style.
Suggestions appreciated on how I should spec this.
<li>I use <a href=http://dev.w3.org/csswg/cssom/#resolved-value>resolved value</a> instead of computed or used or anything like that, just
because that's what my test implementation uses (via getComputedStyle). This
is not necessarily the best actual choice: if it should be something else,
please tell me.
<li><p>I haven't paid much attention to performance. The algorithms here
aren't performance-critical in most cases, but I might have accidentally
included some algorithms that are too slow anyway on large pages. Generally
I haven't worried about throwing nodes away and recreating them multiple
times or things like that, as long as it produces the correct result.
<p>If it would be useful to implementers for me to spend time and spec
complexity on avoiding some of the masses of useless operations that are
currently required, please say so. All intermediate DOM states are
black-box detectable via mutation events or whatever their replacement will
be, so implementers theoretically can't optimize most of this stuff too much
themselves, but in practice I doubt anyone will rely on the intermediate DOM
states much.
<li><code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-br-element>br</a></code>s are a nightmare. I have tons of hacks all over the place which
are totally wrong, mostly to account for the fact that sometimes <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-br-element>br</a></code>s do
nothing and we need to treat that case magically. I don't know what a good
way is to fix this. At this point I've mostly gotten the evil concentrated
in the definitions "collapsed line break", "extraneous line break", and
"collapsed block prop", but there's lots of other special-case handling
scattered about. Feedback appreciated. How do browsers handle this?
<li>The CSS styling flag is an issue. Currently authors are forced to turn
it entirely on or entirely off. If it's on, it produces stuff like <code title=""><span style=font-weight:bold></code> instead of <code title=""><b></code>, while if it's off, it produces stuff like <code title=""><font color=red></code> instead of <code title=""><span
style=color:red></code>. The issue is that authors might want a mix, like
making the markup as concise as possible while still conforming, and they
can't do that. Changing the flag on a per-command basis doesn't help because
of things like the "restore the values" algorithm, which might create several
different types of style at once and has to use the same styling flag for all
of them. This was discussed back in March in <a href=http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2011-March/030714.html>this
thread</a>, along with a number of other things, but at that time I hadn't
written commands that change multiple styles at once, so it seemed feasible
to ask authors to switch styleWithCSS on or off on a per-command basis.
<li>I haven't defined the "undo" or "redo" commands yet. They look very
complicated to define precisely, and other people are working on them right
now.
</ul>
<p class=XXX>A variety of other issues are also noted in the text, formatted
like this. Feedback would be appreciated on all of them.
<div class=comments>
<p>TODO:
<ul>
<li>Scour browser bug trackers to try spotting issues I haven't thought of.
<li>The wording I use for DOM stuff is not maximally precise. Really I want
DOM Core to define nice concepts that I can xref, like "insert a node". I
don't want to have to explicitly refer to DOM methods like insertBefore()
every time I want to move things.
<li>JavaScript can modify the DOM synchronously in some cases, such as DOM
mutation events and onunload when moving around iframes and objects. This
has to be dealt with somehow. (Pointed out by Ryosuke Niwa of WebKit:
<a href=http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2011-March/030730.html>1</a>
<a href=http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2011-March/030751.html>2</a>)
<li>What happens if you do something like delete a selection or insert text or
whatnot in the middle of a surrogate pair? This could make the content not
serialize through a character encoding change.
<li>Some more thought needs to go into what happens to the selection when you
mutate the DOM. In some cases the results are pretty arbitrary. It might
make sense to do some kind of normalization.
<li>I'm sloppy about handling things like nodes that don't descend from a
Document, comments that are children of a Document, that sort of thing. Not
essential for prototyping, but needs to be cleaned up eventually. Mostly we
should be able to avoid the problems by requiring that everything be
editable, since that immediately means it has to descend from an element or
Document (and cannot be parentless itself).
<li>I need to pay more attention to invisible nodes. These will have no visual
effect, but they'll make many algorithms behave differently: decomposing a
range, block-extending, etc. Also, need to improve the definition to include
things like whitespace-only nodes.
<li>Have to make sure that in all the places where we set a selection, it's
valid.
<li>Redefine things in terms of ranges, not selections.
<li>Allow some type of switch to affect non-editable regions too, perhaps on a
per-command basis.
<li>Things like delete, forwardDelete, insertText need to handle non-BMP
characters.
</ul>
<p>Also TODO: Things that are only implemented by a couple of browsers and may
or may not be useful to spec:
<ul>
<li>decreaseFontSize, increaseFontSize: Only implemented in Gecko and Opera.
<li>contentReadOnly, enableInlineTableEditing, enableObjectResizing, heading,
insertBrOnReturn: MDC docs say not implemented in IE (didn't test).
<li>readOnly: MDC docs say it's a deprecated equivalent of contentReadOnly,
so presumably like useCSS but less popular.
<li>2D-Position, absolutePosition, clearAuthenticationCache, createBookmark,
insertButton, insertFieldset, insertIframe, insertInput*, insertMarquee,
insertSelectDropdown, insertSelectListbox, insertTextarea, liveResize,
multipleSelection, overwrite, print, refresh, saveAs, unbookmark: Mentioned
in MSDN docs but not MDC, so presumably IE-only. Some of these seem
inappropriate or useless, others will bear investigation.
<li>findString, fontSizeDelta, insertNewlineInQuotedContent, justifyNone,
print, transpose: There's code for these in WebKit,
Source/WebCore/editing/EditorCommand.cpp, but I didn't see them mentioned
elsewhere. Some might be worth adding.
<li>unselect: Seems to not be implemented by Gecko or Opera, and IE behaves
oddly: it seems to collapse the selection instead of removing it. Will only
implement if there seems to be demand; it's redundant to
Selection.removeAllRanges() anyway.
</ul>
<p>Things I haven't looked at that multiple browsers implement:
<ul>
<li>redo, undo: Needs review of the Google work on this; will probably be
quite complicated.
</ul>
<p>Also need to look at contenteditable=plaintext-only.
</div>
<p>Things that would be useful to address for the future but aren't important
to fix right now are in comments prefixed with "TODO".
<h2 id=selections>Selections</h2>
<div class=comments>
<p>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.
<p>So I changed the spec to a made-up compromise
that allows some simplification but doesn't constrain authors much. See
<a href=http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2011-June/032072.html>discussion</a>.
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.
<p>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.
<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> 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
to. See <a href=selecttest/Document-open.html>test</a>, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=717339">Mozilla bug</a>, <a href="https://bugs.webkit.org/show_bug.cgi?id=76114">WebKit bug</a>.
<p class=note>A document's selection is a singleton object associated with that
document, so it gets replaced with a new object when <code class=external data-anolis-spec=html title=dom-Document-open><a href=http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#dom-document-open>Document.open()</a></code> is called.
<p class=comments>See <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=15470">bug 15470</a>. 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. I follow
Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.
<p>The user agent should allow the user to change the <a class=external data-anolis-spec=html href=http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#active-document title="active document">active document</a>'s
<a href=#concept-selection title=concept-selection>selection</a>. If the user makes any modification to a <a href=#concept-selection title=concept-selection>selection</a>, the user
agent must create a new <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> with suitable <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a> and <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a>
and associate the <a href=#concept-selection title=concept-selection>selection</a> with this new <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> (not modify the
existing <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>). The user agent must not allow the user to set a
<a href=#concept-selection title=concept-selection>selection</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> to null if it was not already null.
<p class=comments>This matches Firefox 12.0a1, as far as I can tell. Chrome 17
dev and Opera Next 12.00 alpha return copies from getRangeAt(), so the
requirement isn't testable for them. IE9 threw weird exceptions in my testing,
so I match the only browser I could test.
<p>Once a <a href=#concept-selection title=concept-selection>selection</a> is associated with a given <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>, it must continue
to be associated with that same <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> until this specification requires
otherwise.
<p class=note>For instance, if the DOM changes in a way that changes the
<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary points</a>, or a script modifies the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary points</a> of
the <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>, the same <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> object must continue to be associated with
the <a href=#concept-selection title=concept-selection>selection</a>. However, if the user changes the selection or a script
calls <code title=dom-Selection-addRange><a href=#dom-selection-addrange>addRange()</a></code>, the <a href=#concept-selection title=concept-selection>selection</a>
must be associated with a new <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> object, as required elsewhere in this
specification.
<p class=comments>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.
<p>If the <a href=#concept-selection title=concept-selection>selection</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> is not null and is <code class=external data-anolis-spec=dom title=dom-Range-collapsed><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-range-collapsed>collapsed</a></code>, then
the caret position must be at that <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a>. When the
<a href=#concept-selection title=concept-selection>selection</a> 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 <a href=#concept-selection title=concept-selection>selection</a>, the end of the <a href=#concept-selection title=concept-selection>selection</a>,
or somewhere else.
<p class=comments>This short-changes Mac users. See <a href="http://www.w3.org/Bugs/Public/show_bug.cgi?id=13909">bug 13909</a>.
<p>Each <a href=#concept-selection title=concept-selection>selection</a> has a <dfn id=concept-selection-dir title=concept-selection-dir>direction</dfn>,
either <i title="">forwards</i> or <i title="">backwards</i>. If the user creates a
<a href=#concept-selection title=concept-selection>selection</a> by indicating first one <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a> of the <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> and
then the other (such as by clicking on one point and dragging to another), and
the first indicated <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp title=concept-range-bp>boundary point</a> is <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-after title=concept-range-bp-after>after</a> the second, then the
corresponding <a href=#concept-selection title=concept-selection>selection</a> must initially be backwards. Otherwise, it must be
forwards (including if the user didn't create the <a href=#concept-selection title=concept-selection>selection</a>, created it by
selecting an entire part of the page using a keyboard shortcut, etc.).
<p class=XXX>Wouldn't it make more sense if addRange()/removeRange() reset
direction?
<p><a href=#concept-selection title=concept-selection>Selections</a> also have an <dfn id=anchor>anchor</dfn> and a <dfn id=focus>focus</dfn>. If
the <a href=#concept-selection title=concept-selection>selection</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> is null, its <a href=#anchor>anchor</a> and
<a href=#focus>focus</a> are both null. If the <a href=#concept-selection title=concept-selection>selection</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a> is not null
and its <a href=#concept-selection-dir title=concept-selection-dir>direction</a> is forwards, its <a href=#anchor>anchor</a> is the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range title=concept-range>range</a>'s
<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a>, and its <a href=#focus>focus</a> is the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a>. Otherwise, its
<a href=#focus>focus</a> is the <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-start title=concept-range-start>start</a> and its <a href=#anchor>anchor</a> is the
<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-end title=concept-range-end>end</a>.
<pre class=idl>interface <dfn id=selection>Selection</dfn> {
readonly attribute <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a>? <a href=#dom-selection-anchornode title=dom-Selection-anchorNode>anchorNode</a>;
readonly attribute unsigned long <a href=#dom-selection-anchoroffset title=dom-Selection-anchorOffset>anchorOffset</a>;
readonly attribute <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a>? <a href=#dom-selection-focusnode title=dom-Selection-focusNode>focusNode</a>;
readonly attribute unsigned long <a href=#dom-selection-focusoffset title=dom-Selection-focusOffset>focusOffset</a>;
readonly attribute boolean <a href=#dom-selection-iscollapsed title=dom-Selection-isCollapsed>isCollapsed</a>;
void <a href=#dom-selection-collapse title=dom-Selection-collapse>collapse</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> node, unsigned long offset);
void <a href=#dom-selection-collapsetostart title=dom-Selection-collapseToStart>collapseToStart</a>();
void <a href=#dom-selection-collapsetoend title=dom-Selection-collapseToEnd>collapseToEnd</a>();
void <a href=#dom-selection-extend title=dom-Selection-extend>extend</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> node, unsigned long offset);
void <a href=#dom-selection-selectallchildren title=dom-Selection-selectAllChildren>selectAllChildren</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node>Node</a> node);
void <a href=#dom-selection-deletefromdocument title=dom-Selection-deleteFromDocument>deleteFromDocument</a>();
readonly attribute unsigned long <a href=#dom-selection-rangecount title=dom-Selection-rangeCount>rangeCount</a>;
<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#range>Range</a> <a href=#dom-selection-getrangeat title=dom-Selection-getRangeAt>getRangeAt</a>(unsigned long index);
void <a href=#dom-selection-addrange title=dom-Selection-addRange>addRange</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#range>Range</a> range);
void <a href=#dom-selection-removerange title=dom-Selection-removeRange>removeRange</a>(<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#range>Range</a> range);
void <a href=#dom-selection-removeallranges title=dom-Selection-removeAllRanges>removeAllRanges</a>();
<a href=#dom-selection-stringifier title=dom-Selection-stringifier>stringifier</a>;
};</pre>
<p class=comments>See also <a href=http://lxr.mozilla.org/mozilla/source/content/base/public/nsISelection.idl>nsISelection.idl</a>
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.
<div class=note>
<p>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.
<p>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
<code title="">removeRange()</code> and <code title="">removeAllRanges()</code>, and a
<code title="">getRangeAt()</code> method that takes an integer argument that must always be
zero.
</div>
<p>All of the members of the <code><a href=#selection>Selection</a></code> interface are defined in
terms of operations on the <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> object (if any) represented by the object.
These operations can raise exceptions, as defined for the <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#range>Range</a></code> interface; this can therefore result in the
members of the <code><a href=#selection>Selection</a></code> interface raising exceptions as well, in
addition to any explicitly called out below.
<p class=XXX>What happens if you try to put a selection in some node that's not
part of the selection's document? Assuming it works, how is it presented to
the user?
<p class=XXX>What does <code title="">getSelection().getRangeAt(0).detach()</code> do?
<dl class=domintro>
<dt><var title="">selection</var> . <code title=dom-Selection-anchorNode><a href=#dom-selection-anchornode>anchorNode</a></code>
<dd>
<p>Returns the element that contains the start of the selection.
<p>Returns null if there's no selection.
<dt><var title="">selection</var> . <code title=dom-Selection-anchorOffset><a href=#dom-selection-anchoroffset>anchorOffset</a></code>
<dd>
<p>Returns the offset of the start of the selection relative to the element
that contains the start of the selection.
<p>Returns 0 if there's no selection.
<dt><var title="">selection</var> . <code title=dom-Selection-focusNode><a href=#dom-selection-focusnode>focusNode</a></code>
<dd>
<p>Returns the element that contains the end of the selection.
<p>Returns null if there's no selection.
<dt><var title="">selection</var> . <code title=dom-Selection-focusOffset><a href=#dom-selection-focusoffset>focusOffset</a></code>
<dd>
<p>Returns the offset of the end of the selection relative to the element
that contains the end of the selection.
<p>Returns 0 if there's no selection.
</dl>
<p>The <dfn id=dom-selection-anchornode title=dom-Selection-anchorNode><code>anchorNode</code></dfn>
attribute 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=#anchor>anchor</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a>,
or null if the <a href=#anchor>anchor</a> is null.
<p>The <dfn id=dom-selection-anchoroffset title=dom-Selection-anchorOffset><code>anchorOffset</code></dfn>
attribute 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=#anchor>anchor</a>'s
<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-offset title=concept-range-bp-offset>offset</a>, or 0 if the <a href=#anchor>anchor</a> is null.
<p>The <dfn id=dom-selection-focusnode title=dom-Selection-focusNode><code>focusNode</code></dfn>
attribute 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=#focus>focus</a>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a>, or
null if the <a href=#focus>focus</a> is null.
<p>The <dfn id=dom-selection-focusoffset title=dom-Selection-focusOffset><code>focusOffset</code></dfn>
attribute 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=#focus>focus</a>'s
<a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-range-bp-offset title=concept-range-bp-offset>offset</a>, or 0 if the <a href=#focus>focus</a> is null.
<dl class=domintro>
<dt><var title="">collapsed</var> = <var title="">selection</var> . <code title=dom-Selection-isCollapsed><a href=#dom-selection-iscollapsed>isCollapsed</a></code>()
<dd>
<p>Returns true if there's no selection or if the selection is empty.
Otherwise, returns false.
<dt><var title="">selection</var> .
<code title=dom-Selection-collapse><a href=#dom-selection-collapse>collapse</a></code>(<var title="">node</var>,
<var title="">offset</var>)
<dd>
<p>Replaces the selection with a collapsed one at the given position.
<p>Throws an <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#indexsizeerror>IndexSizeError</a></code> exception if <var title="">offset</var> is negative
or longer than <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>.
<dt><var title="">selection</var> . <code title=dom-Selection-collapseToStart><a href=#dom-selection-collapsetostart>collapseToStart</a></code>()
<dd>
<p>Replaces the selection with an empty one at the position of the start of
the current selection.
<p>Throws an <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidstateerror>InvalidStateError</a></code> exception if there is no selection.
<dt><var title="">selection</var> . <code title=dom-Selection-collapseToEnd><a href=#dom-selection-collapsetoend>collapseToEnd</a></code>()
<dd>
<p>Replaces the selection with an empty one at the position of the end of
the current selection.
<p>Throws an <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidstateerror>InvalidStateError</a></code> exception if there is no selection.
<dt><var title="">selection</var> .
<code title=dom-Selection-extend><a href=#dom-selection-extend>extend</a></code>(<var title="">node</var>,
<var title="">offset</var>)
<dd>
<p>Changes the <a href=#focus>focus</a> while leaving the <a href=#anchor>anchor</a> in
place.
<p>Throws an <code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidstateerror>InvalidStateError</a></code> if there's no selection, an
<code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#invalidnodetypeerror>InvalidNodeTypeError</a></code> if <var title="">node</var> is a <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-doctype title=concept-doctype>doctype</a>, and an
<code class=external data-anolis-spec=dom><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#indexsizeerror>IndexSizeError</a></code> exception if <var title="">offset</var> is negative or longer
than <var title="">node</var>'s <a class=external data-anolis-spec=dom href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length title=concept-node-length>length</a>.
</dl>
<p>The <dfn id=dom-selection-iscollapsed title=dom-Selection-isCollapsed><code>isCollapsed</code></dfn>
attribute must return true if the <a href=#anchor>anchor</a> and <a href=#focus>focus</a>
are the same (including if both are null). Otherwise it must return false.