Skip to content

Commit

Permalink
walmart.com/wallet focuses phone number field when attempting to add …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
nt1m committed Dec 15, 2024
1 parent d6d9a45 commit 72adbb9
Show file tree
Hide file tree
Showing 38 changed files with 186 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function writeToClipboardUsingDataTransfer(data) {
const input = document.createElement("input");
document.body.appendChild(input);
input.value = "a";
input.focus();
input.setSelectionRange(0, 1);
input.addEventListener("copy", event => {
for (const type of Object.keys(data))
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/editing/deleting/5290534.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

var search = document.getElementById("search");
search.setSelectionRange(0, 0);
search.focus();
document.execCommand("InsertText", false, "x");
if (search.value != "x")
log("Failure: text wasn't added to the search field.");
Expand Down
2 changes: 1 addition & 1 deletion LayoutTests/editing/inserting/4960120-1.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
<script>
var textarea = document.getElementById("textarea");
textarea.setSelectionRange(0, 0);

textarea.focus();
document.execCommand("InsertLineBreak");
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
testRunner.dumpAsText();

var input = document.getElementById("input");
input.focus();
input.setSelectionRange(1, 1);
document.execCommand("InsertHTML", false, "b");
if (input.value == "ab")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
destination.addEventListener("dragover", updateResultWithEvent);
destination.addEventListener("drop", updateResultWithEvent);

source.focus();
source.setSelectionRange(0, source.value.length);

if (window.testRunner && window.eventSender && window.internals) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
event.preventDefault();
}

source.focus();
source.setSelectionRange(0, source.value.length);
destination.addEventListener("paste", updateResultWithEvent);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

// Drag a word in the textarea
var textarea = document.getElementById("textarea");
textarea.focus();
textarea.setSelectionRange(0, 4);
x = textarea.offsetLeft + 10;
y = textarea.offsetTop + textarea.offsetHeight / 2;
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/editing/pasteboard/drag-drop-url-text.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

// Drag a URL text in the source
var source = document.getElementById("source");
source.focus();
source.setSelectionRange(0, source.value.length);
x = source.offsetLeft + 10;
y = source.offsetTop + source.offsetHeight / 2;
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/editing/pasteboard/pasting-tabs.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<script>
var textarea = document.getElementById("textarea");
textarea.setSelectionRange(0, 0);
textarea.focus();
document.execCommand("SelectAll");
document.execCommand("Copy");
var div = document.getElementById("div");
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/editing/selection/4975120.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

function runTest() {
var input = document.getElementById("input");
input.focus();
input.setSelectionRange(0, 3);
var frame = frames[0];
frame.focus();
Expand Down
2 changes: 1 addition & 1 deletion LayoutTests/editing/selection/5497643-expected.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
textareaOffset = nodeIndex(textarea); textarea.setSelectionRange(0, 0); textarea.parentNode.removeChild(textarea);
textareaOffset = nodeIndex(textarea); textarea.focus(); textarea.setSelectionRange(0, 0); textarea.parentNode.removeChild(textarea);
PASS getSelection().type is 'Caret'
PASS getSelection().getRangeAt(0).startContainer is document.body
PASS getSelection().getRangeAt(0).startOffset is textareaOffset
Expand Down
24 changes: 14 additions & 10 deletions LayoutTests/editing/selection/5497643.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,24 @@
<body>
<p>This tests to make sure that a selection inside a textarea is updated when the textarea is removed from the document.</p>
<textarea id="textarea"></textarea>
<script src="../../resources/js-test-pre.js"></script>
<script src="../../resources/js-test.js"></script>
<script>
if (window.testRunner)
window.testRunner.dumpAsText();
if (window.testRunner) {
testRunner.dumpAsText();
testRunner.waitUntilDone();
}
function nodeIndex(node) {
return Array.prototype.slice.call(node.parentNode.childNodes).indexOf(node);
}
textarea = document.getElementById("textarea");
evalAndLog("textareaOffset = nodeIndex(textarea); textarea.setSelectionRange(0, 0); textarea.parentNode.removeChild(textarea);");
shouldBe("getSelection().type", "'Caret'");
shouldBe("getSelection().getRangeAt(0).startContainer", "document.body");
shouldBe("getSelection().getRangeAt(0).startOffset", "textareaOffset");
var successfullyParsed = true;
window.onload = () => {
textarea = document.getElementById("textarea");
evalAndLog("textareaOffset = nodeIndex(textarea); textarea.focus(); textarea.setSelectionRange(0, 0); textarea.parentNode.removeChild(textarea);");
shouldBe("getSelection().type", "'Caret'");
shouldBe("getSelection().getRangeAt(0).startContainer", "document.body");
shouldBe("getSelection().getRangeAt(0).startOffset", "textareaOffset");
if (window.testRunner)
testRunner.notifyDone();
};
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
if (window.testRunner)
testRunner.dumpAsText();

document.querySelector('input').focus();
document.querySelector('input').setRangeText('aa', 0, 1, 'end');
getSelection().extend(document.createElement('select'));
document.execCommand('delete', false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
eventSender.mouseUp();
}

textarea.focus();
textarea.setSelectionRange(0, 3);
document.execCommand('delete');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
}

function runTest() {
document.getElementById('input_0').disabled = true;
document.getElementById('input_0').focus();
document.getElementById('input_0').setRangeText("abc");
window.getSelection().extend(document.getElementById('input_0'), 0);
window.getSelection().deleteFromDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@
range.setEnd(container, range.startOffset + 'in'.length);
selection.addRange(range);
} else {
node.selectionDirection = 'none';
node.selectionStart = node.value.search('ine 2');
node.selectionEnd = node.selectionStart + 'in'.length;
node.focus();
node.selectionDirection = 'none';
node.selectionStart = node.value.search('ine 2');
node.selectionEnd = node.selectionStart + 'in'.length;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
window.addEventListener('focusin', eventHandle);
var element = iframe.contentWindow.document.getElementById("input");
element.value = 'demo';
element.focus();
element.selectionStart = 0;
}
function eventHandle(event)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@


PASS setSelectionRange() should not update FrameSelection if the target element is not focused.
PASS setRangeText() should not update FrameSelection if the target element is not focused.

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<body>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<input id="notFocused" value="foo">
<input id="focused" value="a">
<script>
test(() => {
var notFocused = document.getElementById('notFocused');
var focused = document.getElementById('focused');
var selection = window.getSelection();
selection.removeAllRanges();
focused.focus();

var originalAnchorNode = selection.anchorNode;
var originalAnchorOffset = selection.anchorOffset;
notFocused.setSelectionRange(3, 3);
assert_equals(selection.anchorNode, originalAnchorNode);
assert_equals(selection.anchorOffset, originalAnchorOffset);
}, 'setSelectionRange() should not update FrameSelection if the target element is not focused.');

test(() => {
var notFocused = document.getElementById('notFocused');
var focused = document.getElementById('focused');
var selection = window.getSelection();
selection.removeAllRanges();
focused.focus();

var originalAnchorNode = selection.anchorNode;
var originalAnchorOffset = selection.anchorOffset;
notFocused.setRangeText('barrr', 0, 3, 'select');
assert_equals(selection.anchorNode, originalAnchorNode);
assert_equals(selection.anchorOffset, originalAnchorOffset);
}, 'setRangeText() should not update FrameSelection if the target element is not focused.');
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Setting selection through APIs does not focus unless selection is inside the text control.



PASS setSelectionRange does not focus unless selection is inside the text control.
PASS selectionStart/selectionEnd does not focus unless selection is inside the text control.
PASS setRangeText does not focus unless selection is inside the text control.

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<title>Setting selection through APIs does not focus unless selection is inside the text control.</title>
</head>
<body>
<p>Setting selection through APIs does not focus unless selection is inside the text control.</p>
<input id="input" value="XXXXXXXX">
<textarea id="textarea">XXXXXXXX</textarea>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
function testSetSelectionRange(element, expectFocus) {
const selection = window.getSelection();
selection.removeAllRanges();
element.setSelectionRange(null, null);
assert_equals(document.activeElement == element, expectFocus, `Element is should ${!expectFocus ? "not " : ""}be focused`);
assert_equals(element.selectionStart, 0, "selectionStart is correctly set");
assert_equals(element.selectionStart, 0, "selectionEnd is correctly set");
element.setSelectionRange(2, 4);
assert_equals(document.activeElement == element, expectFocus, `Element is should ${!expectFocus ? "not " : ""}be focused`);
assert_equals(element.selectionStart, 2, "selectionStart is correctly set");
assert_equals(element.selectionEnd, 4, "selectionEnd is correctly set");
}
function testSelectionStartEnd(element, expectFocus) {
element.selectionStart = 3;
element.selectionEnd = 5;
assert_equals(document.activeElement == element, expectFocus, `Element is should ${!expectFocus ? "not " : ""}be focused`);
assert_equals(element.selectionStart, 3, "selectionStart is correctly set");
assert_equals(element.selectionEnd, 5, "selectionEnd is correctly set");
}

function testSetRangeText(element, expectFocus) {
element.setRangeText('barrr', 0, 3, 'select');
assert_equals(document.activeElement == element, expectFocus, `Element is should ${!expectFocus ? "not " : ""}be focused`);
}

test(t => {
t.add_cleanup(() => { input.blur(); textarea.blur(); getSelection().removeAllRanges(); });
testSetSelectionRange(input, false);
testSetSelectionRange(textarea, false);
input.focus();
testSetSelectionRange(input, true);
textarea.focus();
testSetSelectionRange(textarea, true);
}, "setSelectionRange does not focus unless selection is inside the text control.");

test(t => {
t.add_cleanup(() => { input.blur(); textarea.blur(); getSelection().removeAllRanges(); });
testSelectionStartEnd(input, false);
testSelectionStartEnd(textarea, false);
input.focus();
testSelectionStartEnd(input, true);
textarea.focus();
testSelectionStartEnd(textarea, true);
}, "selectionStart/selectionEnd does not focus unless selection is inside the text control.");

test(t => {
t.add_cleanup(() => { input.blur(); textarea.blur(); getSelection().removeAllRanges(); });
testSetRangeText(input, false);
testSetRangeText(textarea, false);
input.focus();
testSetRangeText(input, true);
textarea.focus();
testSetRangeText(textarea, true);
}, "setRangeText does not focus unless selection is inside the text control.");
</script>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
testRunner.dumpAsText();

var ta = document.getElementById('ta');
ta.focus();
ta.setSelectionRange(4, 16);

var lastSelectedLine;
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/fast/css/content/content-on-focus-change.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

function main() {
input.setSelectionRange(0,31,"forward");
input.focus();
}
function f1() {
var input = document.getElementById("input");
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/fast/events/context-no-deselect.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// This test checks that if the user right clicks on selected text,
// the selected text doesn't change or get deselected.
var input = document.getElementById("text");
input.focus();
input.selectionStart = 5;
input.selectionEnd = 15;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
}

onload = () => {
inputElement.focus();
inputElement.setRangeText("foo");
}

Expand Down
1 change: 1 addition & 0 deletions LayoutTests/fast/forms/input-appearance-selection.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

function testSelectionRange (testNumber, start, end, expectedStart, expectedEnd, tf, res)
{
tf.focus();
tf.setSelectionRange(start, end);
res.innerHTML = res.innerHTML + "<br>Test " + testNumber + ": setSelectionRange(" + start + ", " + end + ")";
if (tf.selectionStart == expectedStart && tf.selectionEnd == expectedEnd)
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/fast/forms/input-delete.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
testRunner.dumpAsText();
}
document.getElementById('tf').setSelectionRange(5, 11);
document.getElementById('tf').focus();
deleteCommand();
if (document.getElementById('tf').value == "Test Failed") {
document.getElementById('res').innerHTML = "Failed";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<div>
<input id=i1 value="Text">
<script>
document.getElementById('i1').focus();
document.getElementById('i1').setSelectionRange(4, 4);
</script>
</body>
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/fast/forms/paste-into-textarea.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
testRunner.dumpAsText();
var e = document.getElementById("test");
e.setSelectionRange(1, 1);
e.focus();
document.execCommand("InsertHTML", false, "(There should be one 'x' before and after this sentence.)");
if (e.value == "x(There should be one 'x' before and after this sentence.)x")
document.write("<p>Hooray, test succeeded.</p>");
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/fast/forms/textarea-arrow-navigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// that when you go down by a line, the cursor will be at the end of the
// numbered lines:
textarea.setSelectionRange(5, 5);
textarea.focus();
for (var i = 0; i < 10; i++) {
// press the 'down arrow' a bunch of times to try to get to the end of the text area
eventSender.keyDown("downArrow");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
}
function main() {
var x29 = document.getElementById("x29");
try { x22.selectionEnd = 87; } catch { }
try { x22.focus(); x22.selectionEnd = 87; } catch { }
try { x29.prepend(x7); } catch { }
}
function f4() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<div contenteditable="true">This is an editable area: <a href="https://webkit.org">WebKit</a> <a href="https://webkit.org/downloads">downloads</a>.</div>
<script>
addEventListener("load", async () => {
document.querySelector("input").focus();
document.querySelector("input").setSelectionRange(4, 7);

if (!window.testRunner)
Expand Down
1 change: 1 addition & 0 deletions LayoutTests/fast/text/out-of-flow-line-break-crash.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
testRunner.dumpAsText();
embed.appendChild(meter);
textarea.setSelectionRange(1,0,"text");
textarea.focus();
container.appendChild(meter);
document.execCommand("selectAll", false);
document.execCommand("createLink", false, "#link");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


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

Loading

0 comments on commit 72adbb9

Please sign in to comment.