blob: f2ca5a0a654f270d33d8662f4e8b25369cd98df7 [file] [log] [blame]
Lan Weid98e17b2020-12-08 23:26:531<!DOCTYPE html>
2<meta charset="utf-8">
3<title>Cut and Paste should trigger corresponding InputEvent</title>
4<script src="/resources/testharness.js"></script>
5<script src="/resources/testharnessreport.js"></script>
6<script src="/resources/testdriver.js"></script>
7<script src="/resources/testdriver-actions.js"></script>
8<script src="/resources/testdriver-vendor.js"></script>
9<script type="text/javascript" src="pointerevent_support.js"></script>
10<p>To manually run this test, please follow the steps below:<br/>
111. Select 'plain' => Cut (e.g. Ctrl/Cmd-X) => Paste (e.g. Ctrl/Cmd-V).<br/>
122. Select 'rich' => Cut => Paste.<br/>
133. Select 'prevent' => Paste.<br/>
144. Select 'prevent' => Cut => Select 'normal' => Paste.<br/>
15<br/>
16If a "PASS" result appears the test passes, otherwise it fails</p>
17<textarea id="test1_plain">plain</textarea>
18<p id="test2_editable" contenteditable><b>rich</b></p>
19<p id="test3_editable_prevent" contenteditable>prevent</p>
20<p id="test3_editable_normal" contenteditable>normal</p>
21<script>
22
23function resolveWhen(condition) {
24 return new Promise((resolve, reject) => {
25 function tick() {
26 if (condition())
27 resolve();
28 else
29 requestAnimationFrame(tick.bind(this));
30 }
31 tick();
32 });
33}
34
35let modifier_key = "\uE009";
36if(navigator.platform.includes('Mac'))
37 modifier_key = "\uE03D";
38const commands = {
39 COPY: 'copy',
40 CUT: 'cut',
41 PASTE: 'paste',
42}
43function selectTextCommand(target, command) {
44 let command_key = "";
45 if(command == "copy")
46 command_key = "c";
47 else if (command == "cut")
48 command_key = "x";
49 else if (command == "paste")
50 command_key = "v";
51 return new test_driver.Actions()
52 .pointerMove(0, 0, {origin: target})
53 .pointerDown()
54 .pointerUp()
55 .addTick()
56 .keyDown(modifier_key)
57 .keyDown("a")
58 .keyUp("a")
59 .keyDown(command_key)
60 .keyUp(command_key)
61 .keyUp(modifier_key)
62 .send();
63}
64
65function selectTextCutAndPaste(target1, target2) {
66 return selectTextCommand(target1, commands.CUT).then(() => {
67 return selectTextCommand(target2, commands.PASTE);
68 })
69}
70
71promise_test(async test => {
72 const expectedEventLog = [
73 'cut-[null]', 'beforeinput-deleteByCut', 'input-deleteByCut',
74 'paste-[null]', 'beforeinput-insertFromPaste', 'input-insertFromPaste'];
75 const actualEventLog = [];
76 const text1 = document.getElementById("test1_plain");
77
78 for (let eventType of ['beforeinput', 'input', 'cut', 'paste']) {
79 text1.addEventListener(eventType, test.step_func(function() {
80 if (event.type === 'beforeinput' && event.inputType === 'insertFromPaste') {
81 assert_equals(event.data, 'plain');
82 assert_equals(event.dataTransfer, null);
83 }
84
85 actualEventLog.push(`${event.type}-${event.inputType || '[null]'}`);
86 }));
87 }
88 await selectTextCutAndPaste(text1, text1);
89 await resolveWhen(() => { return actualEventLog.length == expectedEventLog.length });
90 assert_array_equals(actualEventLog, expectedEventLog,
91 `Expected: ${expectedEventLog}; Actual: ${actualEventLog}.`);
92}, 'Event order and data on textarea.');
93
94promise_test(async test => {
95 const expectedEventLog = [
96 'cut-[null]', 'beforeinput-deleteByCut', 'input-deleteByCut',
97 'paste-[null]', 'beforeinput-insertFromPaste', 'input-insertFromPaste'];
98 const actualEventLog = [];
99 const text2 = document.getElementById("test2_editable");
100
101 for (let eventType of ['beforeinput', 'input', 'cut', 'paste']) {
102 text2.addEventListener(eventType, test.step_func(function() {
103 if (event.type === 'beforeinput' && event.inputType === 'insertFromPaste') {
104 assert_equals(event.data, null);
105 assert_equals(event.dataTransfer.getData('text/plain'), 'rich');
106 assert_regexp_match(event.dataTransfer.getData('text/html'), /<b.*>rich<\/b>$/);
107 }
108
109 actualEventLog.push(`${event.type}-${event.inputType || '[null]'}`);
110 }));
111 }
112 await selectTextCutAndPaste(text2, text2);
113 await resolveWhen(() => { return actualEventLog.length == expectedEventLog.length });
114 assert_array_equals(actualEventLog, expectedEventLog,
115 `Expected: ${expectedEventLog}; Actual: ${actualEventLog}.`);
116}, 'Event order and dataTransfer on contenteditable.');
117
118promise_test(async test => {
119 const prevent = document.getElementById('test3_editable_prevent');
120 const normal = document.getElementById('test3_editable_normal');
121 prevent.addEventListener('beforeinput', test.step_func(function() {
122 if (event.inputType === 'deleteByCut' ||
123 event.inputType === 'insertFromPaste') {
124 event.preventDefault();
125 }
126 }));
127
128 normal.addEventListener('input', test.step_func(function() {
129 if (event.inputType === 'insertFromPaste') {
130 assert_equals(prevent.textContent, 'prevent');
131 assert_equals(normal.textContent, 'prevent');
132 }
133 }));
134
135 await selectTextCommand(prevent, commands.PASTE);
136 await selectTextCutAndPaste(prevent, normal);
137 await resolveWhen(() => { return normal.textContent == 'prevent' });
138 assert_equals(prevent.textContent, 'prevent');
139 assert_equals(normal.textContent, 'prevent');
140}, 'preventDefault() should prevent DOM modification but allow clipboard updates.');
141</script>