mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Steps 7-9 of the input type change algorithm
Spec: https://html.spec.whatwg.org/multipage/input.html#input-type-change In short, this resets the selection to the start of the field when the type has changed from one which doesn't support the selection API to one that does. I couldn't see an existing WPT test covering this.
This commit is contained in:
parent
ce7bae8834
commit
a8b64aca2a
5 changed files with 40 additions and 7 deletions
|
@ -53,7 +53,7 @@ use std::ops::Range;
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
use style::element_state::ElementState;
|
use style::element_state::ElementState;
|
||||||
use style::str::split_commas;
|
use style::str::split_commas;
|
||||||
use textinput::{SelectionDirection, TextInput};
|
use textinput::{Direction, SelectionDirection, TextInput};
|
||||||
use textinput::KeyReaction::{DispatchInput, Nothing, RedrawSelection, TriggerDefaultAction};
|
use textinput::KeyReaction::{DispatchInput, Nothing, RedrawSelection, TriggerDefaultAction};
|
||||||
use textinput::Lines::Single;
|
use textinput::Lines::Single;
|
||||||
|
|
||||||
|
@ -566,7 +566,7 @@ impl HTMLInputElementMethods for HTMLInputElement {
|
||||||
self.sanitize_value();
|
self.sanitize_value();
|
||||||
// Step 5.
|
// Step 5.
|
||||||
if *self.textinput.borrow().single_line_content() != old_value {
|
if *self.textinput.borrow().single_line_content() != old_value {
|
||||||
self.textinput.borrow_mut().clear_selection_to_limit();
|
self.textinput.borrow_mut().clear_selection_to_limit(Direction::Forward);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ValueMode::Default |
|
ValueMode::Default |
|
||||||
|
@ -1159,6 +1159,8 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#input-type-change
|
// https://html.spec.whatwg.org/multipage/#input-type-change
|
||||||
let (old_value_mode, old_idl_value) = (self.value_mode(), self.Value());
|
let (old_value_mode, old_idl_value) = (self.value_mode(), self.Value());
|
||||||
|
let previously_selectable = self.selection_api_applies();
|
||||||
|
|
||||||
self.input_type.set(new_type);
|
self.input_type.set(new_type);
|
||||||
|
|
||||||
if new_type.is_textual() {
|
if new_type.is_textual() {
|
||||||
|
@ -1210,6 +1212,11 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
|
|
||||||
// Step 6
|
// Step 6
|
||||||
self.sanitize_value();
|
self.sanitize_value();
|
||||||
|
|
||||||
|
// Steps 7-9
|
||||||
|
if !previously_selectable && self.selection_api_applies() {
|
||||||
|
self.textinput.borrow_mut().clear_selection_to_limit(Direction::Backward);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
AttributeMutation::Removed => {
|
AttributeMutation::Removed => {
|
||||||
if self.input_type() == InputType::Radio {
|
if self.input_type() == InputType::Radio {
|
||||||
|
|
|
@ -36,7 +36,7 @@ use std::default::Default;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
use style::element_state::ElementState;
|
use style::element_state::ElementState;
|
||||||
use textinput::{KeyReaction, Lines, SelectionDirection, TextInput};
|
use textinput::{Direction, KeyReaction, Lines, SelectionDirection, TextInput};
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLTextAreaElement {
|
pub struct HTMLTextAreaElement {
|
||||||
|
@ -262,7 +262,7 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
|
||||||
|
|
||||||
if old_value != textinput.get_content() {
|
if old_value != textinput.get_content() {
|
||||||
// Step 4
|
// Step 4
|
||||||
textinput.clear_selection_to_limit();
|
textinput.clear_selection_to_limit(Direction::Forward);
|
||||||
} else {
|
} else {
|
||||||
textinput.selection_origin = old_selection;
|
textinput.selection_origin = old_selection;
|
||||||
}
|
}
|
||||||
|
|
|
@ -533,9 +533,9 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the current selection and set the edit point to the end of the content.
|
/// Remove the current selection and set the edit point to the end of the content.
|
||||||
pub fn clear_selection_to_limit(&mut self) {
|
pub fn clear_selection_to_limit(&mut self, direction: Direction) {
|
||||||
self.clear_selection();
|
self.clear_selection();
|
||||||
self.adjust_horizontal_to_limit(Direction::Forward, Selection::NotSelected);
|
self.adjust_horizontal_to_limit(direction, Selection::NotSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn adjust_horizontal_by_word(&mut self, direction: Direction, select: Selection) {
|
pub fn adjust_horizontal_by_word(&mut self, direction: Direction, select: Selection) {
|
||||||
|
|
|
@ -553459,7 +553459,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"html/semantics/forms/the-input-element/type-change-state.html": [
|
"html/semantics/forms/the-input-element/type-change-state.html": [
|
||||||
"d731573ee091b7e658ea0b1ded46a764e8165f6c",
|
"6ca94002609dae5548e5c832e4a84639c1094f69",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"html/semantics/forms/the-input-element/url.html": [
|
"html/semantics/forms/the-input-element/url.html": [
|
||||||
|
|
|
@ -31,6 +31,11 @@
|
||||||
{ type: "reset" },
|
{ type: "reset" },
|
||||||
{ type: "button" }
|
{ type: "button" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const selectionStart = 2;
|
||||||
|
const selectionEnd = 5;
|
||||||
|
const selectionDirection = "backward";
|
||||||
|
|
||||||
for (var i = 0; i < types.length; i++) {
|
for (var i = 0; i < types.length; i++) {
|
||||||
for (var j = 0; j < types.length; j++) {
|
for (var j = 0; j < types.length; j++) {
|
||||||
if (types[i] != types[j]) {
|
if (types[i] != types[j]) {
|
||||||
|
@ -49,6 +54,13 @@
|
||||||
assert_equals(input.value, "");
|
assert_equals(input.value, "");
|
||||||
} else {
|
} else {
|
||||||
input.value = expected;
|
input.value = expected;
|
||||||
|
|
||||||
|
const previouslySelectable = (input.selectionStart !== null);
|
||||||
|
|
||||||
|
if (previouslySelectable) {
|
||||||
|
input.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
|
||||||
|
}
|
||||||
|
|
||||||
input.type = types[j].type; // change state
|
input.type = types[j].type; // change state
|
||||||
|
|
||||||
// type[i] sanitization
|
// type[i] sanitization
|
||||||
|
@ -69,6 +81,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_equals(input.value, expected, "input.value should be '" + expected + "' after change of state");
|
assert_equals(input.value, expected, "input.value should be '" + expected + "' after change of state");
|
||||||
|
|
||||||
|
const nowSelectable = (input.selectionStart !== null);
|
||||||
|
|
||||||
|
if (nowSelectable) {
|
||||||
|
if (previouslySelectable) {
|
||||||
|
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, "none", "selectionDirection should be 'none'");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, "change state from " + types[i].type + " to " + types[j].type);
|
}, "change state from " + types[i].type + " to " + types[j].type);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue