LibWeb/HTML: Correctly reset selection on type change

The selection now gets reset to the beginning of the control if the
type changes from an unselectable type to a selectable type.
This commit is contained in:
Glenn Skrzypczak 2025-04-20 19:43:37 +02:00 committed by Tim Ledbetter
commit 5f75558646
Notes: github-actions[bot] 2025-04-23 06:21:13 +00:00
3 changed files with 552 additions and 0 deletions

View file

@ -1470,6 +1470,7 @@ void HTMLInputElement::type_attribute_changed(TypeAttributeState old_state, Type
// 9. If previouslySelectable is false and nowSelectable is true, set the element's text entry cursor position to the
// beginning of the text control, and set its selection direction to "none".
if (!previously_selectable && now_selectable) {
set_the_selection_range(0, 0);
set_selection_direction(OptionalNone {});
}
}

View file

@ -0,0 +1,385 @@
Harness status: OK
Found 380 tests
380 Pass
Pass change state from hidden to text
Pass change state from hidden to search
Pass change state from hidden to tel
Pass change state from hidden to url
Pass change state from hidden to email
Pass change state from hidden to password
Pass change state from hidden to datetime-local
Pass change state from hidden to date
Pass change state from hidden to time
Pass change state from hidden to number
Pass change state from hidden to range
Pass change state from hidden to color
Pass change state from hidden to checkbox
Pass change state from hidden to radio
Pass change state from hidden to file
Pass change state from hidden to submit
Pass change state from hidden to image
Pass change state from hidden to reset
Pass change state from hidden to button
Pass change state from text to hidden
Pass change state from text to search
Pass change state from text to tel
Pass change state from text to url
Pass change state from text to email
Pass change state from text to password
Pass change state from text to datetime-local
Pass change state from text to date
Pass change state from text to time
Pass change state from text to number
Pass change state from text to range
Pass change state from text to color
Pass change state from text to checkbox
Pass change state from text to radio
Pass change state from text to file
Pass change state from text to submit
Pass change state from text to image
Pass change state from text to reset
Pass change state from text to button
Pass change state from search to hidden
Pass change state from search to text
Pass change state from search to tel
Pass change state from search to url
Pass change state from search to email
Pass change state from search to password
Pass change state from search to datetime-local
Pass change state from search to date
Pass change state from search to time
Pass change state from search to number
Pass change state from search to range
Pass change state from search to color
Pass change state from search to checkbox
Pass change state from search to radio
Pass change state from search to file
Pass change state from search to submit
Pass change state from search to image
Pass change state from search to reset
Pass change state from search to button
Pass change state from tel to hidden
Pass change state from tel to text
Pass change state from tel to search
Pass change state from tel to url
Pass change state from tel to email
Pass change state from tel to password
Pass change state from tel to datetime-local
Pass change state from tel to date
Pass change state from tel to time
Pass change state from tel to number
Pass change state from tel to range
Pass change state from tel to color
Pass change state from tel to checkbox
Pass change state from tel to radio
Pass change state from tel to file
Pass change state from tel to submit
Pass change state from tel to image
Pass change state from tel to reset
Pass change state from tel to button
Pass change state from url to hidden
Pass change state from url to text
Pass change state from url to search
Pass change state from url to tel
Pass change state from url to email
Pass change state from url to password
Pass change state from url to datetime-local
Pass change state from url to date
Pass change state from url to time
Pass change state from url to number
Pass change state from url to range
Pass change state from url to color
Pass change state from url to checkbox
Pass change state from url to radio
Pass change state from url to file
Pass change state from url to submit
Pass change state from url to image
Pass change state from url to reset
Pass change state from url to button
Pass change state from email to hidden
Pass change state from email to text
Pass change state from email to search
Pass change state from email to tel
Pass change state from email to url
Pass change state from email to password
Pass change state from email to datetime-local
Pass change state from email to date
Pass change state from email to time
Pass change state from email to number
Pass change state from email to range
Pass change state from email to color
Pass change state from email to checkbox
Pass change state from email to radio
Pass change state from email to file
Pass change state from email to submit
Pass change state from email to image
Pass change state from email to reset
Pass change state from email to button
Pass change state from password to hidden
Pass change state from password to text
Pass change state from password to search
Pass change state from password to tel
Pass change state from password to url
Pass change state from password to email
Pass change state from password to datetime-local
Pass change state from password to date
Pass change state from password to time
Pass change state from password to number
Pass change state from password to range
Pass change state from password to color
Pass change state from password to checkbox
Pass change state from password to radio
Pass change state from password to file
Pass change state from password to submit
Pass change state from password to image
Pass change state from password to reset
Pass change state from password to button
Pass change state from datetime-local to hidden
Pass change state from datetime-local to text
Pass change state from datetime-local to search
Pass change state from datetime-local to tel
Pass change state from datetime-local to url
Pass change state from datetime-local to email
Pass change state from datetime-local to password
Pass change state from datetime-local to date
Pass change state from datetime-local to time
Pass change state from datetime-local to number
Pass change state from datetime-local to range
Pass change state from datetime-local to color
Pass change state from datetime-local to checkbox
Pass change state from datetime-local to radio
Pass change state from datetime-local to file
Pass change state from datetime-local to submit
Pass change state from datetime-local to image
Pass change state from datetime-local to reset
Pass change state from datetime-local to button
Pass change state from date to hidden
Pass change state from date to text
Pass change state from date to search
Pass change state from date to tel
Pass change state from date to url
Pass change state from date to email
Pass change state from date to password
Pass change state from date to datetime-local
Pass change state from date to time
Pass change state from date to number
Pass change state from date to range
Pass change state from date to color
Pass change state from date to checkbox
Pass change state from date to radio
Pass change state from date to file
Pass change state from date to submit
Pass change state from date to image
Pass change state from date to reset
Pass change state from date to button
Pass change state from time to hidden
Pass change state from time to text
Pass change state from time to search
Pass change state from time to tel
Pass change state from time to url
Pass change state from time to email
Pass change state from time to password
Pass change state from time to datetime-local
Pass change state from time to date
Pass change state from time to number
Pass change state from time to range
Pass change state from time to color
Pass change state from time to checkbox
Pass change state from time to radio
Pass change state from time to file
Pass change state from time to submit
Pass change state from time to image
Pass change state from time to reset
Pass change state from time to button
Pass change state from number to hidden
Pass change state from number to text
Pass change state from number to search
Pass change state from number to tel
Pass change state from number to url
Pass change state from number to email
Pass change state from number to password
Pass change state from number to datetime-local
Pass change state from number to date
Pass change state from number to time
Pass change state from number to range
Pass change state from number to color
Pass change state from number to checkbox
Pass change state from number to radio
Pass change state from number to file
Pass change state from number to submit
Pass change state from number to image
Pass change state from number to reset
Pass change state from number to button
Pass change state from range to hidden
Pass change state from range to text
Pass change state from range to search
Pass change state from range to tel
Pass change state from range to url
Pass change state from range to email
Pass change state from range to password
Pass change state from range to datetime-local
Pass change state from range to date
Pass change state from range to time
Pass change state from range to number
Pass change state from range to color
Pass change state from range to checkbox
Pass change state from range to radio
Pass change state from range to file
Pass change state from range to submit
Pass change state from range to image
Pass change state from range to reset
Pass change state from range to button
Pass change state from color to hidden
Pass change state from color to text
Pass change state from color to search
Pass change state from color to tel
Pass change state from color to url
Pass change state from color to email
Pass change state from color to password
Pass change state from color to datetime-local
Pass change state from color to date
Pass change state from color to time
Pass change state from color to number
Pass change state from color to range
Pass change state from color to checkbox
Pass change state from color to radio
Pass change state from color to file
Pass change state from color to submit
Pass change state from color to image
Pass change state from color to reset
Pass change state from color to button
Pass change state from checkbox to hidden
Pass change state from checkbox to text
Pass change state from checkbox to search
Pass change state from checkbox to tel
Pass change state from checkbox to url
Pass change state from checkbox to email
Pass change state from checkbox to password
Pass change state from checkbox to datetime-local
Pass change state from checkbox to date
Pass change state from checkbox to time
Pass change state from checkbox to number
Pass change state from checkbox to range
Pass change state from checkbox to color
Pass change state from checkbox to radio
Pass change state from checkbox to file
Pass change state from checkbox to submit
Pass change state from checkbox to image
Pass change state from checkbox to reset
Pass change state from checkbox to button
Pass change state from radio to hidden
Pass change state from radio to text
Pass change state from radio to search
Pass change state from radio to tel
Pass change state from radio to url
Pass change state from radio to email
Pass change state from radio to password
Pass change state from radio to datetime-local
Pass change state from radio to date
Pass change state from radio to time
Pass change state from radio to number
Pass change state from radio to range
Pass change state from radio to color
Pass change state from radio to checkbox
Pass change state from radio to file
Pass change state from radio to submit
Pass change state from radio to image
Pass change state from radio to reset
Pass change state from radio to button
Pass change state from file to hidden
Pass change state from file to text
Pass change state from file to search
Pass change state from file to tel
Pass change state from file to url
Pass change state from file to email
Pass change state from file to password
Pass change state from file to datetime-local
Pass change state from file to date
Pass change state from file to time
Pass change state from file to number
Pass change state from file to range
Pass change state from file to color
Pass change state from file to checkbox
Pass change state from file to radio
Pass change state from file to submit
Pass change state from file to image
Pass change state from file to reset
Pass change state from file to button
Pass change state from submit to hidden
Pass change state from submit to text
Pass change state from submit to search
Pass change state from submit to tel
Pass change state from submit to url
Pass change state from submit to email
Pass change state from submit to password
Pass change state from submit to datetime-local
Pass change state from submit to date
Pass change state from submit to time
Pass change state from submit to number
Pass change state from submit to range
Pass change state from submit to color
Pass change state from submit to checkbox
Pass change state from submit to radio
Pass change state from submit to file
Pass change state from submit to image
Pass change state from submit to reset
Pass change state from submit to button
Pass change state from image to hidden
Pass change state from image to text
Pass change state from image to search
Pass change state from image to tel
Pass change state from image to url
Pass change state from image to email
Pass change state from image to password
Pass change state from image to datetime-local
Pass change state from image to date
Pass change state from image to time
Pass change state from image to number
Pass change state from image to range
Pass change state from image to color
Pass change state from image to checkbox
Pass change state from image to radio
Pass change state from image to file
Pass change state from image to submit
Pass change state from image to reset
Pass change state from image to button
Pass change state from reset to hidden
Pass change state from reset to text
Pass change state from reset to search
Pass change state from reset to tel
Pass change state from reset to url
Pass change state from reset to email
Pass change state from reset to password
Pass change state from reset to datetime-local
Pass change state from reset to date
Pass change state from reset to time
Pass change state from reset to number
Pass change state from reset to range
Pass change state from reset to color
Pass change state from reset to checkbox
Pass change state from reset to radio
Pass change state from reset to file
Pass change state from reset to submit
Pass change state from reset to image
Pass change state from reset to button
Pass change state from button to hidden
Pass change state from button to text
Pass change state from button to search
Pass change state from button to tel
Pass change state from button to url
Pass change state from button to email
Pass change state from button to password
Pass change state from button to datetime-local
Pass change state from button to date
Pass change state from button to time
Pass change state from button to number
Pass change state from button to range
Pass change state from button to color
Pass change state from button to checkbox
Pass change state from button to radio
Pass change state from button to file
Pass change state from button to submit
Pass change state from button to image
Pass change state from button to reset

View file

@ -0,0 +1,166 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Input element's type attribute changes state</title>
<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
<link rel=help href="https://html.spec.whatwg.org/multipage/#the-input-element">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
const INITIAL_VALUE = " foo\rbar ";
// Sanitize algorithm implementations only for values used in this test.
function sanitizeText(value) {
switch (value) {
case INITIAL_VALUE: return " foobar ";
case " foobar ": return value;
case "foobar": return value;
case "50": return value;
case "#000000": return value;
case "": return value;
default: throw new DOMException(`Internal Error: Should add support of "${value}"`, "NotSupportedError");
}
}
function sanitizeEmailOrUrl(value) {
switch (value) {
case INITIAL_VALUE: return "foobar";
case " foobar ": return "foobar";
case "foobar": return value;
case "50": return value;
case "#000000": return value;
case "": return value;
default: throw new DOMException(`Internal Error: Should add support of "${value}"`, "NotSupportedError");
}
}
function sanitizeTemporal(value) {
// We have no test cases using valid temporal values.
return "";
}
function sanitizeNumber(value) {
switch (value) {
case "50": return value;
default:
// We have no test cases using valid numbers other than "50".
return "";
}
}
function sanitizeRange(value) {
// We have no test cases using valid numbers other than "50".
return "50";
}
function sanitizeColor(value) {
// We have no test cases using valid colors other than "#000000".
return "#000000";
}
function browserSupportsInputTypeOf(inputType) {
var inputTest = document.createElement("input");
inputTest.type = inputType;
return (inputTest.type === inputType);
}
var types = [
{ type: "hidden" },
{ type: "text", sanitizer: sanitizeText },
{ type: "search", sanitizer: sanitizeText },
{ type: "tel", sanitizer: sanitizeText },
{ type: "url", sanitizer: sanitizeEmailOrUrl },
{ type: "email", sanitizer: sanitizeEmailOrUrl },
{ type: "password", sanitizer: sanitizeText },
{ type: "datetime-local", sanitizer: sanitizeTemporal },
{ type: "date", sanitizer: sanitizeTemporal },
{ type: "time", sanitizer: sanitizeTemporal },
{ type: "number", sanitizer: sanitizeNumber },
{ type: "range", sanitizer: sanitizeRange },
{ type: "color", sanitizer: sanitizeColor },
{ type: "checkbox", defaultValue: "on" },
{ type: "radio", defaultValue: "on" },
{ type: "file" },
{ type: "submit" },
{ type: "image" },
{ type: "reset" },
{ type: "button" }
];
const selectionStart = 2;
const selectionEnd = 5;
const selectionDirection = "backward";
// Obtain selectionDirection after setting it to "none".
// Some platforms don't support "none" direction, and "forward" is returned
// in such platforms.
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#set-the-selection-direction
function testNoneDirection() {
const input = document.createElement("input");
input.selectionDirection = "none";
return input.selectionDirection;
}
const noneDirectionResult = testNoneDirection();
for (var i = 0; i < types.length; i++) {
for (var j = 0; j < types.length; j++) {
if (types[i] != types[j]) {
test(function() {
assert_implements(browserSupportsInputTypeOf(types[i].type), "Support for input type " + types[i].type + " is required for this test.");
assert_implements(browserSupportsInputTypeOf(types[j].type), "Support for input type " + types[j].type + " is required for this test.");
var input = document.createElement("input");
var expected = INITIAL_VALUE;
input.type = types[i].type;
if (types[i].type === "file") {
assert_throws_dom("INVALID_STATE_ERR", function() {
input.value = expected;
});
assert_equals(input.value, "");
} else if (types[j].type === "file") {
input.value = expected;
input.type = types[j].type; // change state
assert_equals(input.value, "");
} else {
input.value = expected;
expected = input.value;
const previouslySelectable = (input.selectionStart !== null);
if (previouslySelectable) {
input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
}
input.type = types[j].type; // change state
var preSanitizeValue = expected;
// type[j] sanitization
if (types[j].sanitizer) {
expected = types[j].sanitizer(expected);
}
// type[j] defaultValue
if (expected === "" && types[j].defaultValue) {
expected = types[j].defaultValue;
}
assert_equals(input.value, expected, "input.value should be '" + expected + "' after change of state");
const nowSelectable = (input.selectionStart !== null);
if (nowSelectable) {
if (previouslySelectable) {
// Value might change after sanitization. The following checks are only valid when the value stays the same.
if (preSanitizeValue === expected) {
assert_equals(input.selectionStart, selectionStart, "selectionStart should be unchanged");
assert_equals(input.selectionEnd, selectionEnd, "selectionEnd should be unchanged");
assert_equals(input.selectionDirection, selectionDirection, "selectionDirection should be unchanged");
}
} else {
assert_equals(input.selectionStart, 0, "selectionStart should be 0");
assert_equals(input.selectionEnd, 0, "selectionEnd should be 0");
assert_equals(input.selectionDirection, noneDirectionResult,
`selectionDirection should be '{noneDirectionResult}'`);
}
}
}
}, "change state from " + types[i].type + " to " + types[j].type);
}
}
}
</script>