Skip to content

Commit 7b1e319

Browse files
nt1mJarred-Sumner
authored andcommitted
walmart.com/wallet focuses phone number field when attempting to add a credit card
https://bugs.webkit.org/show_bug.cgi?id=284630 rdar://139075809 Reviewed by Ryosuke Niwa. Setting the selection should not focus unless there is an existing selection. This matches other browsers while preserving the principle that focus & selection must be in sync (by neither focusing or selecting). Notably, these APIs now have this behavior: - element.setSelectionRange() - element.selectionStart/selectionEnd setters - element.setRangeText() These APIs preserve the old behavior by focusing the text controls before selecting: - element.select() - accessibility APIs Here is the relevant Blink commits for the corresponding change there: chromium/chromium@5300153 In order to limit the risk of breakage in older macOS/iOS apps, this behavior is put behind a linked-on-or-after check. * LayoutTests/editing/async-clipboard/resources/async-clipboard-helpers.js: (async writeToClipboardUsingDataTransfer): * LayoutTests/editing/deleting/5290534.html: * LayoutTests/editing/inserting/4960120-1.html: * LayoutTests/editing/inserting/insert-text-into-text-field.html: * LayoutTests/editing/pasteboard/data-transfer-get-data-on-drop-plain-text.html: * LayoutTests/editing/pasteboard/data-transfer-get-data-on-paste-plain-text.html: * LayoutTests/editing/pasteboard/drag-drop-input-textarea.html: * LayoutTests/editing/pasteboard/drag-drop-url-text.html: * LayoutTests/editing/pasteboard/pasting-tabs.html: * LayoutTests/editing/selection/4975120.html: * LayoutTests/editing/selection/5497643-expected.txt: * LayoutTests/editing/selection/5497643.html: * LayoutTests/editing/selection/delete-selection-with-disconnected-extent.html: * LayoutTests/editing/selection/delete-word-granularity-text-control.html: * LayoutTests/editing/selection/deleteFromDocument-shadow-tree-crash.html: * LayoutTests/editing/selection/select-iframe-focusin-document-crash.html: * LayoutTests/editing/selection/selection-setSelectionRange-frameselection-expected.txt: Added. * LayoutTests/editing/selection/selection-setSelectionRange-frameselection.html: Added. * LayoutTests/editing/selection/setting-selection-does-not-focus-unless-selected-expected.txt: Added. * LayoutTests/editing/selection/setting-selection-does-not-focus-unless-selected.html: Added. * LayoutTests/editing/selection/shrink-selection-after-shift-pagedown.html: * LayoutTests/fast/css/content/content-on-focus-change.html: * LayoutTests/fast/events/context-no-deselect.html: * LayoutTests/fast/forms/datalist/datalist-idTargetChanged-crash.html: * LayoutTests/fast/forms/input-appearance-selection.html: * LayoutTests/fast/forms/input-delete.html: * LayoutTests/fast/forms/input-placeholder-visibility-2-expected.html: * LayoutTests/fast/forms/paste-into-textarea.html: * LayoutTests/fast/forms/textarea-arrow-navigation.html: * LayoutTests/fast/rendering/render-compositor-null-layer-crash.html: * LayoutTests/fast/text-extraction/basic-text-extraction.html: * LayoutTests/fast/text/out-of-flow-line-break-crash.html: * LayoutTests/imported/w3c/web-platform-tests/html/interaction/focus/processing-model/textarea-scroll-selection-expected.txt: * LayoutTests/resources/accessibility-helper.js: * Source/WTF/wtf/cocoa/RuntimeApplicationChecksCocoa.h: * Source/WebCore/accessibility/AccessibilityRenderObject.cpp: (WebCore::AccessibilityRenderObject::setSelectedTextRange): (WebCore::AccessibilityRenderObject::setSelectedVisiblePositionRange const): * Source/WebCore/html/HTMLTextFormControlElement.cpp: (WebCore::HTMLTextFormControlElement::select): (WebCore::HTMLTextFormControlElement::setSelectionRange): Canonical link: https://commits.webkit.org/287851@main
1 parent d43024e commit 7b1e319

File tree

38 files changed

+186
-29
lines changed

38 files changed

+186
-29
lines changed

LayoutTests/editing/async-clipboard/resources/async-clipboard-helpers.js

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function writeToClipboardUsingDataTransfer(data) {
4545
const input = document.createElement("input");
4646
document.body.appendChild(input);
4747
input.value = "a";
48+
input.focus();
4849
input.setSelectionRange(0, 1);
4950
input.addEventListener("copy", event => {
5051
for (const type of Object.keys(data))

LayoutTests/editing/deleting/5290534.html

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
var search = document.getElementById("search");
1818
search.setSelectionRange(0, 0);
19+
search.focus();
1920
document.execCommand("InsertText", false, "x");
2021
if (search.value != "x")
2122
log("Failure: text wasn't added to the search field.");

LayoutTests/editing/inserting/4960120-1.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
<script>
55
var textarea = document.getElementById("textarea");
66
textarea.setSelectionRange(0, 0);
7-
7+
textarea.focus();
88
document.execCommand("InsertLineBreak");
99
</script>

LayoutTests/editing/inserting/insert-text-into-text-field.html

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
testRunner.dumpAsText();
2727

2828
var input = document.getElementById("input");
29+
input.focus();
2930
input.setSelectionRange(1, 1);
3031
document.execCommand("InsertHTML", false, "b");
3132
if (input.value == "ab")

LayoutTests/editing/pasteboard/data-transfer-get-data-on-drop-plain-text.html

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
destination.addEventListener("dragover", updateResultWithEvent);
4646
destination.addEventListener("drop", updateResultWithEvent);
4747

48+
source.focus();
4849
source.setSelectionRange(0, source.value.length);
4950

5051
if (window.testRunner && window.eventSender && window.internals) {

LayoutTests/editing/pasteboard/data-transfer-get-data-on-paste-plain-text.html

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
event.preventDefault();
4242
}
4343

44+
source.focus();
4445
source.setSelectionRange(0, source.value.length);
4546
destination.addEventListener("paste", updateResultWithEvent);
4647

LayoutTests/editing/pasteboard/drag-drop-input-textarea.html

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
// Drag a word in the textarea
1919
var textarea = document.getElementById("textarea");
20+
textarea.focus();
2021
textarea.setSelectionRange(0, 4);
2122
x = textarea.offsetLeft + 10;
2223
y = textarea.offsetTop + textarea.offsetHeight / 2;

LayoutTests/editing/pasteboard/drag-drop-url-text.html

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
// Drag a URL text in the source
1919
var source = document.getElementById("source");
20+
source.focus();
2021
source.setSelectionRange(0, source.value.length);
2122
x = source.offsetLeft + 10;
2223
y = source.offsetTop + source.offsetHeight / 2;

LayoutTests/editing/pasteboard/pasting-tabs.html

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<script>
1111
var textarea = document.getElementById("textarea");
1212
textarea.setSelectionRange(0, 0);
13+
textarea.focus();
1314
document.execCommand("SelectAll");
1415
document.execCommand("Copy");
1516
var div = document.getElementById("div");

LayoutTests/editing/selection/4975120.html

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
function runTest() {
77
var input = document.getElementById("input");
8+
input.focus();
89
input.setSelectionRange(0, 3);
910
var frame = frames[0];
1011
frame.focus();

LayoutTests/editing/selection/5497643-expected.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
textareaOffset = nodeIndex(textarea); textarea.setSelectionRange(0, 0); textarea.parentNode.removeChild(textarea);
1+
textareaOffset = nodeIndex(textarea); textarea.focus(); textarea.setSelectionRange(0, 0); textarea.parentNode.removeChild(textarea);
22
PASS getSelection().type is 'Caret'
33
PASS getSelection().getRangeAt(0).startContainer is document.body
44
PASS getSelection().getRangeAt(0).startOffset is textareaOffset

LayoutTests/editing/selection/5497643.html

+14-10
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,24 @@
33
<body>
44
<p>This tests to make sure that a selection inside a textarea is updated when the textarea is removed from the document.</p>
55
<textarea id="textarea"></textarea>
6-
<script src="../../resources/js-test-pre.js"></script>
6+
<script src="../../resources/js-test.js"></script>
77
<script>
8-
if (window.testRunner)
9-
window.testRunner.dumpAsText();
8+
if (window.testRunner) {
9+
testRunner.dumpAsText();
10+
testRunner.waitUntilDone();
11+
}
1012
function nodeIndex(node) {
1113
return Array.prototype.slice.call(node.parentNode.childNodes).indexOf(node);
1214
}
13-
textarea = document.getElementById("textarea");
14-
evalAndLog("textareaOffset = nodeIndex(textarea); textarea.setSelectionRange(0, 0); textarea.parentNode.removeChild(textarea);");
15-
shouldBe("getSelection().type", "'Caret'");
16-
shouldBe("getSelection().getRangeAt(0).startContainer", "document.body");
17-
shouldBe("getSelection().getRangeAt(0).startOffset", "textareaOffset");
18-
var successfullyParsed = true;
15+
window.onload = () => {
16+
textarea = document.getElementById("textarea");
17+
evalAndLog("textareaOffset = nodeIndex(textarea); textarea.focus(); textarea.setSelectionRange(0, 0); textarea.parentNode.removeChild(textarea);");
18+
shouldBe("getSelection().type", "'Caret'");
19+
shouldBe("getSelection().getRangeAt(0).startContainer", "document.body");
20+
shouldBe("getSelection().getRangeAt(0).startOffset", "textareaOffset");
21+
if (window.testRunner)
22+
testRunner.notifyDone();
23+
};
1924
</script>
20-
<script src="../../resources/js-test-post.js"></script>
2125
</body>
2226
</html>

LayoutTests/editing/selection/delete-selection-with-disconnected-extent.html

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
if (window.testRunner)
55
testRunner.dumpAsText();
66

7+
document.querySelector('input').focus();
78
document.querySelector('input').setRangeText('aa', 0, 1, 'end');
89
getSelection().extend(document.createElement('select'));
910
document.execCommand('delete', false);

LayoutTests/editing/selection/delete-word-granularity-text-control.html

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
eventSender.mouseUp();
3030
}
3131

32+
textarea.focus();
3233
textarea.setSelectionRange(0, 3);
3334
document.execCommand('delete');
3435

LayoutTests/editing/selection/deleteFromDocument-shadow-tree-crash.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
}
99

1010
function runTest() {
11-
document.getElementById('input_0').disabled = true;
11+
document.getElementById('input_0').focus();
1212
document.getElementById('input_0').setRangeText("abc");
1313
window.getSelection().extend(document.getElementById('input_0'), 0);
1414
window.getSelection().deleteFromDocument();

LayoutTests/editing/selection/programmatic-selection-on-mac-is-directionless.html

+4-3
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@
4343
range.setEnd(container, range.startOffset + 'in'.length);
4444
selection.addRange(range);
4545
} else {
46-
node.selectionDirection = 'none';
47-
node.selectionStart = node.value.search('ine 2');
48-
node.selectionEnd = node.selectionStart + 'in'.length;
46+
node.focus();
47+
node.selectionDirection = 'none';
48+
node.selectionStart = node.value.search('ine 2');
49+
node.selectionEnd = node.selectionStart + 'in'.length;
4950
}
5051
}
5152

LayoutTests/editing/selection/select-iframe-focusin-document-crash.html

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
window.addEventListener('focusin', eventHandle);
1818
var element = iframe.contentWindow.document.getElementById("input");
1919
element.value = 'demo';
20+
element.focus();
2021
element.selectionStart = 0;
2122
}
2223
function eventHandle(event)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
3+
PASS setSelectionRange() should not update FrameSelection if the target element is not focused.
4+
PASS setRangeText() should not update FrameSelection if the target element is not focused.
5+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<body>
4+
<script src="../../resources/testharness.js"></script>
5+
<script src="../../resources/testharnessreport.js"></script>
6+
<input id="notFocused" value="foo">
7+
<input id="focused" value="a">
8+
<script>
9+
test(() => {
10+
var notFocused = document.getElementById('notFocused');
11+
var focused = document.getElementById('focused');
12+
var selection = window.getSelection();
13+
selection.removeAllRanges();
14+
focused.focus();
15+
16+
var originalAnchorNode = selection.anchorNode;
17+
var originalAnchorOffset = selection.anchorOffset;
18+
notFocused.setSelectionRange(3, 3);
19+
assert_equals(selection.anchorNode, originalAnchorNode);
20+
assert_equals(selection.anchorOffset, originalAnchorOffset);
21+
}, 'setSelectionRange() should not update FrameSelection if the target element is not focused.');
22+
23+
test(() => {
24+
var notFocused = document.getElementById('notFocused');
25+
var focused = document.getElementById('focused');
26+
var selection = window.getSelection();
27+
selection.removeAllRanges();
28+
focused.focus();
29+
30+
var originalAnchorNode = selection.anchorNode;
31+
var originalAnchorOffset = selection.anchorOffset;
32+
notFocused.setRangeText('barrr', 0, 3, 'select');
33+
assert_equals(selection.anchorNode, originalAnchorNode);
34+
assert_equals(selection.anchorOffset, originalAnchorOffset);
35+
}, 'setRangeText() should not update FrameSelection if the target element is not focused.');
36+
</script>
37+
</body>
38+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Setting selection through APIs does not focus unless selection is inside the text control.
2+
3+
4+
5+
PASS setSelectionRange does not focus unless selection is inside the text control.
6+
PASS selectionStart/selectionEnd does not focus unless selection is inside the text control.
7+
PASS setRangeText does not focus unless selection is inside the text control.
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Setting selection through APIs does not focus unless selection is inside the text control.</title>
5+
</head>
6+
<body>
7+
<p>Setting selection through APIs does not focus unless selection is inside the text control.</p>
8+
<input id="input" value="XXXXXXXX">
9+
<textarea id="textarea">XXXXXXXX</textarea>
10+
<script src="../../resources/testharness.js"></script>
11+
<script src="../../resources/testharnessreport.js"></script>
12+
<script>
13+
function testSetSelectionRange(element, expectFocus) {
14+
const selection = window.getSelection();
15+
selection.removeAllRanges();
16+
element.setSelectionRange(null, null);
17+
assert_equals(document.activeElement == element, expectFocus, `Element is should ${!expectFocus ? "not " : ""}be focused`);
18+
assert_equals(element.selectionStart, 0, "selectionStart is correctly set");
19+
assert_equals(element.selectionStart, 0, "selectionEnd is correctly set");
20+
element.setSelectionRange(2, 4);
21+
assert_equals(document.activeElement == element, expectFocus, `Element is should ${!expectFocus ? "not " : ""}be focused`);
22+
assert_equals(element.selectionStart, 2, "selectionStart is correctly set");
23+
assert_equals(element.selectionEnd, 4, "selectionEnd is correctly set");
24+
}
25+
function testSelectionStartEnd(element, expectFocus) {
26+
element.selectionStart = 3;
27+
element.selectionEnd = 5;
28+
assert_equals(document.activeElement == element, expectFocus, `Element is should ${!expectFocus ? "not " : ""}be focused`);
29+
assert_equals(element.selectionStart, 3, "selectionStart is correctly set");
30+
assert_equals(element.selectionEnd, 5, "selectionEnd is correctly set");
31+
}
32+
33+
function testSetRangeText(element, expectFocus) {
34+
element.setRangeText('barrr', 0, 3, 'select');
35+
assert_equals(document.activeElement == element, expectFocus, `Element is should ${!expectFocus ? "not " : ""}be focused`);
36+
}
37+
38+
test(t => {
39+
t.add_cleanup(() => { input.blur(); textarea.blur(); getSelection().removeAllRanges(); });
40+
testSetSelectionRange(input, false);
41+
testSetSelectionRange(textarea, false);
42+
input.focus();
43+
testSetSelectionRange(input, true);
44+
textarea.focus();
45+
testSetSelectionRange(textarea, true);
46+
}, "setSelectionRange does not focus unless selection is inside the text control.");
47+
48+
test(t => {
49+
t.add_cleanup(() => { input.blur(); textarea.blur(); getSelection().removeAllRanges(); });
50+
testSelectionStartEnd(input, false);
51+
testSelectionStartEnd(textarea, false);
52+
input.focus();
53+
testSelectionStartEnd(input, true);
54+
textarea.focus();
55+
testSelectionStartEnd(textarea, true);
56+
}, "selectionStart/selectionEnd does not focus unless selection is inside the text control.");
57+
58+
test(t => {
59+
t.add_cleanup(() => { input.blur(); textarea.blur(); getSelection().removeAllRanges(); });
60+
testSetRangeText(input, false);
61+
testSetRangeText(textarea, false);
62+
input.focus();
63+
testSetRangeText(input, true);
64+
textarea.focus();
65+
testSetRangeText(textarea, true);
66+
}, "setRangeText does not focus unless selection is inside the text control.");
67+
</script>
68+
</body>
69+
</html>

LayoutTests/editing/selection/shrink-selection-after-shift-pagedown.html

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
testRunner.dumpAsText();
88

99
var ta = document.getElementById('ta');
10+
ta.focus();
1011
ta.setSelectionRange(4, 16);
1112

1213
var lastSelectedLine;

LayoutTests/fast/css/content/content-on-focus-change.html

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
function main() {
99
input.setSelectionRange(0,31,"forward");
10+
input.focus();
1011
}
1112
function f1() {
1213
var input = document.getElementById("input");

LayoutTests/fast/events/context-no-deselect.html

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// This test checks that if the user right clicks on selected text,
99
// the selected text doesn't change or get deselected.
1010
var input = document.getElementById("text");
11+
input.focus();
1112
input.selectionStart = 5;
1213
input.selectionEnd = 15;
1314

LayoutTests/fast/forms/datalist/datalist-idTargetChanged-crash.html

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
}
66

77
onload = () => {
8+
inputElement.focus();
89
inputElement.setRangeText("foo");
910
}
1011

LayoutTests/fast/forms/input-appearance-selection.html

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
function testSelectionRange (testNumber, start, end, expectedStart, expectedEnd, tf, res)
2121
{
22+
tf.focus();
2223
tf.setSelectionRange(start, end);
2324
res.innerHTML = res.innerHTML + "<br>Test " + testNumber + ": setSelectionRange(" + start + ", " + end + ")";
2425
if (tf.selectionStart == expectedStart && tf.selectionEnd == expectedEnd)

LayoutTests/fast/forms/input-delete.html

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
testRunner.dumpAsText();
88
}
99
document.getElementById('tf').setSelectionRange(5, 11);
10+
document.getElementById('tf').focus();
1011
deleteCommand();
1112
if (document.getElementById('tf').value == "Test Failed") {
1213
document.getElementById('res').innerHTML = "Failed";

LayoutTests/fast/forms/input-placeholder-visibility-2-expected.html

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<div>
88
<input id=i1 value="Text">
99
<script>
10+
document.getElementById('i1').focus();
1011
document.getElementById('i1').setSelectionRange(4, 4);
1112
</script>
1213
</body>

LayoutTests/fast/forms/paste-into-textarea.html

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
testRunner.dumpAsText();
66
var e = document.getElementById("test");
77
e.setSelectionRange(1, 1);
8+
e.focus();
89
document.execCommand("InsertHTML", false, "(There should be one 'x' before and after this sentence.)");
910
if (e.value == "x(There should be one 'x' before and after this sentence.)x")
1011
document.write("<p>Hooray, test succeeded.</p>");

LayoutTests/fast/forms/textarea-arrow-navigation.html

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
// that when you go down by a line, the cursor will be at the end of the
2525
// numbered lines:
2626
textarea.setSelectionRange(5, 5);
27+
textarea.focus();
2728
for (var i = 0; i < 10; i++) {
2829
// press the 'down arrow' a bunch of times to try to get to the end of the text area
2930
eventSender.keyDown("downArrow");

LayoutTests/fast/rendering/render-compositor-null-layer-crash.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
}
66
function main() {
77
var x29 = document.getElementById("x29");
8-
try { x22.selectionEnd = 87; } catch { }
8+
try { x22.focus(); x22.selectionEnd = 87; } catch { }
99
try { x29.prepend(x7); } catch { }
1010
}
1111
function f4() {

LayoutTests/fast/text-extraction/basic-text-extraction.html

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<div contenteditable="true">This is an editable area: <a href="https://webkit.org">WebKit</a> <a href="https://webkit.org/downloads">downloads</a>.</div>
2626
<script>
2727
addEventListener("load", async () => {
28+
document.querySelector("input").focus();
2829
document.querySelector("input").setSelectionRange(4, 7);
2930

3031
if (!window.testRunner)

LayoutTests/fast/text/out-of-flow-line-break-crash.html

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
testRunner.dumpAsText();
1818
embed.appendChild(meter);
1919
textarea.setSelectionRange(1,0,"text");
20+
textarea.focus();
2021
container.appendChild(meter);
2122
document.execCommand("selectAll", false);
2223
document.execCommand("createLink", false, "#link");
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11

22

3-
FAIL programatic focus() scrolls selection into view including ancestors assert_not_equals: Should've scrolled ancestor to show the selection got disallowed value 0
3+
PASS programatic focus() scrolls selection into view including ancestors
44

0 commit comments

Comments
 (0)