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
|
<!DOCTYPE html>
<meta charset="utf-8">
<title>InputEvent.getTargetRanges() behavior</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<p>To manually run this test, please follow the steps below:<br/>
1. Place caret at the end of 'hel<i>lo wo</i><b>rld</b>'.<br/>
2. Press Ctrl-Backspace (Alt-Backspace on macOS) to delete word backwards.<br/>
3. Place caret at the end of 'test2' => Press 'a' key.<br/>
4. Select 'test2a' => Press 'b' key.<br/>
5. Select 'b' => Bold text through context menu or Command-b on macOS.<br/>
6. Place caret at the end of 'test3' => Press 'a' key => Press Backspace key.<br/>
<br/>
If a "PASS" result appears the test passes, otherwise it fails</p>
<p id="test1_editable" contenteditable>hel<i>lo wo</i><b>rld</b></p>
<p id="test2_editable" contenteditable>test2</p>
<textarea id="test3_plain">test3</textarea>
<script>
function resolveWhen(condition) {
return new Promise((resolve, reject) => {
function tick() {
if (condition())
resolve();
else
requestAnimationFrame(tick.bind(this));
}
tick();
});
}
let modifier_key = "\uE009";
if(navigator.platform.includes('Mac'))
modifier_key = "\uE03D";
const commands = {
COPY: 'copy',
CUT: 'cut',
PASTE: 'paste',
SELECTALL: 'select all',
DELETEALL: 'delete all',
BOLD: 'bold',
}
const backspace = "\uE003";
function clickOnTarget(target) {
return new test_driver.Actions()
.pointerMove(0, 0, {origin: target})
.pointerDown()
.pointerUp()
.send();
}
function sendTextCommand(command) {
let command_key = "";
if(command == "copy")
command_key = "c";
else if (command == "cut")
command_key = "x";
else if (command == "paste")
command_key = "v";
else if (command == "select all")
command_key = "a";
else if (command == "delete all")
command_key = backspace;
else if (command == "bold")
command_key = "b";
return new test_driver.Actions()
.keyDown(modifier_key)
.keyDown(command_key)
.keyUp(command_key)
.keyUp(modifier_key)
.send();
}
function sendTextCommandAtTarget(target, command) {
return clickOnTarget(target).then(() => {
return sendTextCommand(command);
});
}
function addTextAtTarget(target, char) {
return test_driver.send_keys(target, char);
}
promise_test(async test => {
const test1_editable = document.getElementById('test1_editable');
let lastBeforeInput;
test1_editable.addEventListener('beforeinput', test.step_func(function() {
assert_equals(event.inputType, 'deleteWordBackward');
const ranges = event.getTargetRanges();
assert_equals(ranges.length, 1);
const range = ranges[0];
assert_true(range instanceof StaticRange);
assert_equals(range.startOffset, 3);
assert_equals(range.startContainer.textContent, 'lo wo');
assert_equals(range.endOffset, 3);
assert_equals(range.endContainer.textContent, 'rld');
assert_equals(test1_editable.innerHTML, 'hel<i>lo wo</i><b>rld</b>');
lastBeforeInput = event;
}));
test1_editable.addEventListener('input', test.step_func(function() {
assert_equals(event.inputType, 'deleteWordBackward');
assert_equals(test1_editable.innerHTML, 'hel<i>lo </i>');
assert_equals(lastBeforeInput.inputType, 'deleteWordBackward');
assert_equals(lastBeforeInput.getTargetRanges().length, 0,
'getTargetRanges() should be empty after the event has finished dispatching.');
}));
await sendTextCommandAtTarget(test1_editable, commands.DELETEALL);
await resolveWhen(() => { return test1_editable.innerHTML == 'hel<i>lo </i>' });
}, 'getTargetRanges() returns correct range and cleared after dispatch.');
promise_test(async test => {
const expectedEventLog = ['test2-5-test2-5', 'test2a-0-test2a-6', 'b-0-b-1'];
const actualEventLog = [];
const test2_editable = document.getElementById('test2_editable');
test2_editable.addEventListener('beforeinput', test.step_func(function() {
const ranges = event.getTargetRanges();
assert_equals(ranges.length, 1);
const range = ranges[0];
actualEventLog.push(
`${range.startContainer.textContent}-${range.startOffset}-${range.endContainer.textContent}-${range.endOffset}`);
}));
await addTextAtTarget(test2_editable, "a");
await sendTextCommandAtTarget(test2_editable, commands.SELECTALL);
await addTextAtTarget(test2_editable, "b");
await sendTextCommandAtTarget(test2_editable, commands.SELECTALL);
await sendTextCommand(commands.BOLD);
await resolveWhen(() => { return actualEventLog.length == expectedEventLog.length });
assert_array_equals(actualEventLog, expectedEventLog,
`Expected: ${expectedEventLog}; Actual: ${actualEventLog}.`);
}, 'Actions other than deletion should have current selection as target ranges.');
promise_test(async test => {
const test3_plain = document.getElementById('test3_plain');
let event_type;
test3_plain.addEventListener('beforeinput', test.step_func(function() {
assert_equals(event.getTargetRanges().length, 0,
'getTargetRanges() should return empty array on textarea.');
if (event.inputType === 'deleteContentBackward')
event_type = event.inputType;
}));
await addTextAtTarget(test3_plain, "a");
await addTextAtTarget(test3_plain, backspace);
await resolveWhen(() => { return event_type == 'deleteContentBackward' });
}, 'Textarea should have empty target range.');
</script>
|