diff --git a/components/script/dom/textcontrol.rs b/components/script/dom/textcontrol.rs index 4770b1ae18df..85211a7990d5 100644 --- a/components/script/dom/textcontrol.rs +++ b/components/script/dom/textcontrol.rs @@ -136,6 +136,9 @@ pub trait TextControl: DerivedFrom + DerivedFrom { // https://html.spec.whatwg.org/multipage/#set-the-selection-range fn set_selection_range(&self, start: Option, end: Option, direction: Option) { + let mut textinput = self.textinput().borrow_mut(); + let original_selection_state = textinput.selection_state(); + // Step 1 let start = start.unwrap_or(0); @@ -143,16 +146,18 @@ pub trait TextControl: DerivedFrom + DerivedFrom { let end = end.unwrap_or(0); // Steps 3-5 - self.textinput().borrow_mut().set_selection_range(start, end, direction.unwrap_or(SelectionDirection::None)); + textinput.set_selection_range(start, end, direction.unwrap_or(SelectionDirection::None)); // Step 6 - let window = window_from_node(self); - let _ = window.user_interaction_task_source().queue_event( - &self.upcast::(), - atom!("select"), - EventBubbles::Bubbles, - EventCancelable::NotCancelable, - &window); + if textinput.selection_state() != original_selection_state { + let window = window_from_node(self); + window.user_interaction_task_source().queue_event( + &self.upcast::(), + atom!("select"), + EventBubbles::Bubbles, + EventCancelable::NotCancelable, + &window); + } self.upcast::().dirty(NodeDamage::OtherNodeDamage); } diff --git a/components/script/textinput.rs b/components/script/textinput.rs index d703ccee9879..7883b471117a 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -242,6 +242,12 @@ impl TextInput { self.selection_start_offset() .. self.selection_end_offset() } + /// A tuple containing the (start, end, direction) of the current selection. Can be used to + /// compare whether selection state has changed. + pub fn selection_state(&self) -> (TextPoint, TextPoint, SelectionDirection) { + (self.selection_start(), self.selection_end(), self.selection_direction) + } + // Check that the selection is valid. fn assert_ok_selection(&self) { if let Some(begin) = self.selection_origin { diff --git a/tests/wpt/metadata/html/semantics/forms/textfieldselection/select-event.html.ini b/tests/wpt/metadata/html/semantics/forms/textfieldselection/select-event.html.ini index 803dce040adb..cd5202d88ae1 100644 --- a/tests/wpt/metadata/html/semantics/forms/textfieldselection/select-event.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/textfieldselection/select-event.html.ini @@ -1,125 +1,35 @@ [select-event.html] type: testharness - [textarea: select() a second time (must not fire select)] - expected: FAIL - - [textarea: selectionStart a second time (must not fire select)] - expected: FAIL - - [textarea: selectionEnd a second time (must not fire select)] - expected: FAIL - - [textarea: selectionDirection a second time (must not fire select)] - expected: FAIL - - [textarea: setSelectionRange() a second time (must not fire select)] - expected: FAIL - [textarea: setRangeText()] expected: FAIL [textarea: setRangeText() a second time (must not fire select)] expected: FAIL - [input type text: select() a second time (must not fire select)] - expected: FAIL - - [input type text: selectionStart a second time (must not fire select)] - expected: FAIL - - [input type text: selectionEnd a second time (must not fire select)] - expected: FAIL - - [input type text: selectionDirection a second time (must not fire select)] - expected: FAIL - - [input type text: setSelectionRange() a second time (must not fire select)] - expected: FAIL - [input type text: setRangeText()] expected: FAIL [input type text: setRangeText() a second time (must not fire select)] expected: FAIL - [input type search: select() a second time (must not fire select)] - expected: FAIL - - [input type search: selectionStart a second time (must not fire select)] - expected: FAIL - - [input type search: selectionEnd a second time (must not fire select)] - expected: FAIL - - [input type search: selectionDirection a second time (must not fire select)] - expected: FAIL - - [input type search: setSelectionRange() a second time (must not fire select)] - expected: FAIL - [input type search: setRangeText()] expected: FAIL [input type search: setRangeText() a second time (must not fire select)] expected: FAIL - [input type tel: select() a second time (must not fire select)] - expected: FAIL - - [input type tel: selectionStart a second time (must not fire select)] - expected: FAIL - - [input type tel: selectionEnd a second time (must not fire select)] - expected: FAIL - - [input type tel: selectionDirection a second time (must not fire select)] - expected: FAIL - - [input type tel: setSelectionRange() a second time (must not fire select)] - expected: FAIL - [input type tel: setRangeText()] expected: FAIL [input type tel: setRangeText() a second time (must not fire select)] expected: FAIL - [input type url: select() a second time (must not fire select)] - expected: FAIL - - [input type url: selectionStart a second time (must not fire select)] - expected: FAIL - - [input type url: selectionEnd a second time (must not fire select)] - expected: FAIL - - [input type url: selectionDirection a second time (must not fire select)] - expected: FAIL - - [input type url: setSelectionRange() a second time (must not fire select)] - expected: FAIL - [input type url: setRangeText()] expected: FAIL [input type url: setRangeText() a second time (must not fire select)] expected: FAIL - [input type password: select() a second time (must not fire select)] - expected: FAIL - - [input type password: selectionStart a second time (must not fire select)] - expected: FAIL - - [input type password: selectionEnd a second time (must not fire select)] - expected: FAIL - - [input type password: selectionDirection a second time (must not fire select)] - expected: FAIL - - [input type password: setSelectionRange() a second time (must not fire select)] - expected: FAIL - [input type password: setRangeText()] expected: FAIL