diff options
-rw-r--r-- | components/script/dom/htmlinputelement.rs | 86 | ||||
-rw-r--r-- | components/script/dom/htmltextareaelement.rs | 47 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLTextAreaElement.webidl | 8 | ||||
-rw-r--r-- | components/script/textinput.rs | 65 | ||||
-rw-r--r-- | tests/unit/script/textinput.rs | 36 | ||||
-rw-r--r-- | tests/wpt/metadata/html/dom/interfaces.html.ini | 27 | ||||
-rw-r--r-- | tests/wpt/metadata/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html.ini | 59 |
7 files changed, 150 insertions, 178 deletions
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 9c969ceec98..ab753053b8f 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -42,7 +42,7 @@ use string_cache::Atom; use style::element_state::*; use textinput::KeyReaction::{DispatchInput, Nothing, RedrawSelection, TriggerDefaultAction}; use textinput::Lines::Single; -use textinput::TextInput; +use textinput::{TextInput, SelectionDirection}; use util::str::{DOMString, search_index}; const DEFAULT_SUBMIT_VALUE: &'static str = "Submit"; @@ -71,14 +71,6 @@ enum ValueMode { Filename, } -#[derive(JSTraceable, PartialEq, Copy, Clone)] -#[derive(HeapSizeOf)] -enum SelectionDirection { - Forward, - Backward, - None -} - #[dom_struct] pub struct HTMLInputElement { htmlelement: HTMLElement, @@ -94,8 +86,6 @@ pub struct HTMLInputElement { // https://html.spec.whatwg.org/multipage/#concept-input-value-dirty-flag value_dirty: Cell<bool>, - selection_direction: Cell<SelectionDirection>, - // TODO: selected files for file input } @@ -142,10 +132,9 @@ impl HTMLInputElement { value_changed: Cell::new(false), maxlength: Cell::new(DEFAULT_MAX_LENGTH), size: Cell::new(DEFAULT_INPUT_SIZE), - textinput: DOMRefCell::new(TextInput::new(Single, DOMString::new(), chan, None)), + textinput: DOMRefCell::new(TextInput::new(Single, DOMString::new(), chan, None, SelectionDirection::None)), activation_state: DOMRefCell::new(InputActivationState::new()), value_dirty: Cell::new(false), - selection_direction: Cell::new(SelectionDirection::None) } } @@ -177,33 +166,6 @@ impl HTMLInputElement { InputType::InputFile => ValueMode::Filename, } } - - // this method exists so that the functions SetSelectionStart() and SetSelectionEnd() - // don't needlessly allocate strings - fn set_selection_range(&self, start: u32, end: u32, direction: &SelectionDirection) { - let mut text_input = self.textinput.borrow_mut(); - - let mut start = start as usize; - let mut end = end as usize; - - let text_end = text_input.get_content().len(); - if start > text_end { - start = text_end; - } - if end > text_end { - end = text_end; - } - - if start >= end { - start = end; - } - - text_input.selection_begin = Some(text_input.get_text_point_for_absolute_point(start)); - text_input.edit_point = text_input.get_text_point_for_absolute_point(end); - self.selection_direction.set(*direction); - self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); - } - } pub trait LayoutHTMLInputElementHelpers { @@ -547,60 +509,44 @@ impl HTMLInputElementMethods for HTMLInputElement { // https://html.spec.whatwg.org/multipage/#dom-input-selectionstart fn SelectionStart(&self) -> u32 { - let text_input = self.textinput.borrow(); - let selection_start = match text_input.selection_begin { - Some(selection_begin_point) => { - text_input.get_absolute_point_for_text_point(&selection_begin_point) - }, - None => text_input.get_absolute_insertion_point() - }; - - selection_start as u32 + self.textinput.borrow().get_selection_start() } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart fn SetSelectionStart(&self, start: u32) { - self.set_selection_range(start, self.SelectionEnd(), &self.selection_direction.get()); + let selection_end = self.SelectionEnd(); + self.textinput.borrow_mut().set_selection_range(start, selection_end); + self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend fn SelectionEnd(&self) -> u32 { - let text_input = self.textinput.borrow(); - text_input.get_absolute_insertion_point() as u32 + self.textinput.borrow().get_absolute_insertion_point() as u32 } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend fn SetSelectionEnd(&self, end: u32) { - self.set_selection_range(self.SelectionStart(), end, &self.selection_direction.get()); + let selection_start = self.SelectionStart(); + self.textinput.borrow_mut().set_selection_range(selection_start, end); + self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection fn SelectionDirection(&self) -> DOMString { - match self.selection_direction.get() { - SelectionDirection::Forward => DOMString::from("forward"), - SelectionDirection::Backward => DOMString::from("backward"), - SelectionDirection::None => DOMString::from("none"), - } + DOMString::from(self.textinput.borrow().selection_direction) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection fn SetSelectionDirection(&self, direction: DOMString) { - self.SetSelectionRange(self.SelectionStart(), self.SelectionEnd(), Some(direction)); + self.textinput.borrow_mut().selection_direction = SelectionDirection::from(direction); } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) { - let selection_direction = match direction { - Some(selection_direction) => { - match &*selection_direction { - "forward" => SelectionDirection::Forward, - "backward" => SelectionDirection::Backward, - _ => SelectionDirection::None, - } - }, - None => SelectionDirection::None, - }; - self.set_selection_range(start, end, &selection_direction); + let direction = direction.map_or(SelectionDirection::None, |d| SelectionDirection::from(d)); + self.textinput.borrow_mut().selection_direction = direction; + self.textinput.borrow_mut().set_selection_range(start, end); + self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } } diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index a9f8f170889..d3eb7827031 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -31,7 +31,7 @@ use script_traits::ScriptMsg as ConstellationMsg; use std::cell::Cell; use string_cache::Atom; use style::element_state::*; -use textinput::{KeyReaction, Lines, TextInput}; +use textinput::{KeyReaction, Lines, TextInput, SelectionDirection}; use util::str::DOMString; #[dom_struct] @@ -106,7 +106,8 @@ impl HTMLTextAreaElement { htmlelement: HTMLElement::new_inherited_with_state(IN_ENABLED_STATE, localName, prefix, document), - textinput: DOMRefCell::new(TextInput::new(Lines::Multiple, DOMString::new(), chan, None)), + textinput: DOMRefCell::new(TextInput::new( + Lines::Multiple, DOMString::new(), chan, None, SelectionDirection::None)), value_changed: Cell::new(false), } } @@ -216,6 +217,48 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement { fn Labels(&self) -> Root<NodeList> { self.upcast::<HTMLElement>().labels() } + + // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection + fn SetSelectionDirection(&self, direction: DOMString) { + self.textinput.borrow_mut().selection_direction = SelectionDirection::from(direction); + } + + // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection + fn SelectionDirection(&self) -> DOMString { + DOMString::from(self.textinput.borrow().selection_direction) + } + + // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend + fn SetSelectionEnd(&self, end: u32) { + let selection_start = self.SelectionStart(); + self.textinput.borrow_mut().set_selection_range(selection_start, end); + self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); + } + + // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend + fn SelectionEnd(&self) -> u32 { + self.textinput.borrow().get_absolute_insertion_point() as u32 + } + + // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart + fn SetSelectionStart(&self, start: u32) { + let selection_end = self.SelectionEnd(); + self.textinput.borrow_mut().set_selection_range(start, selection_end); + self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); + } + + // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart + fn SelectionStart(&self) -> u32 { + self.textinput.borrow().get_selection_start() + } + + // https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange + fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) { + let direction = direction.map_or(SelectionDirection::None, |d| SelectionDirection::from(d)); + self.textinput.borrow_mut().selection_direction = direction; + self.textinput.borrow_mut().set_selection_range(start, end); + self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); + } } diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl index 797a537d0cc..e5e2cabdb78 100644 --- a/components/script/dom/webidls/HTMLTextAreaElement.webidl +++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl @@ -38,11 +38,11 @@ interface HTMLTextAreaElement : HTMLElement { readonly attribute NodeList labels; //void select(); - // attribute unsigned long selectionStart; - // attribute unsigned long selectionEnd; - // attribute DOMString selectionDirection; + attribute unsigned long selectionStart; + attribute unsigned long selectionEnd; + attribute DOMString selectionDirection; //void setRangeText(DOMString replacement); //void setRangeText(DOMString replacement, unsigned long start, unsigned long end, // optional SelectionMode selectionMode = "preserve"); - //void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction); + void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction); }; diff --git a/components/script/textinput.rs b/components/script/textinput.rs index 1be7962003c..ffd707c5d27 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -21,6 +21,33 @@ pub enum Selection { NotSelected } +#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)] +pub enum SelectionDirection { + Forward, + Backward, + None, +} + +impl From<DOMString> for SelectionDirection { + fn from(direction: DOMString) -> SelectionDirection { + match direction.as_ref() { + "forward" => SelectionDirection::Forward, + "backward" => SelectionDirection::Backward, + _ => SelectionDirection::None, + } + } +} + +impl From<SelectionDirection> for DOMString { + fn from(direction: SelectionDirection) -> DOMString { + match direction { + SelectionDirection::Forward => DOMString::from("forward"), + SelectionDirection::Backward => DOMString::from("backward"), + SelectionDirection::None => DOMString::from("none"), + } + } +} + #[derive(JSTraceable, Copy, Clone, HeapSizeOf, PartialEq)] pub struct TextPoint { /// 0-based line number @@ -45,7 +72,8 @@ pub struct TextInput<T: ClipboardProvider> { /// The maximum number of UTF-16 code units this text input is allowed to hold. /// /// https://html.spec.whatwg.org/multipage/#attr-fe-maxlength - pub max_length: Option<usize> + pub max_length: Option<usize>, + pub selection_direction: SelectionDirection, } /// Resulting action to be taken by the owner of a text input that is handling an event. @@ -138,14 +166,17 @@ fn len_of_first_n_code_units(text: &str, n: usize) -> usize { impl<T: ClipboardProvider> TextInput<T> { /// Instantiate a new text input control - pub fn new(lines: Lines, initial: DOMString, clipboard_provider: T, max_length: Option<usize>) -> TextInput<T> { + pub fn new(lines: Lines, initial: DOMString, + clipboard_provider: T, max_length: Option<usize>, + selection_direction: SelectionDirection) -> TextInput<T> { let mut i = TextInput { lines: vec!(), edit_point: Default::default(), selection_begin: None, multiline: lines == Lines::Multiple, clipboard_provider: clipboard_provider, - max_length: max_length + max_length: max_length, + selection_direction: selection_direction, }; i.set_content(initial); i @@ -607,4 +638,32 @@ impl<T: ClipboardProvider> TextInput<T> { line: line, index: index } } + + pub fn set_selection_range(&mut self, start: u32, end: u32) { + let mut start = start as usize; + let mut end = end as usize; + let text_end = self.get_content().len(); + + if start > text_end { + start = text_end; + } else if end > text_end { + end = text_end; + } else if start >= end { + start = end; + } + + self.selection_begin = Some(self.get_text_point_for_absolute_point(start)); + self.edit_point = self.get_text_point_for_absolute_point(end); + } + + pub fn get_selection_start(&self) -> u32 { + let selection_start = match self.selection_begin { + Some(selection_begin_point) => { + self.get_absolute_point_for_text_point(&selection_begin_point) + }, + None => self.get_absolute_insertion_point() + }; + + selection_start as u32 + } } diff --git a/tests/unit/script/textinput.rs b/tests/unit/script/textinput.rs index 318612e64af..52c5808c30a 100644 --- a/tests/unit/script/textinput.rs +++ b/tests/unit/script/textinput.rs @@ -13,17 +13,17 @@ use msg::constellation_msg::CONTROL; use msg::constellation_msg::SUPER; use msg::constellation_msg::{Key, KeyModifiers}; use script::clipboard_provider::DummyClipboardContext; -use script::textinput::{TextInput, TextPoint, Selection, Lines, Direction}; +use script::textinput::{TextInput, TextPoint, Selection, Lines, Direction, SelectionDirection}; use util::str::DOMString; fn text_input(lines: Lines, s: &str) -> TextInput<DummyClipboardContext> { - TextInput::new(lines, DOMString::from(s), DummyClipboardContext::new(""), None) + TextInput::new(lines, DOMString::from(s), DummyClipboardContext::new(""), None, SelectionDirection::None) } #[test] fn test_set_content_ignores_max_length() { let mut textinput = TextInput::new( - Lines::Single, DOMString::from(""), DummyClipboardContext::new(""), Some(1) + Lines::Single, DOMString::from(""), DummyClipboardContext::new(""), Some(1), SelectionDirection::None ); textinput.set_content(DOMString::from("mozilla rocks")); @@ -36,7 +36,8 @@ fn test_textinput_when_inserting_multiple_lines_over_a_selection_respects_max_le Lines::Multiple, DOMString::from("hello\nworld"), DummyClipboardContext::new(""), - Some(17) + Some(17), + SelectionDirection::None, ); textinput.edit_point = TextPoint { line: 0, index: 1 }; @@ -59,7 +60,8 @@ fn test_textinput_when_inserting_multiple_lines_still_respects_max_length() { Lines::Multiple, DOMString::from("hello\nworld"), DummyClipboardContext::new(""), - Some(17) + Some(17), + SelectionDirection::None ); textinput.edit_point = TextPoint { line: 1, index: 0 }; @@ -75,7 +77,8 @@ fn test_textinput_when_content_is_already_longer_than_max_length_and_theres_no_s Lines::Single, DOMString::from("abc"), DummyClipboardContext::new(""), - Some(1) + Some(1), + SelectionDirection::None, ); textinput.insert_char('a'); @@ -89,7 +92,8 @@ fn test_multi_line_textinput_with_maxlength_doesnt_allow_appending_characters_wh Lines::Multiple, DOMString::from("abc\nd"), DummyClipboardContext::new(""), - Some(5) + Some(5), + SelectionDirection::None, ); textinput.insert_char('a'); @@ -103,7 +107,8 @@ fn test_single_line_textinput_with_max_length_doesnt_allow_appending_characters_ Lines::Single, DOMString::from("abcde"), DummyClipboardContext::new(""), - Some(5) + Some(5), + SelectionDirection::None, ); textinput.edit_point = TextPoint { line: 0, index: 1 }; @@ -123,7 +128,8 @@ fn test_single_line_textinput_with_max_length_multibyte() { Lines::Single, DOMString::from(""), DummyClipboardContext::new(""), - Some(2) + Some(2), + SelectionDirection::None, ); textinput.insert_char('á'); @@ -140,7 +146,8 @@ fn test_single_line_textinput_with_max_length_multi_code_unit() { Lines::Single, DOMString::from(""), DummyClipboardContext::new(""), - Some(3) + Some(3), + SelectionDirection::None, ); textinput.insert_char('\u{10437}'); @@ -159,7 +166,8 @@ fn test_single_line_textinput_with_max_length_inside_char() { Lines::Single, DOMString::from("\u{10437}"), DummyClipboardContext::new(""), - Some(1) + Some(1), + SelectionDirection::None, ); textinput.insert_char('x'); @@ -172,7 +180,8 @@ fn test_single_line_textinput_with_max_length_doesnt_allow_appending_characters_ Lines::Single, DOMString::from("a"), DummyClipboardContext::new(""), - Some(1) + Some(1), + SelectionDirection::None, ); textinput.insert_char('b'); @@ -388,7 +397,8 @@ fn test_clipboard_paste() { let mut textinput = TextInput::new(Lines::Single, DOMString::from("defg"), DummyClipboardContext::new("abc"), - None); + None, + SelectionDirection::None); assert_eq!(textinput.get_content(), "defg"); assert_eq!(textinput.edit_point.index, 0); textinput.handle_keydown_aux(Key::V, MODIFIERS); diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index 5af57f14c88..e16a669de1a 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -4836,24 +4836,12 @@ [HTMLTextAreaElement interface: operation select()] expected: FAIL - [HTMLTextAreaElement interface: attribute selectionStart] - expected: FAIL - - [HTMLTextAreaElement interface: attribute selectionEnd] - expected: FAIL - - [HTMLTextAreaElement interface: attribute selectionDirection] - expected: FAIL - [HTMLTextAreaElement interface: operation setRangeText(DOMString)] expected: FAIL [HTMLTextAreaElement interface: operation setRangeText(DOMString,unsigned long,unsigned long,SelectionMode)] expected: FAIL - [HTMLTextAreaElement interface: operation setSelectionRange(unsigned long,unsigned long,DOMString)] - expected: FAIL - [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "autocomplete" with the proper type (0)] expected: FAIL @@ -4899,15 +4887,6 @@ [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "select" with the proper type (26)] expected: FAIL - [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "selectionStart" with the proper type (27)] - expected: FAIL - - [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "selectionEnd" with the proper type (28)] - expected: FAIL - - [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "selectionDirection" with the proper type (29)] - expected: FAIL - [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "setRangeText" with the proper type (30)] expected: FAIL @@ -4920,12 +4899,6 @@ [HTMLTextAreaElement interface: calling setRangeText(DOMString,unsigned long,unsigned long,SelectionMode) on document.createElement("textarea") with too few arguments must throw TypeError] expected: FAIL - [HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "setSelectionRange" with the proper type (32)] - expected: FAIL - - [HTMLTextAreaElement interface: calling setSelectionRange(unsigned long,unsigned long,DOMString) on document.createElement("textarea") with too few arguments must throw TypeError] - expected: FAIL - [HTMLKeygenElement interface: existence and properties of interface object] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html.ini b/tests/wpt/metadata/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html.ini deleted file mode 100644 index b800a621e4b..00000000000 --- a/tests/wpt/metadata/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html.ini +++ /dev/null @@ -1,59 +0,0 @@ -[textfieldselection-setSelectionRange.html] - type: testharness - [textarea typeof(input.setSelectionRange)'] - expected: FAIL - - [textarea setSelectionRange return void] - expected: FAIL - - [textarea setSelectionRange(0,1)] - expected: FAIL - - [textarea setSelectionRange(0,textarea.value.length+1)] - expected: FAIL - - [textarea setSelectionRange(2,2)] - expected: FAIL - - [textarea setSelectionRange(2,1)] - expected: FAIL - - [textarea direction of setSelectionRange(0,1,"backward")] - expected: FAIL - - [textarea direction of setSelectionRange(0,1,"forward")] - expected: FAIL - - [textarea direction of setSelectionRange(0,1,"none")] - expected: FAIL - - [textarea direction of setSelectionRange(0,1,"hoge")] - expected: FAIL - - [textarea direction of setSelectionRange(0,1,"BACKWARD")] - expected: FAIL - - [textarea direction of setSelectionRange(0,1)] - expected: FAIL - - [textarea setSelectionRange("string",1)] - expected: FAIL - - [textarea setSelectionRange(true,1)] - expected: FAIL - - [textarea setSelectionRange([\],1)] - expected: FAIL - - [textarea setSelectionRange({},1)] - expected: FAIL - - [textarea setSelectionRange(NaN,1)] - expected: FAIL - - [textarea setSelectionRange(null,1)] - expected: FAIL - - [textarea setSelectionRange(undefined,1)] - expected: FAIL - |