| Lan Wei | d98e17b | 2020-12-08 23:26:53 | [diff] [blame^] | 1 | <!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/> | 
|  | 11 | 1. Select 'plain' => Cut (e.g. Ctrl/Cmd-X) => Paste (e.g. Ctrl/Cmd-V).<br/> | 
|  | 12 | 2. Select 'rich' => Cut => Paste.<br/> | 
|  | 13 | 3. Select 'prevent' => Paste.<br/> | 
|  | 14 | 4. Select 'prevent' => Cut => Select 'normal' => Paste.<br/> | 
|  | 15 | <br/> | 
|  | 16 | If 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 |  | 
|  | 23 | function 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 |  | 
|  | 35 | let modifier_key = "\uE009"; | 
|  | 36 | if(navigator.platform.includes('Mac')) | 
|  | 37 | modifier_key = "\uE03D"; | 
|  | 38 | const commands = { | 
|  | 39 | COPY: 'copy', | 
|  | 40 | CUT: 'cut', | 
|  | 41 | PASTE: 'paste', | 
|  | 42 | } | 
|  | 43 | function 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 |  | 
|  | 65 | function selectTextCutAndPaste(target1, target2) { | 
|  | 66 | return selectTextCommand(target1, commands.CUT).then(() => { | 
|  | 67 | return selectTextCommand(target2, commands.PASTE); | 
|  | 68 | }) | 
|  | 69 | } | 
|  | 70 |  | 
|  | 71 | promise_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 |  | 
|  | 94 | promise_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 |  | 
|  | 118 | promise_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> |