summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/input-events/input-events-get-target-ranges.html
blob: bbb275d8d34dbeb173bbffa871db0849927246a5 (plain)
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&nbsp;</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&nbsp;</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>