diff options
author | Jon Leighton <j@jonathanleighton.com> | 2017-12-02 10:53:50 +0100 |
---|---|---|
committer | Jon Leighton <j@jonathanleighton.com> | 2017-12-08 21:07:05 +0100 |
commit | 71a013dd5018294f507c7047ca0d4fd700b555f1 (patch) | |
tree | 86bdd1d4f1a1676b1e973d2c047abd2b7c519c5b /components | |
parent | e64647188879b8269b62c1d5c8aa05732ab9d96d (diff) | |
download | servo-71a013dd5018294f507c7047ca0d4fd700b555f1.tar.gz servo-71a013dd5018294f507c7047ca0d4fd700b555f1.zip |
Handle cases where selection API doesn't apply
The selection API only applies to certain <input> types:
https://html.spec.whatwg.org/multipage/#do-not-apply
This commit ensures that we handle that correctly.
Some notes:
1. TextControl::set_dom_selection_direction now calls
set_selection_range(), which means that setting selectionDirection will
now fire a selection event, as it should per the spec.
2. There is a test for the firing of the select event in
tests/wpt/web-platform-tests/html/semantics/forms/textfieldselection/select-event.html,
however the test did not run due to this syntax error:
(pid:26017) "ERROR:script::dom::bindings::error: Error at http://web-platform.test:8000/html/semantics/forms/textfieldselection/select-event.html:50:11 missing = in const declaration"
This happens due to the us of the "for (const foo of ...)" construct.
Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
this should actually work, so it's somewhat unsatisfying to have to
change the test.
4. If an <input>'s type is unset, it defaults to a text, and the
selection API applies. Also, if an <input>'s type is set to an
invalid value, it defaults to a text too. I've expanded the tests
to account for this second case.
Diffstat (limited to 'components')
-rwxr-xr-x | components/script/dom/htmlinputelement.rs | 38 | ||||
-rwxr-xr-x | components/script/dom/htmltextareaelement.rs | 33 | ||||
-rw-r--r-- | components/script/dom/textcontrol.rs | 108 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLInputElement.webidl | 12 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLTextAreaElement.webidl | 12 | ||||
-rw-r--r-- | components/script/textinput.rs | 8 |
6 files changed, 149 insertions, 62 deletions
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index d748919914e..998b9b275e1 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -408,6 +408,18 @@ impl TextControl for HTMLInputElement { fn textinput(&self) -> &DomRefCell<TextInput<ScriptToConstellationChan>> { &self.textinput } + + // https://html.spec.whatwg.org/multipage/#concept-input-apply + fn selection_api_applies(&self) -> bool { + match self.input_type() { + InputType::Text | InputType::Search | InputType::Url + | InputType::Tel | InputType::Password => { + true + }, + + _ => false + } + } } impl HTMLInputElementMethods for HTMLInputElement { @@ -679,38 +691,38 @@ impl HTMLInputElementMethods for HTMLInputElement { } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart - fn SelectionStart(&self) -> u32 { - self.dom_selection_start() + fn GetSelectionStart(&self) -> Option<u32> { + self.get_dom_selection_start() } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart - fn SetSelectionStart(&self, start: u32) { - self.set_dom_selection_start(start); + fn SetSelectionStart(&self, start: Option<u32>) -> ErrorResult { + self.set_dom_selection_start(start) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend - fn SelectionEnd(&self) -> u32 { - self.dom_selection_end() + fn GetSelectionEnd(&self) -> Option<u32> { + self.get_dom_selection_end() } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend - fn SetSelectionEnd(&self, end: u32) { + fn SetSelectionEnd(&self, end: Option<u32>) -> ErrorResult { self.set_dom_selection_end(end) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection - fn SelectionDirection(&self) -> DOMString { - self.dom_selection_direction() + fn GetSelectionDirection(&self) -> Option<DOMString> { + self.get_dom_selection_direction() } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection - fn SetSelectionDirection(&self, direction: DOMString) { - self.set_dom_selection_direction(direction); + fn SetSelectionDirection(&self, direction: Option<DOMString>) -> ErrorResult { + self.set_dom_selection_direction(direction) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange - fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) { - self.set_dom_selection_range(start, end, direction); + fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) -> ErrorResult { + self.set_dom_selection_range(start, end, direction) } // Select the files based on filepaths passed in, diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index b9a6ad3ff69..7996eecc563 100755 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -8,6 +8,7 @@ use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding; use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::error::ErrorResult; use dom::bindings::inheritance::Castable; use dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom}; use dom::bindings::str::DOMString; @@ -145,6 +146,10 @@ impl TextControl for HTMLTextAreaElement { fn textinput(&self) -> &DomRefCell<TextInput<ScriptToConstellationChan>> { &self.textinput } + + fn selection_api_applies(&self) -> bool { + true + } } impl HTMLTextAreaElementMethods for HTMLTextAreaElement { @@ -260,38 +265,38 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement { } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart - fn SelectionStart(&self) -> u32 { - self.dom_selection_start() + fn GetSelectionStart(&self) -> Option<u32> { + self.get_dom_selection_start() } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart - fn SetSelectionStart(&self, start: u32) { - self.set_dom_selection_start(start); + fn SetSelectionStart(&self, start: Option<u32>) -> ErrorResult { + self.set_dom_selection_start(start) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend - fn SelectionEnd(&self) -> u32 { - self.dom_selection_end() + fn GetSelectionEnd(&self) -> Option<u32> { + self.get_dom_selection_end() } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend - fn SetSelectionEnd(&self, end: u32) { - self.set_dom_selection_end(end); + fn SetSelectionEnd(&self, end: Option<u32>) -> ErrorResult { + self.set_dom_selection_end(end) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection - fn SelectionDirection(&self) -> DOMString { - self.dom_selection_direction() + fn GetSelectionDirection(&self) -> Option<DOMString> { + self.get_dom_selection_direction() } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection - fn SetSelectionDirection(&self, direction: DOMString) { - self.set_dom_selection_direction(direction); + fn SetSelectionDirection(&self, direction: Option<DOMString>) -> ErrorResult { + self.set_dom_selection_direction(direction) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange - fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) { - self.set_dom_selection_range(start, end, direction); + fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) -> ErrorResult { + self.set_dom_selection_range(start, end, direction) } } diff --git a/components/script/dom/textcontrol.rs b/components/script/dom/textcontrol.rs index 2b47fcd00a4..9143c2bda23 100644 --- a/components/script/dom/textcontrol.rs +++ b/components/script/dom/textcontrol.rs @@ -4,6 +4,7 @@ use dom::bindings::cell::DomRefCell; use dom::bindings::conversions::DerivedFrom; +use dom::bindings::error::{Error, ErrorResult}; use dom::bindings::str::DOMString; use dom::event::{EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; @@ -13,52 +14,108 @@ use textinput::{SelectionDirection, TextInput}; pub trait TextControl: DerivedFrom<EventTarget> + DerivedFrom<Node> { fn textinput(&self) -> &DomRefCell<TextInput<ScriptToConstellationChan>>; + fn selection_api_applies(&self) -> bool; // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart - fn dom_selection_start(&self) -> u32 { - self.textinput().borrow().get_selection_start() + fn get_dom_selection_start(&self) -> Option<u32> { + // Step 1 + if !self.selection_api_applies() { + return None; + } + + // Steps 2-3 + Some(self.selection_start()) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart - fn set_dom_selection_start(&self, start: u32) { + fn set_dom_selection_start(&self, start: Option<u32>) -> ErrorResult { + // Step 1 + if !self.selection_api_applies() { + return Err(Error::InvalidState); + } + // Step 2 - let mut end = self.dom_selection_end(); + let mut end = self.selection_end(); // Step 3 - if end < start { - end = start; + if let Some(s) = start { + if end < s { + end = s; + } } // Step 4 - self.set_selection_range(start, end, self.selection_direction()); + self.set_selection_range(start, Some(end), Some(self.selection_direction())); + Ok(()) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend - fn dom_selection_end(&self) -> u32 { - self.textinput().borrow().get_absolute_insertion_point() as u32 + fn get_dom_selection_end(&self) -> Option<u32> { + // Step 1 + if !self.selection_api_applies() { + return None; + } + + // Steps 2-3 + Some(self.selection_end()) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend - fn set_dom_selection_end(&self, end: u32) { - self.set_selection_range(self.dom_selection_start(), end, self.selection_direction()); + fn set_dom_selection_end(&self, end: Option<u32>) -> ErrorResult { + // Step 1 + if !self.selection_api_applies() { + return Err(Error::InvalidState); + } + + // Step 2 + self.set_selection_range(Some(self.selection_start()), end, Some(self.selection_direction())); + Ok(()) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection - fn dom_selection_direction(&self) -> DOMString { - DOMString::from(self.selection_direction()) + fn get_dom_selection_direction(&self) -> Option<DOMString> { + // Step 1 + if !self.selection_api_applies() { + return None; + } + + Some(DOMString::from(self.selection_direction())) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection - fn set_dom_selection_direction(&self, direction: DOMString) { - self.textinput().borrow_mut().selection_direction = SelectionDirection::from(direction); + fn set_dom_selection_direction(&self, direction: Option<DOMString>) -> ErrorResult { + // Step 1 + if !self.selection_api_applies() { + return Err(Error::InvalidState); + } + + // Step 2 + self.set_selection_range( + Some(self.selection_start()), + Some(self.selection_end()), + direction.map(|d| SelectionDirection::from(d)) + ); + Ok(()) } // https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange - fn set_dom_selection_range(&self, start: u32, end: u32, direction: Option<DOMString>) { - // Step 4 - let direction = direction.map_or(SelectionDirection::None, |d| SelectionDirection::from(d)); + fn set_dom_selection_range(&self, start: u32, end: u32, direction: Option<DOMString>) -> ErrorResult { + // Step 1 + if !self.selection_api_applies() { + return Err(Error::InvalidState); + } + + // Step 2 + self.set_selection_range(Some(start), Some(end), direction.map(|d| SelectionDirection::from(d))); + Ok(()) + } - self.set_selection_range(start, end, direction); + fn selection_start(&self) -> u32 { + self.textinput().borrow().get_selection_start() + } + + fn selection_end(&self) -> u32 { + self.textinput().borrow().get_absolute_insertion_point() as u32 } fn selection_direction(&self) -> SelectionDirection { @@ -66,12 +123,15 @@ pub trait TextControl: DerivedFrom<EventTarget> + DerivedFrom<Node> { } // https://html.spec.whatwg.org/multipage/#set-the-selection-range - fn set_selection_range(&self, start: u32, end: u32, direction: SelectionDirection) { - // Step 5 - self.textinput().borrow_mut().selection_direction = direction; + fn set_selection_range(&self, start: Option<u32>, end: Option<u32>, direction: Option<SelectionDirection>) { + // Step 1 + let start = start.unwrap_or(0); - // Step 3 - self.textinput().borrow_mut().set_selection_range(start, end); + // Step 2 + let end = end.unwrap_or(0); + + // Steps 3-5 + self.textinput().borrow_mut().set_selection_range(start, end, direction.unwrap_or(SelectionDirection::None)); // Step 6 let window = window_from_node(self); diff --git a/components/script/dom/webidls/HTMLInputElement.webidl b/components/script/dom/webidls/HTMLInputElement.webidl index 29bc4b27737..93a5a7f108b 100644 --- a/components/script/dom/webidls/HTMLInputElement.webidl +++ b/components/script/dom/webidls/HTMLInputElement.webidl @@ -90,13 +90,17 @@ interface HTMLInputElement : HTMLElement { readonly attribute NodeList labels; //void select(); - attribute unsigned long selectionStart; - attribute unsigned long selectionEnd; - attribute DOMString selectionDirection; + [SetterThrows] + attribute unsigned long? selectionStart; + [SetterThrows] + attribute unsigned long? selectionEnd; + [SetterThrows] + 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); + [Throws] + void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction); // also has obsolete members diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl index 2e2e1288559..f0e8a0be118 100644 --- a/components/script/dom/webidls/HTMLTextAreaElement.webidl +++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl @@ -51,11 +51,15 @@ interface HTMLTextAreaElement : HTMLElement { readonly attribute NodeList labels; // void select(); - attribute unsigned long selectionStart; - attribute unsigned long selectionEnd; - attribute DOMString selectionDirection; + [SetterThrows] + attribute unsigned long? selectionStart; + [SetterThrows] + attribute unsigned long? selectionEnd; + [SetterThrows] + 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); + [Throws] + void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction); }; diff --git a/components/script/textinput.rs b/components/script/textinput.rs index 310e0566453..0fe0024a116 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -21,7 +21,7 @@ pub enum Selection { NotSelected } -#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)] pub enum SelectionDirection { Forward, Backward, @@ -825,7 +825,7 @@ impl<T: ClipboardProvider> TextInput<T> { } } - pub fn set_selection_range(&mut self, start: u32, end: u32) { + pub fn set_selection_range(&mut self, start: u32, end: u32, direction: SelectionDirection) { let mut start = start as usize; let mut end = end as usize; let text_end = self.get_content().len(); @@ -837,7 +837,9 @@ impl<T: ClipboardProvider> TextInput<T> { start = end; } - match self.selection_direction { + self.selection_direction = direction; + + match direction { SelectionDirection::None | SelectionDirection::Forward => { self.selection_begin = Some(self.get_text_point_for_absolute_point(start)); |