-
Notifications
You must be signed in to change notification settings - Fork 37
/
tests.html
2118 lines (1965 loc) · 97.4 KB
/
tests.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>
<html><head>
<title> Clipboard API and events </title>
<meta charset="UTF-8">
<script src="https://www.w3.org/Tools/respec/respec-w3c-common" class="remove"></script>
<script class='remove'>
var respecConfig = {
// document info
specStatus: "ED",
shortName: "clipboard-apis",
//copyrightStart: "2010",
// process version for this spec is the 2005 Process Document
processVersion: "2015",
edDraftURI: "https://w3c.github.io/clipboard-apis/",
// lcEnd: "2010-08-06",
// extraCSS: ["../css/respec.css"],
/*extraCSS: ["http://dev.w3.org/2009/dap/ReSpec.js/css/respec.css"],*/
NoIDLIn: true,
// editors
editors: [
{ name: "Hallvord R. M. Steen", url: "mailto:[email protected]",
company: "Mozilla", companyURL: "http://www.mozilla.com/",
w3cid: "42065" },
],
otherLinks:[
{
key:'Repository and Participation',
data: [
{value:"Clipboard API spec on Github", href:"https://github.com/w3c/clipboard-apis/"},
{value:"Read past discussions", href:"http://lists.w3.org/Archives/Public/public-webapps/"},
{value:"Browse open bugs", href:"https://github.com/w3c/clipboard-apis/issues"},
{value:"File an Issue", href:"https://github.com/w3c/clipboard-apis/issues/new"}
]
}
],
// WG
wg: "Web Platform Working Group",
wgURI: "https://www.w3.org/WebPlatform/WG/",
license: "w3c-software-doc",
wgPublicList: "public-webapps",
/* add required bibliographic references */
localBiblio: {
'RFC2392': {
title: 'Content-ID and Message-ID Uniform Resource Locators. August 1998. Internet RFC 2392.',
href: 'http://www.ietf.org/rfc/rfc2392.txt',
authors: ['E. Levinson']
},
'HTMLEA': {
title: 'HTML Editing APIs',
href: 'https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html',
authors: ['Aryeh Gregor. W3C Editing APIs CG.']
},
'HTMLLS': {
title: 'HTML Living Standard',
href: 'https://html.spec.whatwg.org/multipage/',
authors: ['Ian Hickson. WHATWG.']
},
'MICROSOFT-CLIP-OP': {
title: 'About DHTML Data Transfer. Microsoft Developer Network.',
href: 'http://msdn.microsoft.com/en-us/library/ms537658.aspx'}
},
wgPatentURI: "https://www.w3.org/2004/01/pp-impl/83482/status",
preProcess: [ function(){ // mark all SCRIPTs for removal
for( var script, scripts=document.getElementsByTagName('script'),i=2;script=scripts[i];i++ )script.className='remove';
}]
};
</script>
</head>
<!--
The source of this spec contains a number of tests for extraction. Here are some requirements for the test framework:
each SCRIPT in this file will be turned into one test case per listed event in Events: comment and per Targets: comment
extra inline HTML code for test case can be given with Test HTML: comment (defaults to single input)
defines clipboard_api_test() method that returns true for pass, false for failure and string for other unexpected statuses.
framework must set up a listener for the relevant event(s) that calls the clipboard_api_test() method with the event object as argument, and check return value
framework will then focus suitable element and trigger relevant event. For paste, data will be given in 'paste data:' comment.
(If there is no "paste data:" instruction, the framework shall clear the clipboard before each test is run)
for cut/copy, framework will select element contents before triggering command
if test function returns undefined, the test is async and will call a result() method the framework must define with pass/fail
An "External pass condition - clipboard data:" comment indicates that the pass/fail result of the test can not be checked from JavaScript, and the framework must check if the expected data is on the clipboard to know if the test passed or failed
If the test code defines triggerTestManually() the tester or framework needs to do specific actions before the test runs.
If the test code defines onTestSetupReady() it must be called after event listeners were defined to trigger the actual test
Note on automation: if there is an external pass condition, the automation framework must check it and inject script that calls result() method with true or false respectively
-->
<body lang="en">
<section id='abstract'>
<p>This document describes APIs for clipboard operations such as copy, cut and
paste in web applications.</p>
</section>
<section id="sotd">
</section>
<section id="conformance"></section>
<section class="informative">
<h2 id="secintro">Introduction</h2>
<p>This specification defines the common clipboard operations of cutting,
copying and pasting, in such a way that they are exposed to Web Applications
and can be adapted to provide advanced functionalities. Its goal is to
provide for compatibility where possible with existing implementations.</p>
</section>
<section class="informative">
<h2 id="Cases">Use Cases</h2>
<p>There are many use cases for being able to change the default clipboard
operations (cut/copy/paste). We have collected
a few samples to demonstrate possible uses, although these may not all be
supported by this specification.</p>
<section><h3 id="Rich">Rich content editing</h3>
<p>When copying text which contains hyperlinks or other structure,
it is often useful to be able to reformat the content to preserve important
information.</p>
</section>
<section><h3>Graphics with built-in semantics</h3>
<p>In order to make web applications which allow the manipulation of rich
text, or of graphic content such as SVG, it is useful to provide a mechanism
that allows for copying more than just the rendered content.</p>
</section>
<section><h3 id="Mathematic">Mathematical information</h3>
<p>With content such as mathematics, simply copying rendered text and pasting
it into another application generally leads to most of the semantics being
lost. MathML often needs to be transformed to be copied as plain text, for example to make sure "to the power of" is shown with the caret "^" sign in a formula plain-text input. The XML source
could also be placed in the clipboard with the appropriate transformation occurring at paste time.</p>
</section>
</section>
<section>
<h2>APIs from other specifications</h2>
<p>Algorithms in this document rely on several APIs defined in other web platform specifications and recommendations. Below is a list of all methods, properties and definitions this document relies on.</p>
<p>The following items are defined in the HTML Living Standard specification. [[!HTMLLS]]</p>
<ul>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#the-datatransferitemlist-interface">DataTransferItemList</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#dom-datatransfer-setdata">setData()</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#dom-datatransfer-getdata">getData()</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#drag-data-store-mode">drag data store mode</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#the-datatransfer-interface">DataTransfer</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#the-drag-data-item-kind">drag data item kind</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#the-drag-data-item-type-string">drag data item type string</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#dom-datatransfer-files">files</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#dom-datatransfer-types">types</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#dom-datatransfer-cleardata">clearData()</a></dfn></li>
<li><dfn><a href="https://html.spec.whatwg.org/multipage/interaction.html#dom-datatransferitemlist-clear">items.clear()</a></dfn></li>
</ul>
<p>The following items are defined in the HTML5 specification. [[!HTML5]]</p>
<ul>
<li><dfn><a href="https://www.w3.org/TR/html/sections.html#the-body-element">the body element</a></dfn></li>
<li>The <dfn><a href="https://www.w3.org/TR/html5/browsers.html#allowed-to-show-a-popup">allowed to show a popup</a></dfn> logic</li>
</ul>
<p>The following items are defined in the DOM specification [[!DOM]]</p>
<ul>
<li><dfn><a href="https://www.w3.org/TR/dom/#dom-event-type">type</a></dfn></li>
<li><dfn><a href="https://www.w3.org/TR/dom/#dom-event-istrusted">isTrusted</a></dfn></li>
<li><dfn><a href="https://www.w3.org/TR/dom/#dom-event-bubbles">bubbles</a></dfn></li>
<li><dfn><a href="https://www.w3.org/TR/dom/#dom-event-cancelable">cancelable</a></dfn></li>
<li><dfn><a href="https://www.w3.org/TR/dom/#interface-event">event interface</a></dfn></li>
<li><dfn><a href="https://www.w3.org/TR/dom/#constructing-events">construct events</a></dfn></li>
<li><dfn><a href="https://www.w3.org/TR/dom/#eventinit">EventInit</a></dfn></li>
</ul>
</section>
<section>
<h3>Terminology</h3>
<p>The term <dfn>editable context</dfn> means any element that is either an <a data-cite="html">editing host</a>, a textarea element, or an input element with its type attribute set to any of <var>text</var>, <var>search</var>, <var>tel</var>, <var>url</var>, <var>email</var>, <var>password</var> or <var>number</var>.</p>
</section>
<section>
<h3>Clipboard actions and events</h3>
<p>This section defines clipboard actions and events and the processing model for event dispatch.</p>
<section>
<h4>Actions</h4>
<p>Each action has two flags called <em>script-triggered</em> and <em>script-may-access-clipboard</em>.</p>
<p>The <dfn>script-triggered</dfn> flag is set if the action runs because of a script, for example a <code>document.execCommand()</code> call. Future scripting APIs that interact with the clipboard should also use these actions, and the <em>script-triggered</em> flag must be set accordingly.</p>
<p>The <dfn>script-may-access-clipboard</dfn> flag is set as follows:</p>
<dl class="switch">
<dt>If action is <em>copy</em> or <em>cut</em> and the script thread is <a>allowed to modify the clipboard</a></dt>
<dd>Set the action's <em>script-may-access-clipboard</em> flag</dd>
<dt>If action is <em>paste</em> and the script thread is <a>allowed to read from clipboard</a></dt>
<dd>set the action's <em>script-may-access-clipboard</em> flag.</dd>
</dl>
<section>
<h4>The copy action</h4>
<div class="note">
<p>When the user initiates a copy action, the implementation <a href="#fire-a-clipboard-event">fires a clipboard event</a> named <em>copy</em>. If the event is not canceled, the selected data will be copied to the clipboard. </p>
<script>
/** ClipboardEvent - events fire on INPUT */
/* Events: copy cut */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="copied text"></form>*/
/* Targets: document 'input_text' */
function clipboard_api_test(e, test_obj, eventType){
var passed = e.type === eventType;
passed = passed && e.target.id==='input_text';
return passed;
}
</script>
<script>
/** ClipboardEvent - events fire on TEXTAREA */
/* Events: copy cut */
/* Test HTML: <form><textarea id="input_text" autofocus onfocus="this.select()">copied text</textarea></form>*/
/* Targets: document 'input_text' */
function clipboard_api_test(e, test_obj, eventType){
var passed = e.type === eventType;
passed = passed && e.target.id==='input_text';
return passed;
}
</script>
<script>
/** setData() method */
/* This test has no selection or cursor, but events should fire anyway (some UAs might require a BeforeCut "preflight" event?) */
/* Events: copy cut */
/* paste data: "pasted text" */
/* External pass condition - clipboard data: "modified text" */
function clipboard_api_test(e){
var passed = false;
e.clipboardData.setData('text/plain', 'modified text');
e.preventDefault();
}
</script>
<script>
/** copy event when there is no selection and script uses setData() */
/* here we have a cursor in an editable context but no selection */
/* Events: copy cut */
/* Test HTML: <form><input id="input_text" autofocus value="copied text"></form>*/
/* Targets: document */
/* paste data: "clipboard text" */
/* External pass condition - clipboard data: "modified text" */
function clipboard_api_test(e){
e.clipboardData.setData('text/plain', 'modified text');
/* The default action is to do nothing (because there is no selection).
* We thus need to prevent the default 'NOOP' action to make the implementation update the clipboard */
e.preventDefault();
}
</script>
<script>
/** cancelling default action, basic test */
/* Events: copy cut */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="copied text"></form>*/
/* Targets: document 'input_text' */
/* paste data: "clipboard text" */
/* External pass condition - clipboard data: "clipboard text" */
function clipboard_api_test(e){
e.preventDefault();
}
</script>
<p>The current selection is not affected. The event bubbles and is cancelable.</p>
<script>
/** copy event does not modify selection */
/* Events: copy */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="copied text"></form>*/
/* Targets: document 'input_text' */
function clipboard_api_test(e, test_obj){
test_obj.step_timeout(function(){
/* what is the "most standardised" way to test this? */
var passed = document.activeElement == document.getElementById('input_text') ;
passed = passed && document.activeElement.selectionStart == 0 && document.activeElement.selectionEnd == document.activeElement.value.length;
result(passed);
}, 10);
}
</script>
<p>A script which uses the event.clipboardData API to control what ends up on the clipboard, needs to cancel the event. Otherwise, the data the script intends to place on the clipboard will be ignored.</p>
<p>If there is no selection, the clipboard is not modified except if the script has added entries in the <a>DataTransferItemList</a>, for example by calling the <a>setData()</a> method, and canceled the event.</p>
</div>
<script>
/** default action of event when there is no selection is noop */
/* Events: copy cut */
/* Test HTML: <form><input id="input_text" onfocus="this.selectionEnd=this.selectionStart" autofocus value="copied text"></form>*/
/* Targets: document */
/* paste data: "clipboard text" */
/* External pass condition - clipboard data: "clipboard text" */
function clipboard_api_test(e){
void(0);
}
</script>
<script>
/** default action of cut event when there is no selection - no text change */
/* Events: copy */
/* Test HTML: <form><input id="input_text" onfocus="this.selectionEnd=this.selectionStart" autofocus value="copied text"></form>*/
/* Targets: document */
/* paste data: "clipboard text" */
function clipboard_api_test(e, test_obj){
var elm=e.target;
test_obj.step_timeout(
function(){
result(elm.value===elm.defaultValue);
},
50
);
}
</script>
<script>
/** getData() method in cut and copy events should return an empty string */
/* Events: cut copy */
function clipboard_api_test(e){
var passed = false;
if(e.clipboardData && e.clipboardData.getData){
if(e.clipboardData.getData('text/plain')==='')passed=true;
}
return passed;
}
</script>
<script>
/** getData() method when type is unsupported should return an empty string */
/* Events: paste */
/* paste data: "pasted text" */
function clipboard_api_test(e){
var passed = false;
if(e.clipboardData && e.clipboardData.getData){
if(e.clipboardData.getData('text/foobarbogustype')==='')passed=true;
}
return passed;
}
</script>
<pre class="example javascript">
document.addEventListener('copy', function(e){
e.clipboardData.setData('text/plain', 'Hello, world!');
e.clipboardData.setData('text/html', '<b>Hello, world!</b>');
e.preventDefault(); // We want our data, not data from any selection, to be written to the clipboard
});
</pre>
<p>The copy action consists of the following steps:</p>
<ol>
<li>
<dl class="switch">
<dt>If the <em>script-triggered</em> flag is set</dt>
<dd>
<dl class="switch">
<dt>If the <em>script-may-access-clipboard</em> flag is unset</dt>
<dd>Return false from the copy action, terminate this algorithm</dd>
</dl>
</dd>
</dl>
</li>
<li><a href="#fire-a-clipboard-event">Fire a clipboard event</a> named <em>copy</em></li>
<li>
<dl class="switch">
<dt>If the event was not canceled</dt>
<dd>Copy the selected contents, if any, to the clipboard. Implementations <em>should</em> create alternate text/html and text/plain clipboard formats when content in a web page is selected.</dd>
<dt>else, if the event was canceled</dt>
<dd>Call the <a>writing contents to the clipboard</a> algorithm, passing on the <a>DataTransferItemList</a> list <em>items</em>, a <em>clear-was-called</em> flag and a <em>types-to-clear</em> list.</dd>
</dl>
</li>
<li>Return true from the copy action</li>
</ol>
</section>
<section>
<h4>The cut action</h4>
<div class="note">
<p>When the user initiates a cut action, the implementation <a href="#fire-a-clipboard-event">fires a clipboard event</a> named <em>cut</em>. In an <a>editable context</a>, if the event is not canceled the action will place the selected data on the clipboard and remove the selection from the document.</p>
<p>The event bubbles and is cancelable.</p>
<!-- Tests are above, under copy. One additional test for preventing default action here: -->
<script>
/** cancelling default action of cut prevents removal of text from editable context */
/* Events: cut */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="copied text"></form>*/
/* Targets: document 'input_text' */
function clipboard_api_test(e, test_obj){
e.preventDefault();
var theTarget=e.target;
test_obj.step_timeout( function(){ var passed = theTarget.value === theTarget.defaultValue; result(passed); }, 10 );
}
</script>
<p>The cut event fires before the selected data is removed.
<script>
/** cut fires before text is removed */
/* Events: cut */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="cut text"></form>*/
/* Targets: document 'input_text' */
function clipboard_api_test(e){
return e.target.value === e.target.defaultValue;
}
</script>
When the cut operation is completed, the selection is collapsed.</p>
<script>
/** cut collapses selection */
/* Events: cut */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="cut text"></form>*/
/* Targets: 'input_text' */
function clipboard_api_test(e, test_obj){
test_obj.step_timeout(function(){
var elm=document.getElementById('input_text');
var passed = elm.selectionStart === 0 && elm.selectionEnd === 0 && elm.value === '';
result( passed );
}, 20);
}
</script>
<p>In a non-<a>editable context</a>, or if there is no selection, the <em>cut action</em> does nothing. The implementation fires the event regardless.
<script>
/** no default action for cut in non-editable context */
/* Events: cut */
/* Targets: document */
/* paste data: "clipboard text" */
/* External pass condition - clipboard data: "clipboard text" */
function clipboard_api_test(e){
/* the point of the test is to make sure that the event fires but the clipboard data is not altered */
/* hence we don't need to to anything here (if the event doesn't fire the test will hang without giving further instructions) */
}
</script>
In this case nothing, the clipboard is not modified except if the script has added entries in the <a>DataTransferItemList</a> and the event is canceled.</p>
<script>
/** setData() in cut event without preventDefault() has no effect when default action is noop */
/* Events: cut */
/* Targets: document */
/* paste data: "clipboard text" */
/* External pass condition - clipboard data: "clipboard text" */
function clipboard_api_test(e){
e.clipboardData.setData('text/plain', 'cut text');
/* NO e.preventDefault() call here. This event's default action is to do nothing since there is no selection. The test verifies that nothing happens to clipboard content. */
}
</script>
<p>Any script which uses the event.clipboardData API to control what the cut event will write to the clipboard also needs to cancel the event. Otherwise, the data the script intends to place on the clipboard will be ignored.</p>
<script>
/** modifying data for cut event in non-editable context with selection */
/* Events: copy cut */
/* Targets: document */
/* Test HTML: <script> function onTestSetupReady(){ if(document.createRange){ var range=document.createRange(); range.selectNodeContents(document.body); window.getSelection().addRange(range);}else if(document.selection){ var range=document.selection.createRange(); range.moveToElementText( document.body ); range.select(); }}<\/script>*/
/* paste data: "clipboard text" */
/* External pass condition - clipboard data: "cut text" */
function clipboard_api_test(e){
e.clipboardData.setData('text/plain', 'cut text');
e.preventDefault(); /* this event's default action is a NOOP since the selection can not be removed. */
}
</script>
<script>
/** setData() method without preventing events's default action */
/* Events: copy cut */
/* External pass condition - clipboard data: "unmodified text" */
/* Test HTML: <form><input autofocus onfocus="this.select()" value="unmodified text"></form>*/
function clipboard_api_test(e){
var passed = false;
if(e.clipboardData && e.clipboardData.setData){
e.clipboardData.setData('text/plain', 'copycutpaste modified text');
}
//e.preventDefault(); // The point of this test is that we do NOT call preventDefault() here.
}
</script>
</div>
<p>The cut action consists of the following steps:</p>
<ol>
<li>
<dl class="switch">
<dt>If the <em>script-triggered</em> flag is set</dt>
<dd>
<dl class="switch">
<dt>If the <em>script-may-access-clipboard</em> flag is unset</dt>
<dd>Return false from the cut action, terminate this algorithm</dd>
</dl>
</dd>
</dl>
</li>
<li><a href="#fire-a-clipboard-event">Fire a clipboard event</a> named <em>cut</em></li>
<li>
<dl class="switch">
<dt>If the event was not canceled</dt>
<dd>
<dl class="switch">
<dt>If there is a selection in an <a>editable context</a> where cutting is enabled</dt>
<dd>
<ol>
<li>Copy the selected contents, if any, to the clipboard. Implementations <em>should</em> create alternate text/html and text/plain clipboard formats when content in a web page is selected.</li>
<li>Remove the contents of the selection from the document and collapse the selection.</li>
<li>Queue tasks to fire any events that should fire due to the modification, see <a href="#integration-with-other-scripts-and-events">interaction with other events</a> for details.</li>
</ol>
</dd>
<dt>Else, if there is no selection or the context is not editable</dt>
<dd>Return false</dd>
<script type="text/javascript">
/** execCommand cut in non-editable context returns false */
/* Events: cut */
/* Test HTML: <p>This is filler text</p> */
/* Targets: document */
var eventFired = false
function clipboard_api_test(e){
var eventFired = true;
}
function triggerTestManually(){
var returnValue = document.execCommand('cut', false, null);
/* The event should have fired, but the return value should be false */
result(eventFired && !returnValue);
}
</script>
</dl>
</dd>
<dt>Else, if the event was canceled</dt>
<dd>Call the <a>writing contents to the clipboard</a> algorithm, passing on the <a>DataTransferItemList</a> list <em>items</em>, a <em>clear-was-called</em> flag and a <em>types-to-clear</em> list.</dd>
</dl>
</li>
<li>Return true from the cut action</li>
</ol>
</section>
<section>
<h4>The paste action</h4>
<div class="note">
<p>When a user initiates a paste action, the implementation <a href="#fire-a-clipboard-event">fires a clipboard event</a> named <em>paste</em>. The event fires before any clipboard data is inserted.</p>
<p>The event bubbles and is cancelable.</p>
<script>
/** events fire on INPUT */
/* Events: paste */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="original text"></form>*/
/* Targets: document 'input_text' */
/* paste data: "pasted text" */
function clipboard_api_test(e, test_obj, eventType){
var passed = e.type === eventType;
passed = passed && e.target.id==='input_text';
return passed;
}
</script>
<script>
/** events fire on TEXTAREA */
/* Events: paste */
/* Test HTML: <form><textarea id="input_text" autofocus onfocus="this.select()">original text</textarea></form>*/
/* Targets: document 'input_text' */
/* paste data: "pasted text" */
function clipboard_api_test(e, test_obj, eventType){
var passed = e.type === eventType;
passed = passed && e.target.id==='input_text';
return passed;
}
</script>
<script>
/** paste event fires before data is inserted */
/* Events: paste */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="original text"></form>*/
/* Targets: document 'input_text' */
/* paste data: "pasted text" */
function clipboard_api_test(e){
var passed = e.type == 'paste' && document.getElementById('input_text').value=='original text';
return passed;
}
</script>
<p>If the cursor is in an editable element, the paste action will insert clipboard data in the most suitable format (if any) supported for the given context.</p>
<script>
/** preventing default action */
/* Events: paste */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="original text"></form>*/
/* Targets: document 'input_text' */
/* paste data: "pasted text" */
function clipboard_api_test(e, test_obj){
e.preventDefault();
var theTarget=e.target;
test_obj.step_timeout(function(){
result(function(){assert_equals(theTarget.value, 'original text');});
}, 10 );
}
</script>
<p> The paste action has no effect in a non-<a>editable context</a>, but the event fires regardless.</p>
<script>
/** paste event fires even in non-editable context */
/* Events: paste */
/* Targets: document */
/* paste data: "pasted text" */
/* Test HTML: <p> </p>*/
function clipboard_api_test(e){
var passed = e.type === 'paste';
return passed;
}
</script>
<p>When pasting, the <a>drag data store mode</a> flag is <em>read-only</em>, hence calling <a>setData()</a> from a <b>paste</b> event handler will not modify the data that is inserted, and not modify the data on the clipboard.</p>
<script>
/** setData() does not modify text that is about to be inserted in a paste event */
/* Events: paste */
/* paste data: "pasted text" */
/* Test HTML: <form><input autofocus></form> */
function clipboard_api_test(e, test_obj){
test_obj.step_timeout(function(){
var passed=false;
passed=e.target.value==='pasted text';
result(passed);
}, 10);
e.clipboardData.setData('text/plain', 'modified text');
}
</script>
<script>
/** setData() does not modify text about to be inserted in a paste event - w preventDefault() */
/* Events: paste */
/* paste data: "pasted text" */
/* Test HTML: <form><input autofocus></form> */
function clipboard_api_test(e, test_obj){
test_obj.step_timeout(function(){
result(function(){
assert_equals(e.target.value, 'pasted text');
});
}, 10);
e.clipboardData.setData('text/plain', 'modified text');
e.preventDefault();
}
</script>
<script>
/** setData() doesn't modify text on the clipboard when called from a paste event */
/* Events: paste */
/* paste data: "pasted text" */
/* Test HTML: <form><input autofocus id="input_text"></form> */
/* External pass condition - clipboard data: "pasted text" */
/* Targets: 'input_text' */
function clipboard_api_test(e){
e.clipboardData.setData('text/plain', 'modified text');
}
</script>
<script>
/** setData() doesn't modify text on the clipboard when called from a paste event - w preventDefault() */
/* Events: paste */
/* paste data: "pasted text" */
/* Test HTML: <form><input autofocus id="input_text"></form> */
/* External pass condition - clipboard data: "pasted text" */
/* Targets: 'input_text' */
function clipboard_api_test(e){
e.clipboardData.setData('text/plain', 'modified text');
e.preventDefault();
}
</script>
<script>
/** getData() method in paste event retrieving plain text */
/* Events: paste */
/* paste data: "pasted text" */
function clipboard_api_test(e){
return e.clipboardData.getData('text/plain')==='pasted text';
}
</script>
<script>
/** getData() method when called outside event handler should return an empty string */
/* Events: paste */
/* paste data: "pasted text" */
function clipboard_api_test(e, test_obj){
var cbData=e.clipboardData;
test_obj.step_timeout( function(){
result(function(){
assert_equals(cbData.getData('text/plain', ''));
});
}, 1 );
}
</script>
<script>
/** getData() method with wrong number of arguments */
/* Events: paste */
/* paste data: "pasted text" */
function clipboard_api_test(e){
result(function(){
assert_throws(new TypeError, function(){
e.clipboardData.getData();
});
/* assert_throws('TypeError', function(){
e.clipboardData.getData('text/plain', 'wrong number of arguments');
});*/
});
}
</script>
<script>
/** getData() method supports legacy 'text' argument */
/* Events: paste */
/* paste data: "pasted text" */
function clipboard_api_test(e){
var passed = false;
if(e.clipboardData && e.clipboardData.getData){
if( e.clipboardData.getData('text')==='pasted text'
&& e.clipboardData.getData('tEXt')==='pasted text' )passed=true;
}
return passed;
}
</script>
<script>
/** getData() supports legacy 'url' argument */
/* Events: paste */
/* paste data: "{'text/uri-list':'http://www.example.com/', 'text/plain': 'example.com'}" */
function clipboard_api_test(e){
var passed = false;
if(e.clipboardData && e.clipboardData.getData){
if( e.clipboardData.getData('url')==='http://www.example.com/'
&& e.clipboardData.getData('uRl')==='http://www.example.com/'
&& e.clipboardData.getData('text/plain') === 'example.com' )passed=true;
}
return passed;
}
</script>
<script>
/** getData() method's type argument not case sensitive */
/* Events: paste */
/* paste data: "pasted text" */
function clipboard_api_test(e){
var passed = false;
if(e.clipboardData && e.clipboardData.getData){
if( e.clipboardData.getData('text/PLAIN')==='pasted text' &&
e.clipboardData.getData('TEXT/PLAIN')==='pasted text' &&
e.clipboardData.getData('Text/Plain')==='pasted text' &&
e.clipboardData.getData('TeXt/PlAin')==='pasted text'
)passed=true;
}
return passed;
}
</script>
</div>
<pre class="example javascript">
document.addEventListener('paste', function(e){
if(e.clipboardData.types.indexOf('text/html') > -1){
processDataFromClipboard(e.clipboardData.getData('text/html'));
e.preventDefault(); // We are already handling the data from the clipboard, we do not want it inserted into the document
}
});
</pre>
<p>For the paste action, the <em>script-may-access-clipboard</em> flag depends on an implementation-specific permission mechanism for determining what sites or apps may read from the clipboard. When a paste action is triggered by a script, the implementation must not make clipboard contents available without the user's permission. If the permission has not already been granted, the permission prompt must include the hostname of the document associated with the script thread.
</p>
<p>The paste action consists of the following steps:</p>
<ol>
<li>
<dl class="switch">
<dt>If the <em>script-triggered</em> flag is set</dt>
<dd>
<dl class="switch">
<dt>If <em>script-may-access-clipboard</em> is unset</dt>
<dd>Return false from the paste action, terminate this algorithm</dd>
<script>
/** paste action returns false in non-editable context */
/* Test HTML: <p>This document has no editable context</p> */
/* paste data: "pasted text" */
function clipboard_api_test(e){
assert_false(document.execCommand('paste', false, null));
}
</script>
</dl>
</dd>
</dl>
</li>
<li><a href="#fire-a-clipboard-event">Fire a clipboard event</a> named <em>paste</em></li>
<li>
<dl class="switch">
<dt>If the event was not canceled</dt>
<dd>
<dl class="switch">
<dt>If there is a selection or cursor in an <a>editable context</a> where pasting is enabled</dt>
<dd><ol>
<li>Insert the most suitable content found on the clipboard, if any, into the context.</li>
<li>Queue tasks to fire any events that should fire due to the modification, see <a href="#integration-with-other-scripts-and-events">interaction with other events</a> for details.</li>
</ol>
</dd>
<dt>Else</dt>
<dd>Return false</dd>
</dl>
</dd>
<dt>Else, if the event was canceled</dt>
<dd>Return false</dd>
</li>
<li>Return true from the action</li>
</section>
</section>
<section>
<h3>Processing model for event dispatch</h3>
<p>To <dfn id="fire-a-clipboard-event">fire a clipboard event of type <em>e</em></dfn>,</p>
<ol>
<li>Let <var>clear-was-called</var> be <var>false</var></li>
<li>Let <var>types-to-clear</var> be an empty list</li>
<li>Let <var>clipboard-entry</var> be the sequence number of the current clipboard content, or null if the OS clipboard does not support sequence numbers</li>
<li>Let <var>trusted</var> be <var>true</var> if the event is generated by the user agent, <var>false</var> otherwise</li>
<script>
/** event isTrusted - generated by UA */
/* Events: copy cut paste */
/* paste data: "pasted text" */
function clipboard_api_test(e){
return e.isTrusted;
}
</script>
<script>
/** event isTrusted - generated by execCommand() */
/* Events: copy cut */
function clipboard_api_test(e){
return e.isTrusted === false;
}
function triggerTestManually(eventType, test_obj){
document.execCommand(eventType, false, null);
}
</script>
<li>Set <var>target</var> as follows:
<dl class="switch">
<dt>If the context is editable:</dt>
<dd>Let <var>target</var> be the element that contains the start of the selection in document order, or <a>the body element</a> if there is no selection or cursor.</dd>
<dt>Else, if the context is not editable</dt>
<dd>Let <var>target</var> be the focused node, or <a>the body element</a> if no node has focus.
</li>
</dl>
<script>
/** event target when selection spans several elements */
/* Events: copy cut */
/* Test HTML: <p id="a" contentEditable="true">This<b id="b"> is </b>filler <b>text</b></p><script>if(document.createRange){var range=document.createRange();range.setStartBefore(document.getElementsByTagName('b')[0].firstChild);range.setEnd(document.getElementById('a').childNodes[3].firstChild,2);window.getSelection().addRange(range);}else if(document.selection){ var range=document.selection.createRange(); range.moveToElementText( document.getElementsByTagName('b')[0] ); range.moveEnd('character', 9); range.select(); } <\/script>*/
/* Targets: document 'a' 'b' */
function clipboard_api_test(e){
var passed = e.target.id === 'b';
return passed;
}
</script>
<script>
/** event target when selection spans several elements */
/* Events: paste */
/* Test HTML: <p id="a" contentEditable="true">This<b id="b"> is </b>filler <b>text</b></p><script>if(document.createRange){var range=document.createRange();range.setStartBefore(document.getElementsByTagName('b')[0].firstChild);range.setEnd(document.getElementById('a').childNodes[3].firstChild,2);window.getSelection().addRange(range);}else if(document.selection){ var range=document.selection.createRange(); range.moveToElementText( document.getElementsByTagName('b')[0] ); range.moveEnd('character', 9); range.select(); } <\/script>*/
/* paste data: "pasted text" */
/* Targets: document 'a' 'b' */
function clipboard_api_test(e){
var passed = e.target.id === 'b';
return passed;
}
</script>
<script>
/** event target when selection spans several elements - reversed selection */
/* Events: copy cut */
/* Test HTML: <p id="a" contentEditable="true">This<b id="b"> is </b>filler <b>text</b></p><script>if(document.createRange){var range=document.createRange();range.setStart(document.getElementsByTagName('b')[0].firstChild, 1);range.setEnd(document.getElementById('a').childNodes[3].firstChild,2);var sel=window.getSelection(); var reversedRange=range.cloneRange(); reversedRange.collapse(false); sel.removeAllRanges(); sel.addRange(reversedRange); sel.extend( range.startContainer, range.startOffset );}else if(document.selection){ document.body.appendChild(document.createTextNode('NOTE: this test case requires document.createRange() and window.getSelection() support'));} <\/script>*/
/* Targets: document 'a' 'b' */
function clipboard_api_test(e){
var passed = e.target.id === 'b';
return passed;
}
</script>
<script>
/** event target when selection spans several elements - reversed selection */
/* Events: paste */
/* Test HTML: <p id="a" contentEditable="true">This<b id="b"> is </b>filler <b>text</b></p><script>if(document.createRange){var range=document.createRange();range.setStart(document.getElementsByTagName('b')[0].firstChild, 1);range.setEnd(document.getElementById('a').childNodes[3].firstChild,2);var sel=window.getSelection(); var reversedRange=range.cloneRange(); reversedRange.collapse(false); sel.removeAllRanges(); sel.addRange(reversedRange); sel.extend( range.startContainer, range.startOffset );}else if(document.selection){ document.body.appendChild(document.createTextNode('NOTE: this test case requires document.createRange() and window.getSelection() support'));} <\/script>*/
/* paste data: "pasted text" */
/* Targets: document 'a' 'b' */
function clipboard_api_test(e){
var passed = e.target.id === 'b';
return passed;
}
</script>
<script>
/** event target when focused element has no text node inside */
/* Events: paste */
/* Test HTML: <form><input id="input_img" autofocus onfocus="this.select()" type="image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAI0lEQVR4nGNkYNjCgARYGBgY/v/3hnAYGbcyMaACdD4jmn4A7CkEc/PaWSMAAAAASUVORK5CYII="></form><script>document.getElementById('input_img').focus()<\/script>*/
/* paste data: "pasted text" */
/* Targets: document 'input_img' */
function clipboard_api_test(e){
if(document.activeElement.id!='input_img')return 'Not testable, input.focus() has not focused the input type=image';
var passed = e.target.id==='input_img';
return passed;
}
</script>
<script>
/** copy event target property - selection in input */
/* Events: copy cut paste */
/* Test HTML: <form><input id="input_text" autofocus onfocus="this.select()" value="copied text"></form>*/
/* Targets: document */
function clipboard_api_test(e){
var passed = e.target === document.getElementById('input_text');
return passed;
}
</script>
<script>
/** event target property - selection in document text */
/* Events: copy cut paste */
/* Test HTML: <div>This text should be selected</div><script>if(document.createRange){var range=document.createRange();range.selectNodeContents(document.getElementsByTagName('div')[0]);window.getSelection().addRange(range);}else if(document.selection){ var range=document.selection.createRange(); range.moveToElementText( document.getElementsByTagName('div')[0] ); range.select(); } <\/script>*/
/* Targets: document */
function clipboard_api_test(e){
var passed = e.target === document.getElementsByTagName('div')[0];
return passed;
}
</script>
<script>
/** event target when no specific element has focus */
/* Events: copy cut paste */
/* Test HTML: <div>This is filler text</div>*/
/* Targets: document */
function clipboard_api_test(e){
var passed = e.target===document.body;
return passed;
}
</script>
</li>
<li>
<dl class="switch">
<dt>If <em>e</em> is <var>paste</var></dt>
<dd>
<p>Set the associated <a>DataTransfer</a> object's <a>drag data store mode</a> flag to <em>read-only</em></p>
<dl class="switch">
<dt>If <var>trusted</var> is <var>true</var>, or the implementation is configured to give script-generated events read access to the OS clipboard</dt>
<dd>
<!-- tests: setData() does not modify text that is about to be inserted in a paste event ++ below -->
<p>For each part on the OS clipboard, carry out these steps:</p>
<dl class="switch">
<dt>If the current clipboard part contains plain text:</dt>
<dd>
<ol>
<li>Ensure the text is in the encoding the scripting engine uses internally</li>
<li>Add one entry for the text to the <a>DataTransferItemList</a> with <a>drag data item kind</a> set to <em>string</em> and <a>drag data item type string</a> set to <em>text/plain</em></li>
<script>
/** clipboardData.items when clipboard has one single text/plain entry */
/* Events: paste */
/* paste data: "pasted text" */
function clipboard_api_test(e){
var passed = e.clipboardData.items && e.clipboardData.items.length === 1;
passed = passed && e.clipboardData.items[0].kind=='string' && e.clipboardData.items[0].type=='text/plain';
return passed;
}
</script>
<script>
/** getting data from clipboardData.items when clipboard has one single text/plain entry */
/* Events: paste */
/* paste data: "pasted text" */
function clipboard_api_test(e){
e.clipboardData.items[0].getAsString( function(s){
result( s==='pasted text' );
} );
}
</script>
<script>
/** setData and clipboardData.items */
/* Events: copy cut */
function clipboard_api_test(e){
e.clipboardData.setData('text/plain', 'modified text');
var passed = e.clipboardData.items && e.clipboardData.items.length === 1;
passed = passed && e.clipboardData.items[0].kind=='string' && e.clipboardData.items[0].type=='text/plain';
return passed;
}
</script>
</ol>
</dd>
<!-- CF_HDROP -->
<dt>If the current clipboard part represents file references:</dt>
<dd>
<ol>
<li>Determine MIME type of referenced files</li>
<li>
Add one entry per file reference to the <a>DataTransferItemList</a> with <a>drag data item kind</a> set to <em>file</em> and <a>drag data item type string</a> set to the corresponding MIME type,
<script>
/** pasting a file */
/* Events: paste */
/* Targets: document */
/* Clipboard data type: file reference: ./support/image.jpg */
/* paste data: "the file 'support/image.jpg'" */
/* Test HTML: <p>To complete this test, copy the './support/image.jpg' file from the OS file manager and paste into this page</p> <div contentEditable="true" id="paste_here"> </div><script>document.getElementById('paste_here').focus()<\/script>*/
function clipboard_api_test(e){
var passed = e.clipboardData.items && e.clipboardData.items.length === 1 ? true : false;
passed = passed && e.clipboardData.items[0].kind=='file' && ( /image\/jpe?g/i.test(e.clipboardData.items[0].type) );
return passed;
}
// TODO: figure out how to automate this test (i.e. find a better cross-platform clipboard library for JRuby..)
</script>
or <code>application/octet-stream</code> if the file's type is unknown.</li>