diff --git a/components/script/dom/htmlselectelement.rs b/components/script/dom/htmlselectelement.rs index 0f48c8e923f..2fd8f35c4d8 100644 --- a/components/script/dom/htmlselectelement.rs +++ b/components/script/dom/htmlselectelement.rs @@ -16,6 +16,8 @@ use embedder_traits::{SelectElementOptionOrOptgroup, SelectElementOption}; use euclid::{Size2D, Point2D, Rect}; use embedder_traits::{FormControl as EmbedderFormControl, EmbedderMsg}; +use crate::dom::bindings::refcounted::Trusted; +use crate::dom::event::{EventBubbles, EventCancelable, EventComposed}; use crate::dom::bindings::codegen::GenericBindings::HTMLOptGroupElementBinding::HTMLOptGroupElement_Binding::HTMLOptGroupElementMethods; use crate::dom::activation::Activatable; use crate::dom::attr::Attr; @@ -346,13 +348,6 @@ impl HTMLSelectElement { .SetData(displayed_text.trim().into()); } - pub(crate) fn selection_changed(&self, can_gc: CanGc) { - self.update_shadow_tree(can_gc); - - self.upcast::() - .fire_bubbling_event(atom!("change"), can_gc); - } - pub(crate) fn selected_option(&self) -> Option> { self.list_of_options() .find(|opt_elem| opt_elem.Selected()) @@ -417,12 +412,39 @@ impl HTMLSelectElement { return None; }; - if response.is_some() && response != selected_index { - self.selection_changed(can_gc); - } - response } + + /// + fn send_update_notifications(&self) { + // > When the user agent is to send select update notifications, queue an element task on the + // > user interaction task source given the select element to run these steps: + let this = Trusted::new(self); + self.owner_global() + .task_manager() + .user_interaction_task_source() + .queue(task!(send_select_update_notification: move || { + let this = this.root(); + + // TODO: Step 1. Set the select element's user validity to true. + + // Step 2. Fire an event named input at the select element, with the bubbles and composed + // attributes initialized to true. + this.upcast::() + .fire_event_with_params( + atom!("input"), + EventBubbles::Bubbles, + EventCancelable::NotCancelable, + EventComposed::Composed, + CanGc::note(), + ); + + // Step 3. Fire an event named change at the select element, with the bubbles attribute initialized + // to true. + this.upcast::() + .fire_bubbling_event(atom!("change"), CanGc::note()); + })); + } } impl HTMLSelectElementMethods for HTMLSelectElement { @@ -578,21 +600,28 @@ impl HTMLSelectElementMethods for HTMLSelectElement { /// fn SetSelectedIndex(&self, index: i32, can_gc: CanGc) { + let mut selection_did_change = false; + let mut opt_iter = self.list_of_options(); for opt in opt_iter.by_ref().take(index as usize) { + selection_did_change |= opt.Selected(); opt.set_selectedness(false); } - if let Some(opt) = opt_iter.next() { - opt.set_selectedness(true); - opt.set_dirtiness(true); + if let Some(selected_option) = opt_iter.next() { + selection_did_change |= !selected_option.Selected(); + selected_option.set_selectedness(true); + selected_option.set_dirtiness(true); + // Reset remaining