-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsource.html
9134 lines (7194 loc) · 389 KB
/
source.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 rel=stylesheet href=http://www.whatwg.org/style/specification>
<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 { content: 'Note: '; }
.note var { font-style: normal }
.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>
<h1>HTML Editing APIs</h1>
<h2 class="no-num no-toc">Work in Progress — Last Update [DATE: 01 Jan 1901]</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <<a href=mailto:[email protected]>[email protected]</a>>
<dt>Latest version
<dd><a href=http://aryeh.name/spec/editing/editing.html>http://aryeh.name/spec/editing/editing.html</a>
<dt>Version history
<dd><a href=http://aryeh.name/gitweb.cgi?p=editing>Primary copy</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>
</dl>
</div>
<!-- @} -->
<h2 class=no-num>Status of this Document</h2>
<!-- @{ -->
<p>This document is a preliminary draft of a specification for HTML editing
APIs, mainly defining <code>execCommand()</code> and related functions. It
largely replaces the <a
href=http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#editing-apis>Editing
APIs</a> section of the <a href=http://www.whatwg.org/html>HTML</a>
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>,
which is generously provided by the W3C. Feedback that needs discussion should
preferably be sent to <a href=http://lists.whatwg.org/listinfo.cgi/whatwg-whatwg.org>the WHATWG 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>This specification, along with the accompanying JavaScript implementation
and tests, may 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.
<!-- @} -->
<h2 class=no-num>Table of contents</h2>
<!--toc-->
<h2>Introduction</h2>
<!-- @{ -->
<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 [[strong]] and [[em]].) 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<|b>}} for bold
(if the CSS styling flag is false), and convert {{code<|strong>}} and
{{code|<span style="font-weight: bold">}} 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>Tests</h2>
<!-- @{ -->
<p>This specification is developed in tandem with a more or less complete <a
href=implementation.js>JavaScript implementation</a>, which is used for 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 <span>the
<code title>delete</code> command</span>.
<li><a href=forwarddeletetest.html>forwarddeletetest.html</a>: Manual tests
for <span>the <code title>forwardDelete</code> command</span>.
<li><a href=insertlinebreaktest.html>insertlinebreaktest.html</a>: Manual
tests for <span>the <code title>insertLineBreak</code> command</span>.
<li><a href=insertparagraphtest.html>insertparagraphtest.html</a>: Manual
tests for <span>the <code title>insertParagraph</code> command</span>.
<li><a href=inserttexttest.html>inserttexttest.html</a>: Manual tests for
<span>the <code title>insertText</code> command</span>, with <var>value</var>
"a".
<li><a href=inserttext2test.html>inserttext2test.html</a>: Manual tests for
<span>the <code title>insertText</code> command</span>, with <var>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>execCommand()</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>There's a suite of tests for each command (~30–300 at the time of this
writing) that can be run by clicking the "Run tests" button. This can take a
while for some commands. You can also enter your own tests manually in the box
provided. 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>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>queryCommandIndeterm()</code>, <code>queryCommandState()</code>, and
<code>queryCommandValue()</code>, and their values are noted. Then it runs
<code>execCommand()</code>. Finally, it runs
<code>queryCommandIndeterm()</code>, <code>queryCommandState()</code>, and
<code>queryCommandValue()</code> again. Then it adds the output to the table.
<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' <span>state override</span> or <span>value
override</span>. The syntax is JSON, and looks like
<pre>
[<var>HTML input</var>,
[<var>command name 1</var>, <var>command value 1</var>],
[<var>command name 2</var>, <var>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>Commands that are expected to vary significantly based on the value of the
<span>CSS styling flag</span> have two tables of results. The first table 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 in IE or Opera, because they don't
implement <span>the <code title>styleWithCSS</code> command</span>.
<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>execCommand()</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 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.
<p>These tests are really meant to aid spec development by seeing how browsers
behave, not to aid browser development by seeing where the browser doesn't
match the spec. Proper conformance tests would a) record all expected results
statically to avoid browser JS bugs, and b) compare expected and actual results
much more strictly. They would also test a <em>lot</em> more corner cases,
like nested <code title>contenteditable=false</code> regions. It should be
relatively easy to transform the existing tests into proper conformance tests,
but there's not much point until the spec is more stable.
<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.
<!-- @} -->
<h2>Issues</h2>
<!-- @{ -->
<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 [[resval]] 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>[[br]]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 [[br]]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>Probably need to record and restore overrides in some more places.
<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>Commands</h2>
<h3>Properties of commands</h3>
<!-- @{ -->
<p>This specification defines a number of <dfn title=command>commands</dfn>,
identified by <span data-anolis-spec=domcore>ASCII case-insensitive</span>
strings. Each <span>command</span> can have several pieces of data associated
with it:
<ul>
<li><dfn>Action</dfn>: What the <span>command</span> does when executed via
<code>execCommand()</code>. Every <span>command</span> defined in this
specification has an <span>action</span> defined for it in the relevant
section. For example, <span>the <code title>bold</code> command</span>'s
<span>action</span> generally makes the current selection bold, or removes
bold if the selection is already bold. An editing toolbar might provide
buttons that execute the <span>action</span> for a <span>command</span> if
clicked, or a script might run an <span>action</span> without user
interaction to achieve some particular effect.
<li><dfn>Indeterminate</dfn>: A boolean value returned by
<code>queryCommandIndeterm()</code>, depending on the current state of the
document. Generally, a <span>command</span> that has a <span>state</span>
defined will be <span>indeterminate</span> if the <span>state</span> is true
for part but not all of the current selection, and a <span>command</span>
that has a <span>value</span> defined will be <span>indeterminate</span> if
different parts of the selection have different <span
title=value>values</span>. An editing toolbar might display a button or
control in a special way if the <span>command</span> is
<span>indeterminate</span>, like showing a "bold" button as partially
depressed, or leaving a font size selector blank instead of showing the font
size of the current selection. As a rule, a <span>command</span> can only be
<span>indeterminate</span> if its <span>state</span> is false, supposing it
has a <span>state</span>.
<li><dfn>State</dfn>: A boolean value returned by
<code>queryCommandState()</code>, depending on the current state of the
document. The <span>state</span> of a <span>command</span> is true if it is
already in effect, in some sense specific to the <span>command</span>. Most
<span title=command>commands</span> that have a <span>state</span> defined
will take opposite <span title=action>actions</span> depending on whether the
<span>state</span> is true or false, such as making the selection bold if the
<span>state</span> is false and removing bold if the <span>state</span> is
true. Others will just have no effect if the <span>state</span> is true,
like <span>the <code title>justifyCenter</code> command</span>. Still others
will have the same effect regardless, like <span>the <code
title>styleWithCss</code> command</span>. An editing toolbar might display a
button or control differently depending on the <span>state</span> and <span
title=indeterminate>indeterminacy</span> of the <span>command</span>.
<li><dfn>Value</dfn>: A string returned by <code>queryCommandValue()</code>,
depending on the current state of the document. A <span>command</span>
usually has a <span>value</span> instead of a <span>state</span> if the
property it modifies can take more than two different values, like <span>the
<code title>foreColor</code> command</span>. If the <span>command</span> is
<span>indeterminate</span>, its <span>value</span> is generally based on the
start of the selection. Otherwise, in most cases the <span>value</span>
holds true for the entire selection, but see <span>the <code
title>justifyCenter</code> command</span> and <span title="the justifyFull
command">its</span> <span title="the justifyLeft command">three</span> <span
title="the justifyRight command">companions</span> for an exception. An
editing toolbar might display the <span>value</span> of a
<span>command</span> as selected in a drop-down or filled in in a text box,
if the <span>command</span> isn't <span>indeterminate</span>.
<li><dfn>Relevant CSS property</dfn>: This is defined for certain <a
href=#inline-formatting-commands>inline formatting commands</a>, and is used
in algorithms specific to those commands. It is an implementation detail,
and is not exposed to authors. If a <span>command</span> does not have a
<span>relevant CSS property</span> specified, it defaults to null.
</ul>
<!-- @} -->
<h3>Supported commands</h3>
<!-- @{ -->
<p class=comments>If you try doing anything with an unrecognized command, IE9
throws an "Invalid argument" exception, and Firefox 6.0a2 throws
NS_ERROR_NOT_IMPLEMENTED. Chrome 14 dev and Opera 11.11 both just return a
useless value. I go with IE/Gecko, although of course with a standard
exception type.
<p>Some <span title=command>commands</span> will be <dfn>supported</dfn> in a
given user agent, and some will not. All <span title=command>commands</span>
defined in this specification must be <span>supported</span>, except optionally
<span>the <code title>copy</code> command</span>, <span>the <code
title>cut</code> command</span>, and/or <span>the <code title>paste</code>
command</span>. Additional <span title=command>commands</span> can also be
<span>supported</span>, but implementers should prefix any nonstandard
<span>command</span> names with a vendor-specific string (e.g., "ms", "moz",
"webkit", "opera").
<p class=comments>I.e., no trying to look good on lazy conformance tests by
just sticking in a stub implementation that does nothing.
<p>A <span>command</span> that does absolutely nothing in a particular user
agent, such that <code>execCommand()</code> never has any effect and
<code>queryCommandEnabled()</code> and <code>queryCommandIndeterm()</code> and
<code>queryCommandState()</code> and <code>queryCommandValue()</code> each
return the same value all the time, must not be <span>supported</span>.
<p>In a particular user agent, every <span>command</span> must be consistently
either <span>supported</span> or not. Specifically, a user agent must not
permit one page to see the same <span>command</span> sometimes
<span>supported</span> and sometimes not over the course of the same browsing
session, unless the user agent has been upgraded or reconfigured in the middle
of a session. However, user agents may treat the same <span>command</span> as
<span>supported</span> for some pages and not others, e.g., if the
<span>command</span> is only supported for certain origins for security
reasons.
<p>Authors can tell whether a <span>command</span> is <span>supported</span>
using <code>queryCommandSupported()</code>.
<!-- @} -->
<h3>Enabled commands</h3>
<!-- @{ -->
<p>At any given time, a <span>supported</span> command can be either
<dfn>enabled</dfn> or not. Authors can tell whether a <span>command</span> is
currently <span>enabled</span> using <code>queryCommandEnabled()</code>. <span
title=command>Commands</span> that are not <span>enabled</span> do nothing, as
described in the definitions of the various methods that invoke <span
title=command>commands</span>.
<div class=comments>
<p>Testing with bold:
<p>IE10PP2 seems to return true if the active range's start node is editable,
false otherwise.
<p>Firefox 6.0a2 seems to always return true if there's anything editable on the
page, and throw otherwise. (This is <a
href=https://bugzilla.mozilla.org/show_bug.cgi?id=676401>bug 676401</a>.)
<p>Chrome 14 dev seems to behave the same as IE10PP2.
<p>Opera 11.11 seems to always return true if there's anything editable on the
page, and false otherwise.
<p>Firefox and Opera behave more or less uselessly. IE doesn't make much sense,
in that whether a command is enabled seems meaningless: it will execute it on
all nodes in the selection, editable or not. Chrome's definition makes sense
in that it will only run the command if it's enabled, but it doesn't make much
sense to only have the command run if the start is editable.
<p>It's not clear to me what the point of this method is. There's no way we're
going to always return true if the command will do something and false if it
won't. I just stuck with a really conservative definition that happens to be
convenient: if there's nothing selected, obviously nothing will work, and we
want to bail out early in that case anyway because all the algorithms will talk
about the active range. If there are use-cases for it to be more precise, I
could make it so.
</div>
<p>Among <span title=command>commands</span> defined in this specification,
those listed in <a href=#miscellaneous-commands>Miscellaneous commands</a> are
always <span>enabled</span>. The other <span title=command>commands</span>
defined here are <span>enabled</span> if the <span>active range</span> is not
null, and disabled otherwise.
<!-- @} -->
<h2>Methods of the <code data-anolis-spec=html>HTMLDocument</code> interface</h2>
<!-- @{ -->
<p class=comments>TODO: Define behavior for <var>show UI</var>.
<p>When the <dfn title=execCommand()><code>execCommand(<var>command</var>,
<var>show UI</var>, <var>value</var>)</code></dfn> method on the <code
data-anolis-spec=html>HTMLDocument</code> interface is invoked, the user agent
must run the following steps:
<ol>
<li>If only one argument was provided, let <var>show UI</var> be false.
<li>If only one or two arguments were provided, let <var>value</var> be the
empty string.
<li>If <var>command</var> is not <span>supported</span>, raise a
[[NOT_SUPPORTED_ERR]] exception.
<li>
<p class=comments>I'm just speccing INVALID_ACCESS_ERR for consistency. I
don't expect real-world commands are likely to not have an action defined,
but you never know.
<p>If <var>command</var> has no <span>action</span>, raise an
[[INVALID_ACCESS_ERR]] exception.
<p class=note>No such <span>command</span> is defined in this specification.
<li>
<p class=comments>I didn't research this closely, but at a first glance, this
is possibly how Chrome 14 dev and Opera 11.11 behave. Maybe also Firefox
6.0a2, except it throws if the command isn't enabled, I think. IE9 returns
true in at least some cases even if the command is disabled. TODO: Is this
right? Maybe we should be returning false in other cases too?
<p>If <var>command</var> is not <span>enabled</span>, return false.
<li>Take the <span>action</span> for <var>command</var>, passing
<var>value</var> to the instructions as an argument.
<li>Return true.
</ol>
<p>When the <dfn
title=queryCommandEnabled()><code>queryCommandEnabled(<var>command</var>)</code></dfn>
method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
invoked, the user agent must run the following steps:
<ol>
<li>If <var>command</var> is not <span>supported</span>, raise a
[[NOT_SUPPORTED_ERR]] exception.
<li>Return true if <var>command</var> is <span>enabled</span>, false
otherwise.
</ol>
<div class=comments>
<p>What happens if you call queryCommand(Indeterm|State|Value)() on a command
where it makes no sense?
<p>IE9 consistently returns false for all three.
<p>Firefox 6.0a2 consistently throws NS_ERROR_FAILURE for indeterm/state if not
supported, and returns an empty string for value. Exceptions include unlink
(seems to always return indeterm/state false), and styleWithCss/useCss (throw
NS_ERROR_FAILURE even for value).
<p>Chrome 14 dev returns false for all three, and even does this for unrecognized
commands. It also always defines value if state is defined: it returns the
state cast to a string, either "true" or "false".
<p>Opera 11.11 returns false for state and "" for value (it doesn't support
indeterm). Like Chrome, this is even for unrecognized commands.
<p>Gecko's behavior is the most useful. If the author tries querying some aspect
of a command that makes no sense, they shouldn't receive a value that looks
like it might make sense but is actually just a constant. However, I go even
further than Gecko: I require exceptions even for value, since doing otherwise
makes no sense.
</div>
<p>When the <dfn
title=queryCommandIndeterm()><code>queryCommandIndeterm(<var>command</var>)</code></dfn>
method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
invoked, the user agent must run the following steps:
<ol>
<li>If <var>command</var> is not <span>supported</span>, raise a
[[NOT_SUPPORTED_ERR]] exception.
<li>If <var>command</var> has no <span
title=indeterminate>indeterminacy</span>, raise an [[INVALID_ACCESS_ERR]]
exception.
<li>If <var>command</var> is not <span>enabled</span>, return false.
<li>Return true if <var>command</var> is <span>indeterminate</span>,
otherwise false.
</ol>
<p>When the <dfn
title=queryCommandState()><code>queryCommandState(<var>command</var>)</code></dfn>
method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
invoked, the user agent must run the following steps:
<ol>
<li>If <var>command</var> is not <span>supported</span>, raise a
[[NOT_SUPPORTED_ERR]] exception.
<li>If <var>command</var> has no <span>state</span>, raise an
[[INVALID_ACCESS_ERR]] exception.
<li>If <var>command</var> is not <span>enabled</span>, return false.
<li>If the <span>state override</span> for <var>command</var> is set, return
it.
<li>Return true if <var>command</var>'s <span>state</span> is true, otherwise
false.
</ol>
<p class=comments>Firefox 6.0a2 always throws an exception when this is
called. Opera 11.11 seems to return false if there's nothing editable on the
page, which is unhelpful. The spec follows IE9 and Chrome 14 dev. The reason
this is useful, compared to just running one of the other methods and seeing if
you get a NOT_SUPPORTED_ERR, is that other methods might throw different
exceptions for other reasons. It's easier to check a boolean than to check
exception types, especially since as of June 2011 UAs aren't remotely
consistent on what they do with unsupported commands.
<p>When the <dfn
title=queryCommandSupported()><code>queryCommandSupported(<var>command</var>)</code></dfn>
method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
invoked, the user agent must return true if <var>command</var> is
<span>supported</span>, and false otherwise.
<p>When the <dfn
title=queryCommandValue()><code>queryCommandValue(<var>command</var>)</code></dfn>
method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
invoked, the user agent must run the following steps:
<ol>
<li>If <var>command</var> is not <span>supported</span>, raise a
[[NOT_SUPPORTED_ERR]] exception.
<li>If <var>command</var> has no <span>value</span>, raise an
[[INVALID_ACCESS_ERR]] exception.
<li>
<p class=comments>This is what Firefox 6.0a2 and Opera 11.11 seem to do. Chrome 14 dev
seems to return the string "false", and IE9 seems to return boolean false.
<p>If <var>command</var> is not <span>enabled</span>, return the empty
string.
<li>
<p class=comments>Yuck. This is incredibly messy, as are lots of other
fontSize-related things, but I don't want to define a whole second notion of
value for the sake of a single command . . .
<p>If <var>command</var> is "fontSize" and its <span>value override</span>
is set, convert the <span>value override</span> to an integer number of
pixels and return the <span>legacy font size for</span> the result.
<li>If the <span>value override</span> for <var>command</var> is set, return
it.
<li>Return <var>command</var>'s <span>value</span>.
</ol>
<p>All of these methods must treat their <var>command</var> argument <span
data-anolis-spec=domcore title="ASCII case-insensitive">ASCII
case-insensitively</span>.
<div class=note>
<p>The methods in this section have mostly been designed so that the following
invariants hold after <code title>execCommand()</code> is called, assuming it
didn't throw an exception:
<ul>
<li><code title>queryCommandIndeterm()</code> will return false (or throw an
exception).
<li><code title>queryCommandState()</code> will return the opposite of what it did
before <code title>execCommand()</code> was called (or throw an exception).
<li><code title>queryCommandValue()</code> will return something equivalent to the
value passed to <code title>execCommand()</code> (or throw an exception).
"Equivalent" here needs to be construed broadly in some cases, such as
<code title>fontSize</code>.
</ul>
<p>The first two points do not always hold for <code title>strikethrough</code>
or <code title>underline</code>, because it can be impossible to unset
text-decoration in CSS. Also, by design, the state of <code
title>insertOrderedList</code> and <code title>insertUnorderedList</code> might
be true both before and after calling, because they only remove one level of
indentation. <code title>unlink</code> should set the value to null. And
finally, the state of the various <code title>justify</code> commands should
always be true after calling, and the value should always be the appropriate
string ("center", "justify", "left", or "right"). Any other deviations from
these invariants are bugs in the specification.
</div>
<!-- @} -->
<h2>Common definitions</h2>
<!-- @{ -->
<p>An <dfn>HTML element</dfn> is an [[element]] whose [[namespace]] is the
[[htmlnamespace]].
<p>A <dfn>prohibited paragraph child name</dfn> is "address", "article",
"aside", "blockquote", "caption", "center", "col", "colgroup", "dd", "details",
"dir", "div", "dl", "dt", "fieldset", "figcaption", "figure", "footer", "form",
"h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "li", "listing",
"menu", "nav", "ol", "p", "plaintext", "pre", "section", "summary", "table",
"tbody", "td", "tfoot", "th", "thead", "tr", "ul", or "xmp".
<p class=comments>These are all the things that will close a <p> if found as
a descendant. I think. Plus table stuff, since that can't be a descendant of
a p either, although it won't auto-close it.
<p>A <dfn>prohibited paragraph child</dfn> is an <span>HTML element</span>
whose [[localname]] is a <span>prohibited paragraph child name</span>.
<p class=comments>The block/inline node definitions are CSS-based. "Prohibited
paragraph child" is conceptually similar to "block node", but based on the
element name. Generally we want to use block/inline node when we're interested
in the visual effect, and prohibited paragraph children when we're concerned
about parsing or semantics. TODO: Audit all "block node" usages to see if they
need to become "visible block node", now that block nodes can be invisible (if
they descend from display: none).
<p>A <dfn>block node</dfn> is either an [[element]] whose "display" property
does not have [[resval]] "inline" or "inline-block" or "inline-table" or
"none", or a [[document]], or a [[documentfragment]].
<p>An <dfn>inline node</dfn> is a [[node]] that is not a <span>block
node</span>.
<p>An <dfn>editing host</dfn> is a [[node]] that is either an [[element]] with
a <code data-anolis-spec=html title=attr-contenteditable>contenteditable</code>
attribute set to the true state, or the [[element]] [[child]] of a [[document]]
whose <code data-anolis-spec=html>designMode</code> is enabled.
<p>Something is <dfn>editable</dfn> if it is a [[node]] which is not an
<span>editing host</span>, does not have a <code data-anolis-spec=html
title=attr-contenteditable>contenteditable</code> attribute set to the false
state, and whose [[parent]] is an <span>editing host</span> or
<span>editable</span>.
<p class=note>An <span>editable</span> node cannot be a [[document]] or
[[documentfragment]], its [[parent]] cannot be null, and it must descend from
either an [[element]] or a [[document]].
<p>The <dfn>editing host of</dfn> <var>node</var> is null if <var>node</var> is
neither <span>editable</span> nor an <span>editing host</span>; <var>node</var>
itself, if <var>node</var> is an <span>editing host</span>; or the nearest
[[ancestor]] of <var>node</var> that is an <span>editing host</span>, if
<var>node</var> is <span>editable</span>.
<p>Two [[nodes]] are <dfn>in the same editing host</dfn> if the <span>editing
host of</span> the first is non-null and the same as the <span>editing host
of</span> the second.
<p class=note>Barring bugs, the algorithms here will not alter the attributes
of a non-editable element; will not remove a non-editable node from its parent
(except to immediately give it a new parent in the same editing host); and will
not add, remove, or reorder children of a node unless it is either editable or
an editing host. An editing host is never editable, so authors are assured
that editing commands will only modify the editing host's contents and not the
editing host itself.
<p>A <dfn>collapsed line break</dfn> is a [[br]] that begins a line box which
has nothing else in it, and therefore has zero height.
<p class=XXX>Is this a good definition at all? I mean things like
<p>foo<br></p>, or the second one in <p>foo<br><br></p>.
The way I test it is by adding a text node after it containing a zwsp; if that
changes the offsetHeight of its nearest non-inline ancestor, I deem it
collapsed. But what if it happens to be display: none right now, for instance?
Or its ancestor has a fixed height? Would it be better to use some DOM-based
definition?
<p class=comments>TODO: The thing about li is a not very nice hack. The issue
is that an li won't collapse even if it has no children at all, but that's not
true in all browsers (at least not in Opera 11.11), and also it breaks
assumptions elsewhere. E.g., if it gets turned into a p.
<p>An <dfn>extraneous line break</dfn> is a [[br]] that has no visual effect,
in that removing it from the DOM would not change layout, except that a [[br]]
that is the sole child of an [[li]] is not extraneous.
<p class=XXX>Also possibly a bad definition. Again, I test by just removing it
and seeing what happens. (Actually, setting display: none, so that it doesn't
mess up ranges.)
<p>A <dfn>whitespace node</dfn> is either a [[text]] node whose [[cddata]] is
the empty string; or a [[text]] node whose [[cddata]] consists only of one or
more tabs (0x0009), line feeds (0x000A), carriage returns (0x000D), and/or
spaces (0x0020), and whose [[parent]] is an [[element]] whose [[resval]] for
"white-space" is "normal" or "nowrap"; or a [[text]] node whose [[cddata]]
consists only of one or more tabs (0x0009), carriage returns (0x000D), and/or
spaces (0x0020), and whose [[parent]] is an [[element]] whose [[resval]] for
"white-space" is "pre-line".
<p><var>node</var> is a <dfn>collapsed whitespace node</dfn> if the following
algorithm returns true:
<p class=XXX>This definition is also bad. It's a crude attempt to emulate
CSS2.1 16.6.1, but leaving out a ton of the subtleties. I actually don't want
the exact CSS definitions, because those depend on things like where lines are
broken, but I'm not sure this definition is right anyway. E.g., what about a
pre-line text node consisting of a single line break that's at the end of a
block? That collapses, same idea as an extraneous line break. We could also
worry about nodes containing only zwsp or such if we wanted, or display: none,
or . . .
<ol>
<li>If <var>node</var> is not a <span>whitespace node</span>, return false.
<li>If <var>node</var>'s [[cddata]] is the empty string, return true.
<li>Let <var>ancestor</var> be <var>node</var>'s [[parent]].
<li>If <var>ancestor</var> is null, return true.
<li>If the "display" property of some [[ancestor]] of <var>node</var> has
[[resval]] "none", return true.
<li>While <var>ancestor</var> is not a <span>block node</span> and its
[[parent]] is not null, set <var>ancestor</var> to its [[parent]].