1use std::default::Default;
6use std::iter;
7
8use crate::dom::activation::Activatable;
9use crate::dom::attr::Attr;
10use crate::dom::bindings::cell::{DomRefCell, Ref};
11use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
12use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
13use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
14use crate::dom::bindings::codegen::Bindings::HTMLOptionElementBinding::HTMLOptionElementMethods;
15use crate::dom::bindings::codegen::Bindings::HTMLOptionsCollectionBinding::HTMLOptionsCollectionMethods;
16use crate::dom::bindings::codegen::Bindings::HTMLSelectElementBinding::HTMLSelectElementMethods;
17use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
18use crate::dom::bindings::codegen::GenericBindings::CharacterDataBinding::CharacterData_Binding::CharacterDataMethods;
19use crate::dom::bindings::codegen::GenericBindings::HTMLOptGroupElementBinding::HTMLOptGroupElement_Binding::HTMLOptGroupElementMethods;
20use crate::dom::bindings::codegen::UnionTypes::{
21 HTMLElementOrLong, HTMLOptionElementOrHTMLOptGroupElement,
22};
23use crate::dom::bindings::error::ErrorResult;
24use crate::dom::bindings::inheritance::Castable;
25use crate::dom::bindings::refcounted::Trusted;
26use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
27use crate::dom::bindings::str::DOMString;
28use crate::dom::characterdata::CharacterData;
29use crate::dom::document::Document;
30use crate::dom::document_embedder_controls::ControlElement;
31use crate::dom::element::{AttributeMutation, CustomElementCreationMode, Element, ElementCreator};
32use crate::dom::event::Event;
33use crate::dom::event::{EventBubbles, EventCancelable, EventComposed};
34use crate::dom::eventtarget::EventTarget;
35use crate::dom::html::htmlcollection::{CollectionFilter, CollectionSource, HTMLCollection};
36use crate::dom::html::htmlelement::HTMLElement;
37use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
38use crate::dom::html::htmlformelement::{FormControl, FormDatum, FormDatumValue, HTMLFormElement};
39use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
40use crate::dom::html::htmloptionelement::HTMLOptionElement;
41use crate::dom::html::htmloptionscollection::HTMLOptionsCollection;
42use crate::dom::node::{BindContext, ChildrenMutation, Node, NodeTraits, ShadowIncluding, UnbindContext};
43use crate::dom::nodelist::NodeList;
44use crate::dom::text::Text;
45use crate::dom::types::FocusEvent;
46use crate::dom::validation::{is_barred_by_datalist_ancestor, Validatable};
47use crate::dom::validitystate::{ValidationFlags, ValidityState};
48use crate::dom::virtualmethods::VirtualMethods;
49use crate::script_runtime::CanGc;
50use dom_struct::dom_struct;
51use embedder_traits::{EmbedderControlRequest, SelectElementRequest};
52use embedder_traits::{SelectElementOption, SelectElementOptionOrOptgroup};
53use html5ever::{local_name, ns, LocalName, Prefix, QualName};
54use js::context::JSContext;
55use js::rust::HandleObject;
56use style::attr::AttrValue;
57use stylo_dom::ElementState;
58
59const DEFAULT_SELECT_SIZE: u32 = 0;
60
61const SELECT_BOX_STYLE: &str = "
62 display: flex;
63 align-items: center;
64 height: 100%;
65 gap: 4px;
66";
67
68const TEXT_CONTAINER_STYLE: &str = "flex: 1;";
69
70const CHEVRON_CONTAINER_STYLE: &str = "
71 background-image: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"180\" height=\"180\" viewBox=\"0 0 180 180\"> <path d=\"M10 50h160L90 130z\" style=\"fill:currentcolor\"/> </svg>');
72 background-size: 100%;
73 background-repeat: no-repeat;
74 background-position: center;
75
76 vertical-align: middle;
77 line-height: 1;
78 display: inline-block;
79 width: 0.75em;
80 height: 0.75em;
81";
82
83#[derive(JSTraceable, MallocSizeOf)]
84struct OptionsFilter;
85impl CollectionFilter for OptionsFilter {
86 fn filter<'a>(&self, elem: &'a Element, root: &'a Node) -> bool {
87 if !elem.is::<HTMLOptionElement>() {
88 return false;
89 }
90
91 let node = elem.upcast::<Node>();
92 if root.is_parent_of(node) {
93 return true;
94 }
95
96 match node.GetParentNode() {
97 Some(optgroup) => optgroup.is::<HTMLOptGroupElement>() && root.is_parent_of(&optgroup),
98 None => false,
99 }
100 }
101}
102
103#[derive(JSTraceable, MallocSizeOf)]
106struct SelectedOptionsSource;
107impl CollectionSource for SelectedOptionsSource {
108 fn iter<'a>(&'a self, root: &'a Node) -> Box<dyn Iterator<Item = DomRoot<Element>> + 'a> {
109 let select = root
110 .downcast::<HTMLSelectElement>()
111 .expect("SelectedOptionsSource must be rooted on an HTMLSelectElement");
112 Box::new(
113 select
114 .list_of_options()
115 .filter(|option| option.Selected())
116 .map(DomRoot::upcast::<Element>),
117 )
118 }
119}
120
121#[dom_struct]
122pub(crate) struct HTMLSelectElement {
123 htmlelement: HTMLElement,
124 options: MutNullableDom<HTMLOptionsCollection>,
125 selected_options: MutNullableDom<HTMLCollection>,
126 form_owner: MutNullableDom<HTMLFormElement>,
127 labels_node_list: MutNullableDom<NodeList>,
128 validity_state: MutNullableDom<ValidityState>,
129 shadow_tree: DomRefCell<Option<ShadowTree>>,
130}
131
132#[derive(Clone, JSTraceable, MallocSizeOf)]
134#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
135struct ShadowTree {
136 selected_option: Dom<Text>,
137}
138
139impl HTMLSelectElement {
140 fn new_inherited(
141 local_name: LocalName,
142 prefix: Option<Prefix>,
143 document: &Document,
144 ) -> HTMLSelectElement {
145 HTMLSelectElement {
146 htmlelement: HTMLElement::new_inherited_with_state(
147 ElementState::ENABLED | ElementState::VALID,
148 local_name,
149 prefix,
150 document,
151 ),
152 options: Default::default(),
153 selected_options: Default::default(),
154 form_owner: Default::default(),
155 labels_node_list: Default::default(),
156 validity_state: Default::default(),
157 shadow_tree: Default::default(),
158 }
159 }
160
161 pub(crate) fn new(
162 cx: &mut js::context::JSContext,
163 local_name: LocalName,
164 prefix: Option<Prefix>,
165 document: &Document,
166 proto: Option<HandleObject>,
167 ) -> DomRoot<HTMLSelectElement> {
168 let n = Node::reflect_node_with_proto(
169 cx,
170 Box::new(HTMLSelectElement::new_inherited(
171 local_name, prefix, document,
172 )),
173 document,
174 proto,
175 );
176
177 n.upcast::<Node>().set_weird_parser_insertion_mode();
178 n
179 }
180
181 pub(crate) fn list_of_options(
183 &self,
184 ) -> impl Iterator<Item = DomRoot<HTMLOptionElement>> + use<'_> {
185 self.upcast::<Node>().children().flat_map(|node| {
186 if node.is::<HTMLOptionElement>() {
187 let node = DomRoot::downcast::<HTMLOptionElement>(node).unwrap();
188 Choice3::First(iter::once(node))
189 } else if node.is::<HTMLOptGroupElement>() {
190 Choice3::Second(node.children().filter_map(DomRoot::downcast))
191 } else {
192 Choice3::Third(iter::empty())
193 }
194 })
195 }
196
197 fn get_placeholder_label_option(&self) -> Option<DomRoot<HTMLOptionElement>> {
199 if self.Required() && !self.Multiple() && self.display_size() == 1 {
200 self.list_of_options().next().filter(|node| {
201 let parent = node.upcast::<Node>().GetParentNode();
202 node.Value().is_empty() && parent.as_deref() == Some(self.upcast())
203 })
204 } else {
205 None
206 }
207 }
208
209 pub(crate) fn reset(&self) {
211 for opt in self.list_of_options() {
212 opt.set_selectedness(opt.DefaultSelected());
213 opt.set_dirtiness(false);
214 }
215 self.ask_for_reset();
216 }
217
218 pub(crate) fn ask_for_reset(&self) {
220 if self.Multiple() {
221 return;
222 }
223
224 let mut first_enabled: Option<DomRoot<HTMLOptionElement>> = None;
225 let mut last_selected: Option<DomRoot<HTMLOptionElement>> = None;
226
227 for opt in self.list_of_options() {
228 if opt.Selected() {
229 opt.set_selectedness(false);
230 last_selected = Some(DomRoot::from_ref(&opt));
231 }
232 let element = opt.upcast::<Element>();
233 if first_enabled.is_none() && !element.disabled_state() {
234 first_enabled = Some(DomRoot::from_ref(&opt));
235 }
236 }
237
238 if let Some(last_selected) = last_selected {
239 last_selected.set_selectedness(true);
240 } else if self.display_size() == 1 {
241 if let Some(first_enabled) = first_enabled {
242 first_enabled.set_selectedness(true);
243 }
244 }
245 }
246
247 pub(crate) fn push_form_data(&self, data_set: &mut Vec<FormDatum>) {
248 if self.Name().is_empty() {
249 return;
250 }
251 for opt in self.list_of_options() {
252 let element = opt.upcast::<Element>();
253 if opt.Selected() && element.enabled_state() {
254 data_set.push(FormDatum {
255 ty: self.Type(),
256 name: self.Name(),
257 value: FormDatumValue::String(opt.Value()),
258 });
259 }
260 }
261 }
262
263 pub(crate) fn pick_option(&self, picked: &HTMLOptionElement) {
265 if !self.Multiple() {
266 let picked = picked.upcast();
267 for opt in self.list_of_options() {
268 if opt.upcast::<HTMLElement>() != picked {
269 opt.set_selectedness(false);
270 }
271 }
272 }
273 }
274
275 fn display_size(&self) -> u32 {
277 if self.Size() == 0 {
278 if self.Multiple() { 4 } else { 1 }
279 } else {
280 self.Size()
281 }
282 }
283
284 fn create_shadow_tree(&self, cx: &mut JSContext) {
285 let document = self.owner_document();
286 let root = self.upcast::<Element>().attach_ua_shadow_root(cx, true);
287
288 let select_box = Element::create(
289 cx,
290 QualName::new(None, ns!(html), local_name!("div")),
291 None,
292 &document,
293 ElementCreator::ScriptCreated,
294 CustomElementCreationMode::Asynchronous,
295 None,
296 );
297 select_box.set_string_attribute(
298 &local_name!("style"),
299 SELECT_BOX_STYLE.into(),
300 CanGc::from_cx(cx),
301 );
302
303 let text_container = Element::create(
304 cx,
305 QualName::new(None, ns!(html), local_name!("div")),
306 None,
307 &document,
308 ElementCreator::ScriptCreated,
309 CustomElementCreationMode::Asynchronous,
310 None,
311 );
312 text_container.set_string_attribute(
313 &local_name!("style"),
314 TEXT_CONTAINER_STYLE.into(),
315 CanGc::from_cx(cx),
316 );
317 select_box
318 .upcast::<Node>()
319 .AppendChild(cx, text_container.upcast::<Node>())
320 .unwrap();
321
322 let text = Text::new(cx, DOMString::new(), &document);
323 let _ = self.shadow_tree.borrow_mut().insert(ShadowTree {
324 selected_option: text.as_traced(),
325 });
326 text_container
327 .upcast::<Node>()
328 .AppendChild(cx, text.upcast::<Node>())
329 .unwrap();
330
331 let chevron_container = Element::create(
332 cx,
333 QualName::new(None, ns!(html), local_name!("div")),
334 None,
335 &document,
336 ElementCreator::ScriptCreated,
337 CustomElementCreationMode::Asynchronous,
338 None,
339 );
340 chevron_container.set_string_attribute(
341 &local_name!("style"),
342 CHEVRON_CONTAINER_STYLE.into(),
343 CanGc::from_cx(cx),
344 );
345 select_box
346 .upcast::<Node>()
347 .AppendChild(cx, chevron_container.upcast::<Node>())
348 .unwrap();
349
350 root.upcast::<Node>()
351 .AppendChild(cx, select_box.upcast::<Node>())
352 .unwrap();
353 }
354
355 fn shadow_tree(&self, cx: &mut JSContext) -> Ref<'_, ShadowTree> {
356 if !self.upcast::<Element>().is_shadow_host() {
357 self.create_shadow_tree(cx);
358 }
359
360 Ref::filter_map(self.shadow_tree.borrow(), Option::as_ref)
361 .ok()
362 .expect("UA shadow tree was not created")
363 }
364
365 pub(crate) fn update_shadow_tree(&self, cx: &mut JSContext) {
366 let shadow_tree = self.shadow_tree(cx);
367
368 let selected_options = self.selected_options();
369 let selected_options_count = selected_options.len();
370
371 let displayed_text = if selected_options_count == 1 {
372 let first_selected_option = self
373 .selected_option()
374 .or_else(|| self.list_of_options().next());
375
376 let first_selected_option_text = first_selected_option
377 .map(|option| option.displayed_label())
378 .unwrap_or_default();
379
380 itertools::join(first_selected_option_text.str().split_whitespace(), " ")
382 } else {
383 format!("{selected_options_count} selected")
384 };
385
386 shadow_tree
387 .selected_option
388 .upcast::<CharacterData>()
389 .SetData(displayed_text.trim().into());
390 }
391
392 pub(crate) fn selected_option(&self) -> Option<DomRoot<HTMLOptionElement>> {
393 self.list_of_options()
394 .find(|opt_elem| opt_elem.Selected())
395 .or_else(|| self.list_of_options().next())
396 }
397
398 pub(crate) fn selected_options(&self) -> Vec<DomRoot<HTMLOptionElement>> {
399 self.list_of_options()
400 .filter(|opt_elem| opt_elem.Selected())
401 .collect()
402 }
403
404 pub(crate) fn show_menu(&self) {
405 let mut index = 0;
407 let mut embedder_option_from_option = |option: &HTMLOptionElement| {
408 let embedder_option = SelectElementOption {
409 id: index,
410 label: option.displayed_label().into(),
411 is_disabled: option.Disabled(),
412 };
413 index += 1;
414 embedder_option
415 };
416 let options = self
417 .upcast::<Node>()
418 .children()
419 .flat_map(|child| {
420 if let Some(option) = child.downcast::<HTMLOptionElement>() {
421 return Some(embedder_option_from_option(option).into());
422 }
423
424 if let Some(optgroup) = child.downcast::<HTMLOptGroupElement>() {
425 let options = optgroup
426 .upcast::<Node>()
427 .children()
428 .flat_map(DomRoot::downcast::<HTMLOptionElement>)
429 .map(|option| embedder_option_from_option(&option))
430 .collect();
431 let label = optgroup.Label().into();
432
433 return Some(SelectElementOptionOrOptgroup::Optgroup { label, options });
434 }
435
436 None
437 })
438 .collect();
439
440 let selected_options = self
441 .list_of_options()
442 .enumerate()
443 .filter(|(_, option)| option.Selected())
444 .map(|(index, _)| index)
445 .collect();
446
447 self.owner_document()
448 .embedder_controls()
449 .show_embedder_control(
450 ControlElement::Select(DomRoot::from_ref(self)),
451 EmbedderControlRequest::SelectElement(SelectElementRequest {
452 options,
453 selected_options,
454 allow_select_multiple: self.Multiple(),
455 }),
456 None,
457 );
458 self.upcast::<Element>().set_open_state(true);
459 }
460
461 pub(crate) fn handle_embedder_response(&self, cx: &mut JSContext, selected_values: Vec<usize>) {
462 self.upcast::<Element>().set_open_state(false);
463
464 let selected_values = if self.Multiple() {
465 selected_values
466 } else {
467 selected_values.into_iter().take(1).collect()
468 };
469
470 let mut selection_did_change = false;
471 for (index, option) in self.list_of_options().enumerate() {
472 let should_be_selected = selected_values.contains(&index);
473 let option_selected_did_change = option.Selected() != should_be_selected;
474
475 if option_selected_did_change {
476 selection_did_change = true;
477 }
478
479 option.set_selectedness(should_be_selected);
480
481 if option_selected_did_change {
482 option.set_dirtiness(true);
483 }
484 }
485
486 if selection_did_change {
487 self.update_shadow_tree(cx);
488 self.send_update_notifications();
489 }
490 }
491
492 fn multiple_attribute_mutated(&self, cx: &mut JSContext, mutation: AttributeMutation) {
493 if mutation.is_removal() {
494 let mut first_enabled: Option<DomRoot<HTMLOptionElement>> = None;
495 let mut first_selected: Option<DomRoot<HTMLOptionElement>> = None;
496
497 for option in self.list_of_options() {
498 if first_selected.is_none() && option.Selected() {
499 first_selected = Some(DomRoot::from_ref(&option));
500 }
501 option.set_selectedness(false);
502 let element = option.upcast::<Element>();
503 if first_enabled.is_none() && !element.disabled_state() {
504 first_enabled = Some(DomRoot::from_ref(&option));
505 }
506 }
507
508 if let Some(first_selected) = first_selected {
509 first_selected.set_selectedness(true);
510 } else if self.display_size() == 1 {
511 if let Some(first_enabled) = first_enabled {
512 first_enabled.set_selectedness(true);
513 }
514 }
515
516 self.update_shadow_tree(cx);
517 }
518 }
519
520 fn send_update_notifications(&self) {
522 let this = Trusted::new(self);
525 self.owner_global()
526 .task_manager()
527 .user_interaction_task_source()
528 .queue(task!(send_select_update_notification: move |cx| {
529 let this = this.root();
530
531 this.upcast::<EventTarget>()
536 .fire_event_with_params(cx,
537 atom!("input"),
538 EventBubbles::Bubbles,
539 EventCancelable::NotCancelable,
540 EventComposed::Composed,
541 );
542
543 this.upcast::<EventTarget>()
546 .fire_bubbling_event(cx, atom!("change"));
547 }));
548 }
549
550 fn may_have_embedder_control(&self) -> bool {
551 let el = self.upcast::<Element>();
552 !el.disabled_state()
553 }
554
555 pub(crate) fn get_enabled_selectedcontent(&self) -> Option<DomRoot<Element>> {
557 if self.Multiple() {
559 return None;
560 }
561
562 self.upcast::<Node>()
568 .traverse_preorder(ShadowIncluding::No)
569 .skip(1)
570 .filter_map(DomRoot::downcast::<Element>)
571 .find(|element| element.local_name() == &local_name!("selectedcontent"))
572 }
573}
574
575impl HTMLSelectElementMethods<crate::DomTypeHolder> for HTMLSelectElement {
576 fn Add(
578 &self,
579 cx: &mut JSContext,
580 element: HTMLOptionElementOrHTMLOptGroupElement,
581 before: Option<HTMLElementOrLong>,
582 ) -> ErrorResult {
583 self.Options().Add(cx, element, before)
584 }
585
586 make_bool_getter!(Disabled, "disabled");
588
589 make_bool_setter!(SetDisabled, "disabled");
591
592 fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
594 self.form_owner()
595 }
596
597 make_bool_getter!(Multiple, "multiple");
599
600 make_bool_setter!(SetMultiple, "multiple");
602
603 make_getter!(Name, "name");
605
606 make_atomic_setter!(SetName, "name");
608
609 make_bool_getter!(Required, "required");
611
612 make_bool_setter!(SetRequired, "required");
614
615 make_uint_getter!(Size, "size", DEFAULT_SELECT_SIZE);
617
618 make_uint_setter!(SetSize, "size", DEFAULT_SELECT_SIZE);
620
621 fn Type(&self) -> DOMString {
623 DOMString::from(if self.Multiple() {
624 "select-multiple"
625 } else {
626 "select-one"
627 })
628 }
629
630 make_labels_getter!(Labels, labels_node_list);
632
633 fn Options(&self) -> DomRoot<HTMLOptionsCollection> {
635 self.options.or_init(|| {
636 let window = self.owner_window();
637 HTMLOptionsCollection::new(
638 &window,
639 self,
640 Box::new(OptionsFilter),
641 CanGc::deprecated_note(),
642 )
643 })
644 }
645
646 fn SelectedOptions(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
648 self.selected_options.or_init(|| {
649 let window = self.owner_window();
650 HTMLCollection::new_with_source(
651 cx,
652 &window,
653 self.upcast(),
654 Box::new(SelectedOptionsSource),
655 )
656 })
657 }
658
659 fn Length(&self) -> u32 {
661 self.Options().Length()
662 }
663
664 fn SetLength(&self, cx: &mut JSContext, length: u32) {
666 self.Options().SetLength(cx, length)
667 }
668
669 fn Item(&self, index: u32) -> Option<DomRoot<Element>> {
671 self.Options().upcast().Item(index)
672 }
673
674 fn IndexedGetter(&self, index: u32) -> Option<DomRoot<Element>> {
676 self.Options().IndexedGetter(index)
677 }
678
679 fn IndexedSetter(
681 &self,
682 cx: &mut JSContext,
683 index: u32,
684 value: Option<&HTMLOptionElement>,
685 ) -> ErrorResult {
686 self.Options().IndexedSetter(cx, index, value)
687 }
688
689 fn NamedItem(&self, name: DOMString) -> Option<DomRoot<HTMLOptionElement>> {
691 self.Options()
692 .NamedGetter(name)
693 .and_then(DomRoot::downcast::<HTMLOptionElement>)
694 }
695
696 fn Remove_(&self, cx: &mut JSContext, index: i32) {
698 self.Options().Remove(cx, index)
699 }
700
701 fn Remove(&self, cx: &mut JSContext) {
703 self.upcast::<Element>().Remove(cx)
704 }
705
706 fn Value(&self) -> DOMString {
708 self.list_of_options()
709 .find(|opt_elem| opt_elem.Selected())
710 .map(|opt_elem| opt_elem.Value())
711 .unwrap_or_default()
712 }
713
714 fn SetValue(&self, cx: &mut JSContext, value: DOMString) {
716 let mut opt_iter = self.list_of_options();
717 for opt in opt_iter.by_ref() {
719 if opt.Value() == value {
720 opt.set_selectedness(true);
721 opt.set_dirtiness(true);
722 break;
723 }
724 opt.set_selectedness(false);
725 }
726 for opt in opt_iter {
728 opt.set_selectedness(false);
729 }
730
731 self.validity_state(CanGc::from_cx(cx))
732 .perform_validation_and_update(ValidationFlags::VALUE_MISSING, CanGc::from_cx(cx));
733 }
734
735 fn SelectedIndex(&self) -> i32 {
737 self.list_of_options()
738 .enumerate()
739 .filter(|(_, opt_elem)| opt_elem.Selected())
740 .map(|(i, _)| i as i32)
741 .next()
742 .unwrap_or(-1)
743 }
744
745 fn SetSelectedIndex(&self, cx: &mut JSContext, index: i32) {
747 let mut selection_did_change = false;
748
749 let mut opt_iter = self.list_of_options();
750 for opt in opt_iter.by_ref().take(index as usize) {
751 selection_did_change |= opt.Selected();
752 opt.set_selectedness(false);
753 }
754 if let Some(selected_option) = opt_iter.next() {
755 selection_did_change |= !selected_option.Selected();
756 selected_option.set_selectedness(true);
757 selected_option.set_dirtiness(true);
758
759 for opt in opt_iter {
761 selection_did_change |= opt.Selected();
762 opt.set_selectedness(false);
763 }
764 }
765
766 if selection_did_change {
767 self.update_shadow_tree(cx);
768 }
769 }
770
771 fn WillValidate(&self) -> bool {
773 self.is_instance_validatable()
774 }
775
776 fn Validity(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
778 self.validity_state(can_gc)
779 }
780
781 fn CheckValidity(&self, cx: &mut JSContext) -> bool {
783 self.check_validity(cx)
784 }
785
786 fn ReportValidity(&self, cx: &mut JSContext) -> bool {
788 self.report_validity(cx)
789 }
790
791 fn ValidationMessage(&self) -> DOMString {
793 self.validation_message()
794 }
795
796 fn SetCustomValidity(&self, error: DOMString, can_gc: CanGc) {
798 self.validity_state(can_gc).set_custom_error_message(error);
799 }
800}
801
802impl VirtualMethods for HTMLSelectElement {
803 fn super_type(&self) -> Option<&dyn VirtualMethods> {
804 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
805 }
806
807 fn attribute_mutated(
808 &self,
809 cx: &mut js::context::JSContext,
810 attr: &Attr,
811 mutation: AttributeMutation,
812 ) {
813 let could_have_had_embedder_control = self.may_have_embedder_control();
814 self.super_type()
815 .unwrap()
816 .attribute_mutated(cx, attr, mutation);
817 match *attr.local_name() {
818 local_name!("multiple") => {
819 self.multiple_attribute_mutated(cx, mutation);
820 },
821 local_name!("required") => {
822 self.validity_state(CanGc::from_cx(cx))
823 .perform_validation_and_update(
824 ValidationFlags::VALUE_MISSING,
825 CanGc::from_cx(cx),
826 );
827 },
828 local_name!("disabled") => {
829 let el = self.upcast::<Element>();
830 match mutation {
831 AttributeMutation::Set(..) => {
832 el.set_disabled_state(true);
833 el.set_enabled_state(false);
834 },
835 AttributeMutation::Removed => {
836 el.set_disabled_state(false);
837 el.set_enabled_state(true);
838 el.check_ancestors_disabled_state_for_form_control();
839 },
840 }
841
842 self.validity_state(CanGc::from_cx(cx))
843 .perform_validation_and_update(
844 ValidationFlags::VALUE_MISSING,
845 CanGc::from_cx(cx),
846 );
847 },
848 local_name!("form") => {
849 self.form_attribute_mutated(mutation, CanGc::from_cx(cx));
850 },
851 _ => {},
852 }
853 if could_have_had_embedder_control && !self.may_have_embedder_control() {
854 self.owner_document()
855 .embedder_controls()
856 .hide_embedder_control(self.upcast());
857 }
858 }
859
860 fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
861 if let Some(s) = self.super_type() {
862 s.bind_to_tree(cx, context);
863 }
864
865 self.upcast::<Element>()
866 .check_ancestors_disabled_state_for_form_control();
867 }
868
869 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
870 self.super_type().unwrap().unbind_from_tree(cx, context);
871
872 let node = self.upcast::<Node>();
873 let el = self.upcast::<Element>();
874 if node
875 .ancestors()
876 .any(|ancestor| ancestor.is::<HTMLFieldSetElement>())
877 {
878 el.check_ancestors_disabled_state_for_form_control();
879 } else {
880 el.check_disabled_attribute();
881 }
882
883 self.owner_document()
884 .embedder_controls()
885 .hide_embedder_control(self.upcast());
886 }
887
888 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
889 if let Some(s) = self.super_type() {
890 s.children_changed(cx, mutation);
891 }
892
893 self.update_shadow_tree(cx);
894 }
895
896 fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
897 match *local_name {
898 local_name!("size") => AttrValue::from_u32(value.into(), DEFAULT_SELECT_SIZE),
899 _ => self
900 .super_type()
901 .unwrap()
902 .parse_plain_attribute(local_name, value),
903 }
904 }
905
906 fn handle_event(&self, cx: &mut js::context::JSContext, event: &Event) {
907 self.super_type().unwrap().handle_event(cx, event);
908 if let Some(event) = event.downcast::<FocusEvent>() {
909 if *event.upcast::<Event>().type_() != *"blur" {
910 self.owner_document()
911 .embedder_controls()
912 .hide_embedder_control(self.upcast());
913 }
914 }
915 }
916}
917
918impl FormControl for HTMLSelectElement {
919 fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
920 self.form_owner.get()
921 }
922
923 fn set_form_owner(&self, form: Option<&HTMLFormElement>) {
924 self.form_owner.set(form);
925 }
926
927 fn to_element(&self) -> &Element {
928 self.upcast::<Element>()
929 }
930}
931
932impl Validatable for HTMLSelectElement {
933 fn as_element(&self) -> &Element {
934 self.upcast()
935 }
936
937 fn validity_state(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
938 self.validity_state
939 .or_init(|| ValidityState::new(&self.owner_window(), self.upcast(), can_gc))
940 }
941
942 fn is_instance_validatable(&self) -> bool {
943 !self.upcast::<Element>().disabled_state() && !is_barred_by_datalist_ancestor(self.upcast())
946 }
947
948 fn perform_validation(
949 &self,
950 validate_flags: ValidationFlags,
951 _can_gc: CanGc,
952 ) -> ValidationFlags {
953 let mut failed_flags = ValidationFlags::empty();
954
955 if validate_flags.contains(ValidationFlags::VALUE_MISSING) && self.Required() {
958 let placeholder = self.get_placeholder_label_option();
959 let is_value_missing = !self
960 .list_of_options()
961 .any(|e| e.Selected() && placeholder != Some(e));
962 failed_flags.set(ValidationFlags::VALUE_MISSING, is_value_missing);
963 }
964
965 failed_flags
966 }
967}
968
969impl Activatable for HTMLSelectElement {
970 fn as_element(&self) -> &Element {
971 self.upcast()
972 }
973
974 fn is_instance_activatable(&self) -> bool {
975 !self.upcast::<Element>().disabled_state()
976 }
977
978 fn activation_behavior(
979 &self,
980 _cx: &mut js::context::JSContext,
981 event: &Event,
982 _target: &EventTarget,
983 ) {
984 if !event.IsTrusted() {
985 return;
986 }
987
988 self.show_menu();
989 }
990}
991
992enum Choice3<I, J, K> {
993 First(I),
994 Second(J),
995 Third(K),
996}
997
998impl<I, J, K, T> Iterator for Choice3<I, J, K>
999where
1000 I: Iterator<Item = T>,
1001 J: Iterator<Item = T>,
1002 K: Iterator<Item = T>,
1003{
1004 type Item = T;
1005
1006 fn next(&mut self) -> Option<T> {
1007 match *self {
1008 Choice3::First(ref mut i) => i.next(),
1009 Choice3::Second(ref mut j) => j.next(),
1010 Choice3::Third(ref mut k) => k.next(),
1011 }
1012 }
1013
1014 fn size_hint(&self) -> (usize, Option<usize>) {
1015 match *self {
1016 Choice3::First(ref i) => i.size_hint(),
1017 Choice3::Second(ref j) => j.size_hint(),
1018 Choice3::Third(ref k) => k.size_hint(),
1019 }
1020 }
1021}