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 None,
402 );
403 }
404
405 pub(crate) fn handle_menu_response(&self, response: Option<usize>, can_gc: CanGc) {
406 let Some(selected_value) = response else {
407 return;
408 };
409
410 self.SetSelectedIndex(selected_value as i32, can_gc);
411 self.send_update_notifications();
412 }
413
414 fn send_update_notifications(&self) {
416 let this = Trusted::new(self);
419 self.owner_global()
420 .task_manager()
421 .user_interaction_task_source()
422 .queue(task!(send_select_update_notification: move || {
423 let this = this.root();
424
425 this.upcast::<EventTarget>()
430 .fire_event_with_params(
431 atom!("input"),
432 EventBubbles::Bubbles,
433 EventCancelable::NotCancelable,
434 EventComposed::Composed,
435 CanGc::note(),
436 );
437
438 this.upcast::<EventTarget>()
441 .fire_bubbling_event(atom!("change"), CanGc::note());
442 }));
443 }
444
445 fn may_have_embedder_control(&self) -> bool {
446 let el = self.upcast::<Element>();
447 !el.disabled_state()
448 }
449}
450
451impl HTMLSelectElementMethods<crate::DomTypeHolder> for HTMLSelectElement {
452 fn Add(
454 &self,
455 element: HTMLOptionElementOrHTMLOptGroupElement,
456 before: Option<HTMLElementOrLong>,
457 ) -> ErrorResult {
458 self.Options().Add(element, before)
459 }
460
461 make_bool_getter!(Disabled, "disabled");
463
464 make_bool_setter!(SetDisabled, "disabled");
466
467 fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
469 self.form_owner()
470 }
471
472 make_bool_getter!(Multiple, "multiple");
474
475 make_bool_setter!(SetMultiple, "multiple");
477
478 make_getter!(Name, "name");
480
481 make_atomic_setter!(SetName, "name");
483
484 make_bool_getter!(Required, "required");
486
487 make_bool_setter!(SetRequired, "required");
489
490 make_uint_getter!(Size, "size", DEFAULT_SELECT_SIZE);
492
493 make_uint_setter!(SetSize, "size", DEFAULT_SELECT_SIZE);
495
496 fn Type(&self) -> DOMString {
498 DOMString::from(if self.Multiple() {
499 "select-multiple"
500 } else {
501 "select-one"
502 })
503 }
504
505 make_labels_getter!(Labels, labels_node_list);
507
508 fn Options(&self) -> DomRoot<HTMLOptionsCollection> {
510 self.options.or_init(|| {
511 let window = self.owner_window();
512 HTMLOptionsCollection::new(&window, self, Box::new(OptionsFilter), CanGc::note())
513 })
514 }
515
516 fn Length(&self) -> u32 {
518 self.Options().Length()
519 }
520
521 fn SetLength(&self, length: u32, can_gc: CanGc) {
523 self.Options().SetLength(length, can_gc)
524 }
525
526 fn Item(&self, index: u32) -> Option<DomRoot<Element>> {
528 self.Options().upcast().Item(index)
529 }
530
531 fn IndexedGetter(&self, index: u32) -> Option<DomRoot<Element>> {
533 self.Options().IndexedGetter(index)
534 }
535
536 fn IndexedSetter(
538 &self,
539 index: u32,
540 value: Option<&HTMLOptionElement>,
541 can_gc: CanGc,
542 ) -> ErrorResult {
543 self.Options().IndexedSetter(index, value, can_gc)
544 }
545
546 fn NamedItem(&self, name: DOMString) -> Option<DomRoot<HTMLOptionElement>> {
548 self.Options()
549 .NamedGetter(name)
550 .and_then(DomRoot::downcast::<HTMLOptionElement>)
551 }
552
553 fn Remove_(&self, index: i32) {
555 self.Options().Remove(index)
556 }
557
558 fn Remove(&self) {
560 self.upcast::<Element>().Remove(CanGc::note())
561 }
562
563 fn Value(&self) -> DOMString {
565 self.list_of_options()
566 .find(|opt_elem| opt_elem.Selected())
567 .map(|opt_elem| opt_elem.Value())
568 .unwrap_or_default()
569 }
570
571 fn SetValue(&self, value: DOMString, can_gc: CanGc) {
573 let mut opt_iter = self.list_of_options();
574 for opt in opt_iter.by_ref() {
576 if opt.Value() == value {
577 opt.set_selectedness(true);
578 opt.set_dirtiness(true);
579 break;
580 }
581 opt.set_selectedness(false);
582 }
583 for opt in opt_iter {
585 opt.set_selectedness(false);
586 }
587
588 self.validity_state(can_gc)
589 .perform_validation_and_update(ValidationFlags::VALUE_MISSING, can_gc);
590 }
591
592 fn SelectedIndex(&self) -> i32 {
594 self.list_of_options()
595 .enumerate()
596 .filter(|(_, opt_elem)| opt_elem.Selected())
597 .map(|(i, _)| i as i32)
598 .next()
599 .unwrap_or(-1)
600 }
601
602 fn SetSelectedIndex(&self, index: i32, can_gc: CanGc) {
604 let mut selection_did_change = false;
605
606 let mut opt_iter = self.list_of_options();
607 for opt in opt_iter.by_ref().take(index as usize) {
608 selection_did_change |= opt.Selected();
609 opt.set_selectedness(false);
610 }
611 if let Some(selected_option) = opt_iter.next() {
612 selection_did_change |= !selected_option.Selected();
613 selected_option.set_selectedness(true);
614 selected_option.set_dirtiness(true);
615
616 for opt in opt_iter {
618 selection_did_change |= opt.Selected();
619 opt.set_selectedness(false);
620 }
621 }
622
623 if selection_did_change {
624 self.update_shadow_tree(can_gc);
625 }
626 }
627
628 fn WillValidate(&self) -> bool {
630 self.is_instance_validatable()
631 }
632
633 fn Validity(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
635 self.validity_state(can_gc)
636 }
637
638 fn CheckValidity(&self, can_gc: CanGc) -> bool {
640 self.check_validity(can_gc)
641 }
642
643 fn ReportValidity(&self, can_gc: CanGc) -> bool {
645 self.report_validity(can_gc)
646 }
647
648 fn ValidationMessage(&self) -> DOMString {
650 self.validation_message()
651 }
652
653 fn SetCustomValidity(&self, error: DOMString, can_gc: CanGc) {
655 self.validity_state(can_gc).set_custom_error_message(error);
656 }
657}
658
659impl VirtualMethods for HTMLSelectElement {
660 fn super_type(&self) -> Option<&dyn VirtualMethods> {
661 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
662 }
663
664 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
665 let could_have_had_embedder_control = self.may_have_embedder_control();
666 self.super_type()
667 .unwrap()
668 .attribute_mutated(attr, mutation, can_gc);
669 match *attr.local_name() {
670 local_name!("required") => {
671 self.validity_state(can_gc)
672 .perform_validation_and_update(ValidationFlags::VALUE_MISSING, can_gc);
673 },
674 local_name!("disabled") => {
675 let el = self.upcast::<Element>();
676 match mutation {
677 AttributeMutation::Set(..) => {
678 el.set_disabled_state(true);
679 el.set_enabled_state(false);
680 },
681 AttributeMutation::Removed => {
682 el.set_disabled_state(false);
683 el.set_enabled_state(true);
684 el.check_ancestors_disabled_state_for_form_control();
685 },
686 }
687
688 self.validity_state(can_gc)
689 .perform_validation_and_update(ValidationFlags::VALUE_MISSING, can_gc);
690 },
691 local_name!("form") => {
692 self.form_attribute_mutated(mutation, can_gc);
693 },
694 _ => {},
695 }
696 if could_have_had_embedder_control && !self.may_have_embedder_control() {
697 self.owner_document()
698 .embedder_controls()
699 .hide_embedder_control(self.upcast());
700 }
701 }
702
703 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
704 if let Some(s) = self.super_type() {
705 s.bind_to_tree(context, can_gc);
706 }
707
708 self.upcast::<Element>()
709 .check_ancestors_disabled_state_for_form_control();
710 }
711
712 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
713 self.super_type().unwrap().unbind_from_tree(context, can_gc);
714
715 let node = self.upcast::<Node>();
716 let el = self.upcast::<Element>();
717 if node
718 .ancestors()
719 .any(|ancestor| ancestor.is::<HTMLFieldSetElement>())
720 {
721 el.check_ancestors_disabled_state_for_form_control();
722 } else {
723 el.check_disabled_attribute();
724 }
725
726 self.owner_document()
727 .embedder_controls()
728 .hide_embedder_control(self.upcast());
729 }
730
731 fn children_changed(&self, mutation: &ChildrenMutation, can_gc: CanGc) {
732 if let Some(s) = self.super_type() {
733 s.children_changed(mutation, can_gc);
734 }
735
736 self.update_shadow_tree(can_gc);
737 }
738
739 fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
740 match *local_name {
741 local_name!("size") => AttrValue::from_u32(value.into(), DEFAULT_SELECT_SIZE),
742 _ => self
743 .super_type()
744 .unwrap()
745 .parse_plain_attribute(local_name, value),
746 }
747 }
748
749 fn handle_event(&self, event: &Event, can_gc: CanGc) {
750 self.super_type().unwrap().handle_event(event, can_gc);
751 if let Some(event) = event.downcast::<FocusEvent>() {
752 if *event.upcast::<Event>().type_() != *"blur" {
753 self.owner_document()
754 .embedder_controls()
755 .hide_embedder_control(self.upcast());
756 }
757 }
758 }
759}
760
761impl FormControl for HTMLSelectElement {
762 fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
763 self.form_owner.get()
764 }
765
766 fn set_form_owner(&self, form: Option<&HTMLFormElement>) {
767 self.form_owner.set(form);
768 }
769
770 fn to_element(&self) -> &Element {
771 self.upcast::<Element>()
772 }
773}
774
775impl Validatable for HTMLSelectElement {
776 fn as_element(&self) -> &Element {
777 self.upcast()
778 }
779
780 fn validity_state(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
781 self.validity_state
782 .or_init(|| ValidityState::new(&self.owner_window(), self.upcast(), can_gc))
783 }
784
785 fn is_instance_validatable(&self) -> bool {
786 !self.upcast::<Element>().disabled_state() && !is_barred_by_datalist_ancestor(self.upcast())
789 }
790
791 fn perform_validation(
792 &self,
793 validate_flags: ValidationFlags,
794 _can_gc: CanGc,
795 ) -> ValidationFlags {
796 let mut failed_flags = ValidationFlags::empty();
797
798 if validate_flags.contains(ValidationFlags::VALUE_MISSING) && self.Required() {
801 let placeholder = self.get_placeholder_label_option();
802 let is_value_missing = !self
803 .list_of_options()
804 .any(|e| e.Selected() && placeholder != Some(e));
805 failed_flags.set(ValidationFlags::VALUE_MISSING, is_value_missing);
806 }
807
808 failed_flags
809 }
810}
811
812impl Activatable for HTMLSelectElement {
813 fn as_element(&self) -> &Element {
814 self.upcast()
815 }
816
817 fn is_instance_activatable(&self) -> bool {
818 true
819 }
820
821 fn activation_behavior(&self, _event: &Event, _target: &EventTarget, _can_gc: CanGc) {
822 self.show_menu();
823 }
824}
825
826enum Choice3<I, J, K> {
827 First(I),
828 Second(J),
829 Third(K),
830}
831
832impl<I, J, K, T> Iterator for Choice3<I, J, K>
833where
834 I: Iterator<Item = T>,
835 J: Iterator<Item = T>,
836 K: Iterator<Item = T>,
837{
838 type Item = T;
839
840 fn next(&mut self) -> Option<T> {
841 match *self {
842 Choice3::First(ref mut i) => i.next(),
843 Choice3::Second(ref mut j) => j.next(),
844 Choice3::Third(ref mut k) => k.next(),
845 }
846 }
847
848 fn size_hint(&self) -> (usize, Option<usize>) {
849 match *self {
850 Choice3::First(ref i) => i.size_hint(),
851 Choice3::Second(ref j) => j.size_hint(),
852 Choice3::Third(ref k) => k.size_hint(),
853 }
854 }
855}