mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Correct default selectionStart and selectionEnd
This commit is contained in:
parent
b517410a34
commit
87e7b1ee7a
7 changed files with 58 additions and 26 deletions
|
@ -550,18 +550,24 @@ impl HTMLInputElementMethods for HTMLInputElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-input-value
|
// https://html.spec.whatwg.org/multipage/#dom-input-value
|
||||||
fn SetValue(&self, value: DOMString) -> ErrorResult {
|
fn SetValue(&self, mut value: DOMString) -> ErrorResult {
|
||||||
match self.value_mode() {
|
match self.value_mode() {
|
||||||
ValueMode::Value => {
|
ValueMode::Value => {
|
||||||
// Steps 1-2.
|
|
||||||
let old_value = mem::replace(self.textinput.borrow_mut().single_line_content_mut(), value);
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
self.value_dirty.set(true);
|
self.value_dirty.set(true);
|
||||||
|
|
||||||
// Step 4.
|
// Step 4.
|
||||||
self.sanitize_value();
|
self.sanitize_value(&mut value);
|
||||||
|
|
||||||
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
|
|
||||||
// Step 5.
|
// Step 5.
|
||||||
if *self.textinput.borrow().single_line_content() != old_value {
|
if *textinput.single_line_content() != value {
|
||||||
self.textinput.borrow_mut().clear_selection_to_limit(Direction::Forward);
|
// Steps 1-2
|
||||||
|
textinput.set_content(value);
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
textinput.clear_selection_to_limit(Direction::Forward);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ValueMode::Default |
|
ValueMode::Default |
|
||||||
|
@ -935,8 +941,7 @@ impl HTMLInputElement {
|
||||||
InputType::Image => (),
|
InputType::Image => (),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
self.SetValue(self.DefaultValue())
|
self.textinput.borrow_mut().set_content(self.DefaultValue());
|
||||||
.expect("Failed to reset input value to default.");
|
|
||||||
self.value_dirty.set(false);
|
self.value_dirty.set(false);
|
||||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
}
|
}
|
||||||
|
@ -1093,7 +1098,6 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
|
|
||||||
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
|
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
|
||||||
self.super_type().unwrap().attribute_mutated(attr, mutation);
|
self.super_type().unwrap().attribute_mutated(attr, mutation);
|
||||||
|
|
||||||
match attr.local_name() {
|
match attr.local_name() {
|
||||||
&local_name!("disabled") => {
|
&local_name!("disabled") => {
|
||||||
let disabled_state = match mutation {
|
let disabled_state = match mutation {
|
||||||
|
@ -1194,11 +1198,11 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
let mut textinput = self.textinput.borrow_mut();
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
let mut value = textinput.single_line_content().clone();
|
let mut value = textinput.single_line_content().clone();
|
||||||
self.sanitize_value(&mut value);
|
self.sanitize_value(&mut value);
|
||||||
textinput.set_content(value, true);
|
textinput.set_content(value);
|
||||||
|
|
||||||
// Steps 7-9
|
// Steps 7-9
|
||||||
if !previously_selectable && self.selection_api_applies() {
|
if !previously_selectable && self.selection_api_applies() {
|
||||||
self.textinput.borrow_mut().clear_selection_to_limit(Direction::Backward);
|
textinput.clear_selection_to_limit(Direction::Backward);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttributeMutation::Removed => {
|
AttributeMutation::Removed => {
|
||||||
|
@ -1222,9 +1226,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
let mut value = value.map_or(DOMString::new(), DOMString::from);
|
let mut value = value.map_or(DOMString::new(), DOMString::from);
|
||||||
|
|
||||||
self.sanitize_value(&mut value);
|
self.sanitize_value(&mut value);
|
||||||
|
self.textinput.borrow_mut().set_content(value);
|
||||||
self.textinput.borrow_mut().set_content(
|
|
||||||
value.map_or(DOMString::new(), DOMString::from));
|
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
},
|
},
|
||||||
&local_name!("name") if self.input_type() == InputType::Radio => {
|
&local_name!("name") if self.input_type() == InputType::Radio => {
|
||||||
|
|
|
@ -248,7 +248,6 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
|
||||||
|
|
||||||
// Step 1
|
// Step 1
|
||||||
let old_value = textinput.get_content();
|
let old_value = textinput.get_content();
|
||||||
let old_selection = textinput.selection_origin;
|
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
textinput.set_content(value);
|
textinput.set_content(value);
|
||||||
|
@ -259,8 +258,6 @@ 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(Direction::Forward);
|
textinput.clear_selection_to_limit(Direction::Forward);
|
||||||
} else {
|
|
||||||
textinput.selection_origin = old_selection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
|
@ -327,7 +324,8 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
|
||||||
impl HTMLTextAreaElement {
|
impl HTMLTextAreaElement {
|
||||||
pub fn reset(&self) {
|
pub fn reset(&self) {
|
||||||
// https://html.spec.whatwg.org/multipage/#the-textarea-element:concept-form-reset-control
|
// https://html.spec.whatwg.org/multipage/#the-textarea-element:concept-form-reset-control
|
||||||
self.SetValue(self.DefaultValue());
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
|
textinput.set_content(self.DefaultValue());
|
||||||
self.value_dirty.set(false);
|
self.value_dirty.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -448,9 +448,7 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let col = self.lines[self.edit_point.line][..self.edit_point.index].chars().count();
|
let col = self.lines[self.edit_point.line][..self.edit_point.index].chars().count();
|
||||||
|
|
||||||
self.edit_point.line = target_line as usize;
|
self.edit_point.line = target_line as usize;
|
||||||
self.edit_point.index = len_of_first_n_chars(&self.lines[self.edit_point.line], col);
|
self.edit_point.index = len_of_first_n_chars(&self.lines[self.edit_point.line], col);
|
||||||
self.assert_ok_selection();
|
self.assert_ok_selection();
|
||||||
|
@ -887,7 +885,6 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
if let Some(origin) = self.selection_origin {
|
if let Some(origin) = self.selection_origin {
|
||||||
self.selection_origin = Some(origin.constrain_to(&self.lines));
|
self.selection_origin = Some(origin.constrain_to(&self.lines));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.assert_ok_selection();
|
self.assert_ok_selection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -494,10 +494,11 @@ fn test_textinput_set_content() {
|
||||||
|
|
||||||
assert_eq!(textinput.edit_point().line, 0);
|
assert_eq!(textinput.edit_point().line, 0);
|
||||||
assert_eq!(textinput.edit_point().index, 0);
|
assert_eq!(textinput.edit_point().index, 0);
|
||||||
|
|
||||||
textinput.adjust_horizontal(3, Selection::Selected);
|
textinput.adjust_horizontal(3, Selection::Selected);
|
||||||
assert_eq!(textinput.edit_point().line, 0);
|
assert_eq!(textinput.edit_point().line, 0);
|
||||||
assert_eq!(textinput.edit_point().index, 3);
|
assert_eq!(textinput.edit_point().index, 3);
|
||||||
textinput.set_content(DOMString::from("de"), true);
|
textinput.set_content(DOMString::from("de"));
|
||||||
assert_eq!(textinput.get_content(), "de");
|
assert_eq!(textinput.get_content(), "de");
|
||||||
assert_eq!(textinput.edit_point().line, 0);
|
assert_eq!(textinput.edit_point().line, 0);
|
||||||
assert_eq!(textinput.edit_point().index, 2);
|
assert_eq!(textinput.edit_point().index, 2);
|
||||||
|
@ -634,6 +635,10 @@ fn test_textinput_unicode_handling() {
|
||||||
fn test_selection_bounds() {
|
fn test_selection_bounds() {
|
||||||
let mut textinput = text_input(Lines::Single, "abcdef");
|
let mut textinput = text_input(Lines::Single, "abcdef");
|
||||||
|
|
||||||
|
assert_eq!(TextPoint { line: 0, index: 0 }, textinput.selection_origin_or_edit_point());
|
||||||
|
assert_eq!(TextPoint { line: 0, index: 0 }, textinput.selection_start());
|
||||||
|
assert_eq!(TextPoint { line: 0, index: 0 }, textinput.selection_end());
|
||||||
|
|
||||||
textinput.set_selection_range(2, 5, SelectionDirection::Forward);
|
textinput.set_selection_range(2, 5, SelectionDirection::Forward);
|
||||||
assert_eq!(TextPoint { line: 0, index: 2 }, textinput.selection_origin_or_edit_point());
|
assert_eq!(TextPoint { line: 0, index: 2 }, textinput.selection_origin_or_edit_point());
|
||||||
assert_eq!(TextPoint { line: 0, index: 2 }, textinput.selection_start());
|
assert_eq!(TextPoint { line: 0, index: 2 }, textinput.selection_start());
|
||||||
|
|
|
@ -330871,6 +330871,12 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"html/semantics/forms/textfieldselection/defaultSelection.html": [
|
||||||
|
[
|
||||||
|
"/html/semantics/forms/textfieldselection/defaultSelection.html",
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"html/semantics/forms/textfieldselection/select-event.html": [
|
"html/semantics/forms/textfieldselection/select-event.html": [
|
||||||
[
|
[
|
||||||
"/html/semantics/forms/textfieldselection/select-event.html",
|
"/html/semantics/forms/textfieldselection/select-event.html",
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[setSelectionRange.html]
|
|
||||||
[setSelectionRange on line boundaries]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title></title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<textarea>foo</textarea>
|
||||||
|
<input type="text" value="foo"></input>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
for (let el of [document.querySelector("textarea"), document.querySelector("input")]) {
|
||||||
|
test(function() {
|
||||||
|
assert_equals(el.selectionStart, 0);
|
||||||
|
assert_equals(el.selectionEnd, 0);
|
||||||
|
}, `Default selectionStart and selectionEnd for ${el}`);
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
el.value="foo";
|
||||||
|
assert_equals(el.selectionStart, 0);
|
||||||
|
assert_equals(el.selectionEnd, 0);
|
||||||
|
}, `selectionStart and selectionEnd do not change when same value set again for ${el}`);
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
el.value="Foo";
|
||||||
|
assert_equals(el.selectionStart, 3);
|
||||||
|
assert_equals(el.selectionEnd, 3);
|
||||||
|
}, `selectionStart and selectionEnd change when value changed to upper case for ${el}`);
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue