1use std::default::Default;
6use std::iter;
7
8use dom_struct::dom_struct;
9use embedder_traits::EmbedderControlRequest;
10use embedder_traits::{SelectElementOption, SelectElementOptionOrOptgroup};
11use html5ever::{LocalName, Prefix, QualName, local_name, ns};
12use js::rust::HandleObject;
13use style::attr::AttrValue;
14use stylo_dom::ElementState;
15use crate::dom::bindings::refcounted::Trusted;
16use crate::dom::document_embedder_controls::ControlElement;
17use crate::dom::event::{EventBubbles, EventCancelable, EventComposed};
18use crate::dom::bindings::codegen::GenericBindings::HTMLOptGroupElementBinding::HTMLOptGroupElement_Binding::HTMLOptGroupElementMethods;
19use crate::dom::activation::Activatable;
20use crate::dom::attr::Attr;
21use crate::dom::bindings::cell::{DomRefCell, Ref};
22use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
23use crate::dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
24use crate::dom::bindings::codegen::Bindings::HTMLOptionElementBinding::HTMLOptionElementMethods;
25use crate::dom::bindings::codegen::Bindings::HTMLOptionsCollectionBinding::HTMLOptionsCollectionMethods;
26use crate::dom::bindings::codegen::Bindings::HTMLSelectElementBinding::HTMLSelectElementMethods;
27use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
28use crate::dom::bindings::codegen::GenericBindings::CharacterDataBinding::CharacterData_Binding::CharacterDataMethods;
29use crate::dom::bindings::codegen::UnionTypes::{
30 HTMLElementOrLong, HTMLOptionElementOrHTMLOptGroupElement,
31};
32use crate::dom::bindings::error::ErrorResult;
33use crate::dom::bindings::inheritance::Castable;
34use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
35use crate::dom::bindings::str::DOMString;
36use crate::dom::characterdata::CharacterData;
37use crate::dom::document::Document;
38use crate::dom::element::{AttributeMutation, CustomElementCreationMode, Element, ElementCreator};
39use crate::dom::event::Event;
40use crate::dom::eventtarget::EventTarget;
41use crate::dom::html::htmlcollection::CollectionFilter;
42use crate::dom::html::htmlelement::HTMLElement;
43use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
44use crate::dom::html::htmlformelement::{FormControl, FormDatum, FormDatumValue, HTMLFormElement};
45use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
46use crate::dom::html::htmloptionelement::HTMLOptionElement;
47use crate::dom::html::htmloptionscollection::HTMLOptionsCollection;
48use crate::dom::node::{BindContext, ChildrenMutation, Node, NodeTraits, UnbindContext};
49use crate::dom::nodelist::NodeList;
50use crate::dom::text::Text;
51use crate::dom::types::FocusEvent;
52use crate::dom::validation::{Validatable, is_barred_by_datalist_ancestor};
53use crate::dom::validitystate::{ValidationFlags, ValidityState};
54use crate::dom::virtualmethods::VirtualMethods;
55use crate::script_runtime::CanGc;
56
57const DEFAULT_SELECT_SIZE: u32 = 0;
58
59const SELECT_BOX_STYLE: &str = "
60 display: flex;
61 align-items: center;
62 height: 100%;
63";
64
65const TEXT_CONTAINER_STYLE: &str = "flex: 1;";
66
67const CHEVRON_CONTAINER_STYLE: &str = "
68 font-size: 16px;
69 margin: 4px;
70";
71
72#[derive(JSTraceable, MallocSizeOf)]
73struct OptionsFilter;
74impl CollectionFilter for OptionsFilter {
75 fn filter<'a>(&self, elem: &'a Element, root: &'a Node) -> bool {
76 if !elem.is::<HTMLOptionElement>() {
77 return false;
78 }
79
80 let node = elem.upcast::<Node>();
81 if root.is_parent_of(node) {
82 return true;
83 }
84
85 match node.GetParentNode() {
86 Some(optgroup) => optgroup.is::<HTMLOptGroupElement>() && root.is_parent_of(&optgroup),
87 None => false,
88 }
89 }
90}
91
92#[dom_struct]
93pub(crate) struct HTMLSelectElement {
94 htmlelement: HTMLElement,
95 options: MutNullableDom<HTMLOptionsCollection>,
96 form_owner: MutNullableDom<HTMLFormElement>,
97 labels_node_list: MutNullableDom<NodeList>,
98 validity_state: MutNullableDom<ValidityState>,
99 shadow_tree: DomRefCell<Option<ShadowTree>>,
100}
101
102#[derive(Clone, JSTraceable, MallocSizeOf)]
104#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
105struct ShadowTree {
106 selected_option: Dom<Text>,
107}
108
109impl HTMLSelectElement {
110 fn new_inherited(
111 local_name: LocalName,
112 prefix: Option<Prefix>,
113 document: &Document,
114 ) -> HTMLSelectElement {
115 HTMLSelectElement {
116 htmlelement: HTMLElement::new_inherited_with_state(
117 ElementState::ENABLED | ElementState::VALID,
118 local_name,
119 prefix,
120 document,
121 ),
122 options: Default::default(),
123 form_owner: Default::default(),
124 labels_node_list: Default::default(),
125 validity_state: Default::default(),
126 shadow_tree: Default::default(),
127 }
128 }
129
130 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
131 pub(crate) fn new(
132 local_name: LocalName,
133 prefix: Option<Prefix>,
134 document: &Document,
135 proto: Option<HandleObject>,
136 can_gc: CanGc,
137 ) -> DomRoot<HTMLSelectElement> {
138 let n = Node::reflect_node_with_proto(
139 Box::new(HTMLSelectElement::new_inherited(
140 local_name, prefix, document,
141 )),
142 document,
143 proto,
144 can_gc,
145 );
146
147 n.upcast::<Node>().set_weird_parser_insertion_mode();
148 n
149 }
150
151 pub(crate) fn list_of_options(
153 &self,
154 ) -> impl Iterator<Item = DomRoot<HTMLOptionElement>> + use<'_> {
155 self.upcast::<Node>().children().flat_map(|node| {
156 if node.is::<HTMLOptionElement>() {
157 let node = DomRoot::downcast::<HTMLOptionElement>(node).unwrap();
158 Choice3::First(iter::once(node))
159 } else if node.is::<HTMLOptGroupElement>() {
160 Choice3::Second(node.children().filter_map(DomRoot::downcast))
161 } else {
162 Choice3::Third(iter::empty())
163 }
164 })
165 }
166
167 fn get_placeholder_label_option(&self) -> Option<DomRoot<HTMLOptionElement>> {
169 if self.Required() && !self.Multiple() && self.display_size() == 1 {
170 self.list_of_options().next().filter(|node| {
171 let parent = node.upcast::<Node>().GetParentNode();
172 node.Value().is_empty() && parent.as_deref() == Some(self.upcast())
173 })
174 } else {
175 None
176 }
177 }
178
179 pub(crate) fn reset(&self) {
181 for opt in self.list_of_options() {
182 opt.set_selectedness(opt.DefaultSelected());
183 opt.set_dirtiness(false);
184 }
185 self.ask_for_reset();
186 }
187
188 pub(crate) fn ask_for_reset(&self) {
190 if self.Multiple() {
191 return;
192 }
193
194 let mut first_enabled: Option<DomRoot<HTMLOptionElement>> = None;
195 let mut last_selected: Option<DomRoot<HTMLOptionElement>> = None;
196
197 for opt in self.list_of_options() {
198 if opt.Selected() {
199 opt.set_selectedness(false);
200 last_selected = Some(DomRoot::from_ref(&opt));
201 }
202 let element = opt.upcast::<Element>();
203 if first_enabled.is_none() && !element.disabled_state() {
204 first_enabled = Some(DomRoot::from_ref(&opt));
205 }
206 }
207
208 if let Some(last_selected) = last_selected {
209 last_selected.set_selectedness(true);
210 } else if self.display_size() == 1 {
211 if let Some(first_enabled) = first_enabled {
212 first_enabled.set_selectedness(true);
213 }
214 }
215 }
216
217 pub(crate) fn push_form_data(&self, data_set: &mut Vec<FormDatum>) {
218 if self.Name().is_empty() {
219 return;
220 }
221 for opt in self.list_of_options() {
222 let element = opt.upcast::<Element>();
223 if opt.Selected() && element.enabled_state() {
224 data_set.push(FormDatum {
225 ty: self.Type(),
226 name: self.Name(),
227 value: FormDatumValue::String(opt.Value()),
228 });
229 }
230 }
231 }
232
233 pub(crate) fn pick_option(&self, picked: &HTMLOptionElement) {
235 if !self.Multiple() {
236 let picked = picked.upcast();
237 for opt in self.list_of_options() {
238 if opt.upcast::<HTMLElement>() != picked {
239 opt.set_selectedness(false);
240 }
241 }
242 }
243 }
244
245 fn display_size(&self) -> u32 {
247 if self.Size() == 0 {
248 if self.Multiple() { 4 } else { 1 }
249 } else {
250 self.Size()
251 }
252 }
253
254 fn create_shadow_tree(&self, can_gc: CanGc) {
255 let document = self.owner_document();
256 let root = self.upcast::<Element>().attach_ua_shadow_root(true, can_gc);
257
258 let select_box = Element::create(
259 QualName::new(None, ns!(html), local_name!("div")),
260 None,
261 &document,
262 ElementCreator::ScriptCreated,
263 CustomElementCreationMode::Asynchronous,
264 None,
265 can_gc,
266 );
267 select_box.set_string_attribute(&local_name!("style"), SELECT_BOX_STYLE.into(), can_gc);
268
269 let text_container = Element::create(
270 QualName::new(None, ns!(html), local_name!("div")),
271 None,
272 &document,
273 ElementCreator::ScriptCreated,
274 CustomElementCreationMode::Asynchronous,
275 None,
276 can_gc,
277 );
278 text_container.set_string_attribute(
279 &local_name!("style"),
280 TEXT_CONTAINER_STYLE.into(),
281 can_gc,
282 );
283 select_box
284 .upcast::<Node>()
285 .AppendChild(text_container.upcast::<Node>(), can_gc)
286 .unwrap();
287
288 let text = Text::new(DOMString::new(), &document, can_gc);
289 let _ = self.shadow_tree.borrow_mut().insert(ShadowTree {
290 selected_option: text.as_traced(),
291 });
292 text_container
293 .upcast::<Node>()
294 .AppendChild(text.upcast::<Node>(), can_gc)
295 .unwrap();
296
297 let chevron_container = Element::create(
298 QualName::new(None, ns!(html), local_name!("div")),
299 None,
300 &document,
301 ElementCreator::ScriptCreated,
302 CustomElementCreationMode::Asynchronous,
303 None,
304 can_gc,
305 );
306 chevron_container.set_string_attribute(
307 &local_name!("style"),
308 CHEVRON_CONTAINER_STYLE.into(),
309 can_gc,
310 );
311 chevron_container
312 .upcast::<Node>()
313 .set_text_content_for_element(Some("▾".into()), can_gc);
314 select_box
315 .upcast::<Node>()
316 .AppendChild(chevron_container.upcast::<Node>(), can_gc)
317 .unwrap();
318
319 root.upcast::<Node>()
320 .AppendChild(select_box.upcast::<Node>(), can_gc)
321 .unwrap();
322 }
323
324 fn shadow_tree(&self, can_gc: CanGc) -> Ref<'_, ShadowTree> {
325 if !self.upcast::<Element>().is_shadow_host() {
326 self.create_shadow_tree(can_gc);
327 }
328
329 Ref::filter_map(self.shadow_tree.borrow(), Option::as_ref)
330 .ok()
331 .expect("UA shadow tree was not created")
332 }
333
334 pub(crate) fn update_shadow_tree(&self, can_gc: CanGc) {
335 let shadow_tree = self.shadow_tree(can_gc);
336
337 let selected_option_text = self
338 .selected_option()
339 .or_else(|| self.list_of_options().next())
340 .map(|option| option.displayed_label())
341 .unwrap_or_default();
342
343 let displayed_text = itertools::join(selected_option_text.str().split_whitespace(), " ");
345
346 shadow_tree
347 .selected_option
348 .upcast::<CharacterData>()
349 .SetData(displayed_text.trim().into());
350 }
351
352 pub(crate) fn selected_option(&self) -> Option<DomRoot<HTMLOptionElement>> {
353 self.list_of_options()
354 .find(|opt_elem| opt_elem.Selected())
355 .or_else(|| self.list_of_options().next())
356 }
357
358 pub(crate) fn show_menu(&self) {
359 let mut index = 0;
361 let mut embedder_option_from_option = |option: &HTMLOptionElement| {
362 let embedder_option = SelectElementOption {
363 id: index,
364 label: option.displayed_label().into(),
365 is_disabled: option.Disabled(),
366 };
367 index += 1;
368 embedder_option
369 };
370 let options = self
371 .upcast::<Node>()
372 .children()
373 .flat_map(|child| {
374 if let Some(option) = child.downcast::<HTMLOptionElement>() {
375 return Some(embedder_option_from_option(option).into());
376 }
377
378 if let Some(optgroup) = child.downcast::<HTMLOptGroupElement>() {
379 let options = optgroup
380 .upcast::<Node>()
381 .children()
382 .flat_map(DomRoot::downcast::<HTMLOptionElement>)
383 .map(|option| embedder_option_from_option(&option))
384 .collect();
385 let label = optgroup.Label().into();
386
387 return Some(SelectElementOptionOrOptgroup::Optgroup { label, options });
388 }
389
390 None
391 })
392 .collect();
393
394 let selected_index = self.list_of_options().position(|option| option.Selected());
395
396 self.owner_document()
397 .embedder_controls()
398 .show_embedder_control(
399 ControlElement::Select(DomRoot::from_ref(self)),
400 EmbedderControlRequest::SelectElement(options, selected_index),
401 );
402 }
403
404 pub(crate) fn handle_menu_response(&self, response: Option<usize>, can_gc: CanGc) {
405 let Some(selected_value) = response else {
406 return;
407 };
408
409 self.SetSelectedIndex(selected_value as i32, can_gc);
410 self.send_update_notifications();
411 }
412
413 fn send_update_notifications(&self) {
415 let this = Trusted::new(self);
418 self.owner_global()
419 .task_manager()
420 .user_interaction_task_source()
421 .queue(task!(send_select_update_notification: move || {
422 let this = this.root();
423
424 this.upcast::<EventTarget>()
429 .fire_event_with_params(
430 atom!("input"),
431 EventBubbles::Bubbles,
432 EventCancelable::NotCancelable,
433 EventComposed::Composed,
434 CanGc::note(),
435 );
436
437 this.upcast::<EventTarget>()
440 .fire_bubbling_event(atom!("change"), CanGc::note());
441 }));
442 }
443
444 fn may_have_embedder_control(&self) -> bool {
445 let el = self.upcast::<Element>();
446 !el.disabled_state()
447 }
448}
449
450impl HTMLSelectElementMethods<crate::DomTypeHolder> for HTMLSelectElement {
451 fn Add(
453 &self,
454 element: HTMLOptionElementOrHTMLOptGroupElement,
455 before: Option<HTMLElementOrLong>,
456 ) -> ErrorResult {
457 self.Options().Add(element, before)
458 }
459
460 make_bool_getter!(Disabled, "disabled");
462
463 make_bool_setter!(SetDisabled, "disabled");
465
466 fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
468 self.form_owner()
469 }
470
471 make_bool_getter!(Multiple, "multiple");
473
474 make_bool_setter!(SetMultiple, "multiple");
476
477 make_getter!(Name, "name");
479
480 make_atomic_setter!(SetName, "name");
482
483 make_bool_getter!(Required, "required");
485
486 make_bool_setter!(SetRequired, "required");
488
489 make_uint_getter!(Size, "size", DEFAULT_SELECT_SIZE);
491
492 make_uint_setter!(SetSize, "size", DEFAULT_SELECT_SIZE);
494
495 fn Type(&self) -> DOMString {
497 DOMString::from(if self.Multiple() {
498 "select-multiple"
499 } else {
500 "select-one"
501 })
502 }
503
504 make_labels_getter!(Labels, labels_node_list);
506
507 fn Options(&self) -> DomRoot<HTMLOptionsCollection> {
509 self.options.or_init(|| {
510 let window = self.owner_window();
511 HTMLOptionsCollection::new(&window, self, Box::new(OptionsFilter), CanGc::note())
512 })
513 }
514
515 fn Length(&self) -> u32 {
517 self.Options().Length()
518 }
519
520 fn SetLength(&self, length: u32, can_gc: CanGc) {
522 self.Options().SetLength(length, can_gc)
523 }
524
525 fn Item(&self, index: u32) -> Option<DomRoot<Element>> {
527 self.Options().upcast().Item(index)
528 }
529
530 fn IndexedGetter(&self, index: u32) -> Option<DomRoot<Element>> {
532 self.Options().IndexedGetter(index)
533 }
534
535 fn IndexedSetter(
537 &self,
538 index: u32,
539 value: Option<&HTMLOptionElement>,
540 can_gc: CanGc,
541 ) -> ErrorResult {
542 self.Options().IndexedSetter(index, value, can_gc)
543 }
544
545 fn NamedItem(&self, name: DOMString) -> Option<DomRoot<HTMLOptionElement>> {
547 self.Options()
548 .NamedGetter(name)
549 .and_then(DomRoot::downcast::<HTMLOptionElement>)
550 }
551
552 fn Remove_(&self, index: i32) {
554 self.Options().Remove(index)
555 }
556
557 fn Remove(&self) {
559 self.upcast::<Element>().Remove(CanGc::note())
560 }
561
562 fn Value(&self) -> DOMString {
564 self.list_of_options()
565 .find(|opt_elem| opt_elem.Selected())
566 .map(|opt_elem| opt_elem.Value())
567 .unwrap_or_default()
568 }
569
570 fn SetValue(&self, value: DOMString, can_gc: CanGc) {
572 let mut opt_iter = self.list_of_options();
573 for opt in opt_iter.by_ref() {
575 if opt.Value() == value {
576 opt.set_selectedness(true);
577 opt.set_dirtiness(true);
578 break;
579 }
580 opt.set_selectedness(false);
581 }
582 for opt in opt_iter {
584 opt.set_selectedness(false);
585 }
586
587 self.validity_state(can_gc)
588 .perform_validation_and_update(ValidationFlags::VALUE_MISSING, can_gc);
589 }
590
591 fn SelectedIndex(&self) -> i32 {
593 self.list_of_options()
594 .enumerate()
595 .filter(|(_, opt_elem)| opt_elem.Selected())
596 .map(|(i, _)| i as i32)
597 .next()
598 .unwrap_or(-1)
599 }
600
601 fn SetSelectedIndex(&self, index: i32, can_gc: CanGc) {
603 let mut selection_did_change = false;
604
605 let mut opt_iter = self.list_of_options();
606 for opt in opt_iter.by_ref().take(index as usize) {
607 selection_did_change |= opt.Selected();
608 opt.set_selectedness(false);
609 }
610 if let Some(selected_option) = opt_iter.next() {
611 selection_did_change |= !selected_option.Selected();
612 selected_option.set_selectedness(true);
613 selected_option.set_dirtiness(true);
614
615 for opt in opt_iter {
617 selection_did_change |= opt.Selected();
618 opt.set_selectedness(false);
619 }
620 }
621
622 if selection_did_change {
623 self.update_shadow_tree(can_gc);
624 }
625 }
626
627 fn WillValidate(&self) -> bool {
629 self.is_instance_validatable()
630 }
631
632 fn Validity(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
634 self.validity_state(can_gc)
635 }
636
637 fn CheckValidity(&self, can_gc: CanGc) -> bool {
639 self.check_validity(can_gc)
640 }
641
642 fn ReportValidity(&self, can_gc: CanGc) -> bool {
644 self.report_validity(can_gc)
645 }
646
647 fn ValidationMessage(&self) -> DOMString {
649 self.validation_message()
650 }
651
652 fn SetCustomValidity(&self, error: DOMString, can_gc: CanGc) {
654 self.validity_state(can_gc).set_custom_error_message(error);
655 }
656}
657
658impl VirtualMethods for HTMLSelectElement {
659 fn super_type(&self) -> Option<&dyn VirtualMethods> {
660 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
661 }
662
663 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
664 let could_have_had_embedder_control = self.may_have_embedder_control();
665 self.super_type()
666 .unwrap()
667 .attribute_mutated(attr, mutation, can_gc);
668 match *attr.local_name() {
669 local_name!("required") => {
670 self.validity_state(can_gc)
671 .perform_validation_and_update(ValidationFlags::VALUE_MISSING, can_gc);
672 },
673 local_name!("disabled") => {
674 let el = self.upcast::<Element>();
675 match mutation {
676 AttributeMutation::Set(_) => {
677 el.set_disabled_state(true);
678 el.set_enabled_state(false);
679 },
680 AttributeMutation::Removed => {
681 el.set_disabled_state(false);
682 el.set_enabled_state(true);
683 el.check_ancestors_disabled_state_for_form_control();
684 },
685 }
686
687 self.validity_state(can_gc)
688 .perform_validation_and_update(ValidationFlags::VALUE_MISSING, can_gc);
689 },
690 local_name!("form") => {
691 self.form_attribute_mutated(mutation, can_gc);
692 },
693 _ => {},
694 }
695 if could_have_had_embedder_control && !self.may_have_embedder_control() {
696 self.owner_document()
697 .embedder_controls()
698 .hide_embedder_control(self.upcast());
699 }
700 }
701
702 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
703 if let Some(s) = self.super_type() {
704 s.bind_to_tree(context, can_gc);
705 }
706
707 self.upcast::<Element>()
708 .check_ancestors_disabled_state_for_form_control();
709 }
710
711 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
712 self.super_type().unwrap().unbind_from_tree(context, can_gc);
713
714 let node = self.upcast::<Node>();
715 let el = self.upcast::<Element>();
716 if node
717 .ancestors()
718 .any(|ancestor| ancestor.is::<HTMLFieldSetElement>())
719 {
720 el.check_ancestors_disabled_state_for_form_control();
721 } else {
722 el.check_disabled_attribute();
723 }
724
725 self.owner_document()
726 .embedder_controls()
727 .hide_embedder_control(self.upcast());
728 }
729
730 fn children_changed(&self, mutation: &ChildrenMutation, can_gc: CanGc) {
731 if let Some(s) = self.super_type() {
732 s.children_changed(mutation, can_gc);
733 }
734
735 self.update_shadow_tree(can_gc);
736 }
737
738 fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
739 match *local_name {
740 local_name!("size") => AttrValue::from_u32(value.into(), DEFAULT_SELECT_SIZE),
741 _ => self
742 .super_type()
743 .unwrap()
744 .parse_plain_attribute(local_name, value),
745 }
746 }
747
748 fn handle_event(&self, event: &Event, can_gc: CanGc) {
749 self.super_type().unwrap().handle_event(event, can_gc);
750 if let Some(event) = event.downcast::<FocusEvent>() {
751 if *event.upcast::<Event>().type_() != *"blur" {
752 self.owner_document()
753 .embedder_controls()
754 .hide_embedder_control(self.upcast());
755 }
756 }
757 }
758}
759
760impl FormControl for HTMLSelectElement {
761 fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
762 self.form_owner.get()
763 }
764
765 fn set_form_owner(&self, form: Option<&HTMLFormElement>) {
766 self.form_owner.set(form);
767 }
768
769 fn to_element(&self) -> &Element {
770 self.upcast::<Element>()
771 }
772}
773
774impl Validatable for HTMLSelectElement {
775 fn as_element(&self) -> &Element {
776 self.upcast()
777 }
778
779 fn validity_state(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
780 self.validity_state
781 .or_init(|| ValidityState::new(&self.owner_window(), self.upcast(), can_gc))
782 }
783
784 fn is_instance_validatable(&self) -> bool {
785 !self.upcast::<Element>().disabled_state() && !is_barred_by_datalist_ancestor(self.upcast())
788 }
789
790 fn perform_validation(
791 &self,
792 validate_flags: ValidationFlags,
793 _can_gc: CanGc,
794 ) -> ValidationFlags {
795 let mut failed_flags = ValidationFlags::empty();
796
797 if validate_flags.contains(ValidationFlags::VALUE_MISSING) && self.Required() {
800 let placeholder = self.get_placeholder_label_option();
801 let is_value_missing = !self
802 .list_of_options()
803 .any(|e| e.Selected() && placeholder != Some(e));
804 failed_flags.set(ValidationFlags::VALUE_MISSING, is_value_missing);
805 }
806
807 failed_flags
808 }
809}
810
811impl Activatable for HTMLSelectElement {
812 fn as_element(&self) -> &Element {
813 self.upcast()
814 }
815
816 fn is_instance_activatable(&self) -> bool {
817 true
818 }
819
820 fn activation_behavior(&self, _event: &Event, _target: &EventTarget, _can_gc: CanGc) {
821 self.show_menu();
822 }
823}
824
825enum Choice3<I, J, K> {
826 First(I),
827 Second(J),
828 Third(K),
829}
830
831impl<I, J, K, T> Iterator for Choice3<I, J, K>
832where
833 I: Iterator<Item = T>,
834 J: Iterator<Item = T>,
835 K: Iterator<Item = T>,
836{
837 type Item = T;
838
839 fn next(&mut self) -> Option<T> {
840 match *self {
841 Choice3::First(ref mut i) => i.next(),
842 Choice3::Second(ref mut j) => j.next(),
843 Choice3::Third(ref mut k) => k.next(),
844 }
845 }
846
847 fn size_hint(&self) -> (usize, Option<usize>) {
848 match *self {
849 Choice3::First(ref i) => i.size_hint(),
850 Choice3::Second(ref j) => j.size_hint(),
851 Choice3::Third(ref k) => k.size_hint(),
852 }
853 }
854}