1use std::default::Default;
6use std::iter;
7
8use crate::dom::activation::Activatable;
9use crate::dom::element::attributes::storage::AttrRef;
10use script_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 let Some(first_enabled) = first_enabled
242 {
243 first_enabled.set_selectedness(true);
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(cx, &local_name!("style"), SELECT_BOX_STYLE.into());
298
299 let text_container = Element::create(
300 cx,
301 QualName::new(None, ns!(html), local_name!("div")),
302 None,
303 &document,
304 ElementCreator::ScriptCreated,
305 CustomElementCreationMode::Asynchronous,
306 None,
307 );
308 text_container.set_string_attribute(cx, &local_name!("style"), TEXT_CONTAINER_STYLE.into());
309 select_box
310 .upcast::<Node>()
311 .AppendChild(cx, text_container.upcast::<Node>())
312 .unwrap();
313
314 let text = Text::new(cx, DOMString::new(), &document);
315 let _ = self.shadow_tree.borrow_mut().insert(ShadowTree {
316 selected_option: text.as_traced(),
317 });
318 text_container
319 .upcast::<Node>()
320 .AppendChild(cx, text.upcast::<Node>())
321 .unwrap();
322
323 let chevron_container = Element::create(
324 cx,
325 QualName::new(None, ns!(html), local_name!("div")),
326 None,
327 &document,
328 ElementCreator::ScriptCreated,
329 CustomElementCreationMode::Asynchronous,
330 None,
331 );
332 chevron_container.set_string_attribute(
333 cx,
334 &local_name!("style"),
335 CHEVRON_CONTAINER_STYLE.into(),
336 );
337 select_box
338 .upcast::<Node>()
339 .AppendChild(cx, chevron_container.upcast::<Node>())
340 .unwrap();
341
342 root.upcast::<Node>()
343 .AppendChild(cx, select_box.upcast::<Node>())
344 .unwrap();
345 }
346
347 fn shadow_tree(&self, cx: &mut JSContext) -> Ref<'_, ShadowTree> {
348 if !self.upcast::<Element>().is_shadow_host() {
349 self.create_shadow_tree(cx);
350 }
351
352 Ref::filter_map(self.shadow_tree.borrow(), Option::as_ref)
353 .ok()
354 .expect("UA shadow tree was not created")
355 }
356
357 pub(crate) fn update_shadow_tree(&self, cx: &mut JSContext) {
358 let shadow_tree = self.shadow_tree(cx);
359
360 let selected_options = self.selected_options();
361 let selected_options_count = selected_options.len();
362
363 let displayed_text = if selected_options_count == 1 {
364 let first_selected_option = self
365 .selected_option()
366 .or_else(|| self.list_of_options().next());
367
368 let first_selected_option_text = first_selected_option
369 .map(|option| option.displayed_label())
370 .unwrap_or_default();
371
372 itertools::join(first_selected_option_text.str().split_whitespace(), " ")
374 } else {
375 format!("{selected_options_count} selected")
376 };
377
378 shadow_tree
379 .selected_option
380 .upcast::<CharacterData>()
381 .SetData(displayed_text.trim().into());
382 }
383
384 pub(crate) fn selected_option(&self) -> Option<DomRoot<HTMLOptionElement>> {
385 self.list_of_options()
386 .find(|opt_elem| opt_elem.Selected())
387 .or_else(|| self.list_of_options().next())
388 }
389
390 pub(crate) fn selected_options(&self) -> Vec<DomRoot<HTMLOptionElement>> {
391 self.list_of_options()
392 .filter(|opt_elem| opt_elem.Selected())
393 .collect()
394 }
395
396 pub(crate) fn show_menu(&self) {
397 let mut index = 0;
399 let mut embedder_option_from_option = |option: &HTMLOptionElement| {
400 let embedder_option = SelectElementOption {
401 id: index,
402 label: option.displayed_label().into(),
403 is_disabled: option.Disabled(),
404 };
405 index += 1;
406 embedder_option
407 };
408 let options = self
409 .upcast::<Node>()
410 .children()
411 .flat_map(|child| {
412 if let Some(option) = child.downcast::<HTMLOptionElement>() {
413 return Some(embedder_option_from_option(option).into());
414 }
415
416 if let Some(optgroup) = child.downcast::<HTMLOptGroupElement>() {
417 let options = optgroup
418 .upcast::<Node>()
419 .children()
420 .flat_map(DomRoot::downcast::<HTMLOptionElement>)
421 .map(|option| embedder_option_from_option(&option))
422 .collect();
423 let label = optgroup.Label().into();
424
425 return Some(SelectElementOptionOrOptgroup::Optgroup { label, options });
426 }
427
428 None
429 })
430 .collect();
431
432 let selected_options = self
433 .list_of_options()
434 .enumerate()
435 .filter(|(_, option)| option.Selected())
436 .map(|(index, _)| index)
437 .collect();
438
439 self.owner_document()
440 .embedder_controls()
441 .show_embedder_control(
442 ControlElement::Select(DomRoot::from_ref(self)),
443 EmbedderControlRequest::SelectElement(SelectElementRequest {
444 options,
445 selected_options,
446 allow_select_multiple: self.Multiple(),
447 }),
448 None,
449 );
450 self.upcast::<Element>().set_open_state(true);
451 }
452
453 pub(crate) fn handle_embedder_response(&self, cx: &mut JSContext, selected_values: Vec<usize>) {
454 self.upcast::<Element>().set_open_state(false);
455
456 let selected_values = if self.Multiple() {
457 selected_values
458 } else {
459 selected_values.into_iter().take(1).collect()
460 };
461
462 let mut selection_did_change = false;
463 for (index, option) in self.list_of_options().enumerate() {
464 let should_be_selected = selected_values.contains(&index);
465 let option_selected_did_change = option.Selected() != should_be_selected;
466
467 if option_selected_did_change {
468 selection_did_change = true;
469 }
470
471 option.set_selectedness(should_be_selected);
472
473 if option_selected_did_change {
474 option.set_dirtiness(true);
475 }
476 }
477
478 if selection_did_change {
479 self.update_shadow_tree(cx);
480 self.send_update_notifications();
481 }
482 }
483
484 fn multiple_attribute_mutated(&self, cx: &mut JSContext, mutation: AttributeMutation) {
485 if mutation.is_removal() {
486 let mut first_enabled: Option<DomRoot<HTMLOptionElement>> = None;
487 let mut first_selected: Option<DomRoot<HTMLOptionElement>> = None;
488
489 for option in self.list_of_options() {
490 if first_selected.is_none() && option.Selected() {
491 first_selected = Some(DomRoot::from_ref(&option));
492 }
493 option.set_selectedness(false);
494 let element = option.upcast::<Element>();
495 if first_enabled.is_none() && !element.disabled_state() {
496 first_enabled = Some(DomRoot::from_ref(&option));
497 }
498 }
499
500 if let Some(first_selected) = first_selected {
501 first_selected.set_selectedness(true);
502 } else if self.display_size() == 1 &&
503 let Some(first_enabled) = first_enabled
504 {
505 first_enabled.set_selectedness(true);
506 }
507
508 self.update_shadow_tree(cx);
509 }
510 }
511
512 fn send_update_notifications(&self) {
514 let this = Trusted::new(self);
517 self.owner_global()
518 .task_manager()
519 .user_interaction_task_source()
520 .queue(task!(send_select_update_notification: move |cx| {
521 let this = this.root();
522
523 this.upcast::<EventTarget>()
528 .fire_event_with_params(cx,
529 atom!("input"),
530 EventBubbles::Bubbles,
531 EventCancelable::NotCancelable,
532 EventComposed::Composed,
533 );
534
535 this.upcast::<EventTarget>()
538 .fire_bubbling_event(cx, atom!("change"));
539 }));
540 }
541
542 fn may_have_embedder_control(&self) -> bool {
543 let el = self.upcast::<Element>();
544 !el.disabled_state()
545 }
546
547 pub(crate) fn get_enabled_selectedcontent(&self) -> Option<DomRoot<Element>> {
549 if self.Multiple() {
551 return None;
552 }
553
554 self.upcast::<Node>()
560 .traverse_preorder(ShadowIncluding::No)
561 .skip(1)
562 .filter_map(DomRoot::downcast::<Element>)
563 .find(|element| element.local_name() == &local_name!("selectedcontent"))
564 }
565}
566
567impl HTMLSelectElementMethods<crate::DomTypeHolder> for HTMLSelectElement {
568 fn Add(
570 &self,
571 cx: &mut JSContext,
572 element: HTMLOptionElementOrHTMLOptGroupElement,
573 before: Option<HTMLElementOrLong>,
574 ) -> ErrorResult {
575 self.Options().Add(cx, element, before)
576 }
577
578 make_bool_getter!(Disabled, "disabled");
580
581 make_bool_setter!(SetDisabled, "disabled");
583
584 fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
586 self.form_owner()
587 }
588
589 make_bool_getter!(Multiple, "multiple");
591
592 make_bool_setter!(SetMultiple, "multiple");
594
595 make_getter!(Name, "name");
597
598 make_atomic_setter!(SetName, "name");
600
601 make_bool_getter!(Required, "required");
603
604 make_bool_setter!(SetRequired, "required");
606
607 make_uint_getter!(Size, "size", DEFAULT_SELECT_SIZE);
609
610 make_uint_setter!(SetSize, "size", DEFAULT_SELECT_SIZE);
612
613 fn Type(&self) -> DOMString {
615 DOMString::from(if self.Multiple() {
616 "select-multiple"
617 } else {
618 "select-one"
619 })
620 }
621
622 make_labels_getter!(Labels, labels_node_list);
624
625 fn Options(&self) -> DomRoot<HTMLOptionsCollection> {
627 self.options.or_init(|| {
628 let window = self.owner_window();
629 HTMLOptionsCollection::new(
630 &window,
631 self,
632 Box::new(OptionsFilter),
633 CanGc::deprecated_note(),
634 )
635 })
636 }
637
638 fn SelectedOptions(&self, cx: &mut JSContext) -> DomRoot<HTMLCollection> {
640 self.selected_options.or_init(|| {
641 let window = self.owner_window();
642 HTMLCollection::new_with_source(
643 cx,
644 &window,
645 self.upcast(),
646 Box::new(SelectedOptionsSource),
647 )
648 })
649 }
650
651 fn Length(&self) -> u32 {
653 self.Options().Length()
654 }
655
656 fn SetLength(&self, cx: &mut JSContext, length: u32) {
658 self.Options().SetLength(cx, length)
659 }
660
661 fn Item(&self, index: u32) -> Option<DomRoot<Element>> {
663 self.Options().upcast().Item(index)
664 }
665
666 fn IndexedGetter(&self, index: u32) -> Option<DomRoot<Element>> {
668 self.Options().IndexedGetter(index)
669 }
670
671 fn IndexedSetter(
673 &self,
674 cx: &mut JSContext,
675 index: u32,
676 value: Option<&HTMLOptionElement>,
677 ) -> ErrorResult {
678 self.Options().IndexedSetter(cx, index, value)
679 }
680
681 fn NamedItem(&self, name: DOMString) -> Option<DomRoot<HTMLOptionElement>> {
683 self.Options()
684 .NamedGetter(name)
685 .and_then(DomRoot::downcast::<HTMLOptionElement>)
686 }
687
688 fn Remove_(&self, cx: &mut JSContext, index: i32) {
690 self.Options().Remove(cx, index)
691 }
692
693 fn Remove(&self, cx: &mut JSContext) {
695 self.upcast::<Element>().Remove(cx)
696 }
697
698 fn Value(&self) -> DOMString {
700 self.list_of_options()
701 .find(|opt_elem| opt_elem.Selected())
702 .map(|opt_elem| opt_elem.Value())
703 .unwrap_or_default()
704 }
705
706 fn SetValue(&self, cx: &mut JSContext, value: DOMString) {
708 let mut opt_iter = self.list_of_options();
709 for opt in opt_iter.by_ref() {
711 if opt.Value() == value {
712 opt.set_selectedness(true);
713 opt.set_dirtiness(true);
714 break;
715 }
716 opt.set_selectedness(false);
717 }
718 for opt in opt_iter {
720 opt.set_selectedness(false);
721 }
722
723 self.validity_state(CanGc::from_cx(cx))
724 .perform_validation_and_update(ValidationFlags::VALUE_MISSING, CanGc::from_cx(cx));
725 }
726
727 fn SelectedIndex(&self) -> i32 {
729 self.list_of_options()
730 .enumerate()
731 .filter(|(_, opt_elem)| opt_elem.Selected())
732 .map(|(i, _)| i as i32)
733 .next()
734 .unwrap_or(-1)
735 }
736
737 fn SetSelectedIndex(&self, cx: &mut JSContext, index: i32) {
739 let mut selection_did_change = false;
740
741 let mut opt_iter = self.list_of_options();
742 for opt in opt_iter.by_ref().take(index as usize) {
743 selection_did_change |= opt.Selected();
744 opt.set_selectedness(false);
745 }
746 if let Some(selected_option) = opt_iter.next() {
747 selection_did_change |= !selected_option.Selected();
748 selected_option.set_selectedness(true);
749 selected_option.set_dirtiness(true);
750
751 for opt in opt_iter {
753 selection_did_change |= opt.Selected();
754 opt.set_selectedness(false);
755 }
756 }
757
758 if selection_did_change {
759 self.update_shadow_tree(cx);
760 }
761 }
762
763 fn WillValidate(&self) -> bool {
765 self.is_instance_validatable()
766 }
767
768 fn Validity(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
770 self.validity_state(can_gc)
771 }
772
773 fn CheckValidity(&self, cx: &mut JSContext) -> bool {
775 self.check_validity(cx)
776 }
777
778 fn ReportValidity(&self, cx: &mut JSContext) -> bool {
780 self.report_validity(cx)
781 }
782
783 fn ValidationMessage(&self) -> DOMString {
785 self.validation_message()
786 }
787
788 fn SetCustomValidity(&self, error: DOMString, can_gc: CanGc) {
790 self.validity_state(can_gc).set_custom_error_message(error);
791 }
792}
793
794impl VirtualMethods for HTMLSelectElement {
795 fn super_type(&self) -> Option<&dyn VirtualMethods> {
796 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
797 }
798
799 fn attribute_mutated(
800 &self,
801 cx: &mut js::context::JSContext,
802 attr: AttrRef<'_>,
803 mutation: AttributeMutation,
804 ) {
805 let could_have_had_embedder_control = self.may_have_embedder_control();
806 self.super_type()
807 .unwrap()
808 .attribute_mutated(cx, attr, mutation);
809 match *attr.local_name() {
810 local_name!("multiple") => {
811 self.multiple_attribute_mutated(cx, mutation);
812 },
813 local_name!("required") => {
814 self.validity_state(CanGc::from_cx(cx))
815 .perform_validation_and_update(
816 ValidationFlags::VALUE_MISSING,
817 CanGc::from_cx(cx),
818 );
819 },
820 local_name!("disabled") => {
821 let el = self.upcast::<Element>();
822 match mutation {
823 AttributeMutation::Set(..) => {
824 el.set_disabled_state(true);
825 el.set_enabled_state(false);
826 },
827 AttributeMutation::Removed => {
828 el.set_disabled_state(false);
829 el.set_enabled_state(true);
830 el.check_ancestors_disabled_state_for_form_control();
831 },
832 }
833
834 self.validity_state(CanGc::from_cx(cx))
835 .perform_validation_and_update(
836 ValidationFlags::VALUE_MISSING,
837 CanGc::from_cx(cx),
838 );
839 },
840 local_name!("form") => {
841 self.form_attribute_mutated(mutation, CanGc::from_cx(cx));
842 },
843 _ => {},
844 }
845 if could_have_had_embedder_control && !self.may_have_embedder_control() {
846 self.owner_document()
847 .embedder_controls()
848 .hide_embedder_control(self.upcast());
849 }
850 }
851
852 fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
853 if let Some(s) = self.super_type() {
854 s.bind_to_tree(cx, context);
855 }
856
857 self.upcast::<Element>()
858 .check_ancestors_disabled_state_for_form_control();
859 }
860
861 fn unbind_from_tree(&self, cx: &mut JSContext, context: &UnbindContext) {
862 self.super_type().unwrap().unbind_from_tree(cx, context);
863
864 let node = self.upcast::<Node>();
865 let el = self.upcast::<Element>();
866 if node
867 .ancestors()
868 .any(|ancestor| ancestor.is::<HTMLFieldSetElement>())
869 {
870 el.check_ancestors_disabled_state_for_form_control();
871 } else {
872 el.check_disabled_attribute();
873 }
874
875 self.owner_document()
876 .embedder_controls()
877 .hide_embedder_control(self.upcast());
878 }
879
880 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
881 if let Some(s) = self.super_type() {
882 s.children_changed(cx, mutation);
883 }
884
885 self.update_shadow_tree(cx);
886 }
887
888 fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
889 match *local_name {
890 local_name!("size") => AttrValue::from_u32(value.into(), DEFAULT_SELECT_SIZE),
891 _ => self
892 .super_type()
893 .unwrap()
894 .parse_plain_attribute(local_name, value),
895 }
896 }
897
898 fn handle_event(&self, cx: &mut js::context::JSContext, event: &Event) {
899 self.super_type().unwrap().handle_event(cx, event);
900 if let Some(event) = event.downcast::<FocusEvent>() &&
901 *event.upcast::<Event>().type_() != *"blur"
902 {
903 self.owner_document()
904 .embedder_controls()
905 .hide_embedder_control(self.upcast());
906 }
907 }
908}
909
910impl FormControl for HTMLSelectElement {
911 fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
912 self.form_owner.get()
913 }
914
915 fn set_form_owner(&self, form: Option<&HTMLFormElement>) {
916 self.form_owner.set(form);
917 }
918
919 fn to_element(&self) -> &Element {
920 self.upcast::<Element>()
921 }
922}
923
924impl Validatable for HTMLSelectElement {
925 fn as_element(&self) -> &Element {
926 self.upcast()
927 }
928
929 fn validity_state(&self, can_gc: CanGc) -> DomRoot<ValidityState> {
930 self.validity_state
931 .or_init(|| ValidityState::new(&self.owner_window(), self.upcast(), can_gc))
932 }
933
934 fn is_instance_validatable(&self) -> bool {
935 !self.upcast::<Element>().disabled_state() && !is_barred_by_datalist_ancestor(self.upcast())
938 }
939
940 fn perform_validation(
941 &self,
942 validate_flags: ValidationFlags,
943 _can_gc: CanGc,
944 ) -> ValidationFlags {
945 let mut failed_flags = ValidationFlags::empty();
946
947 if validate_flags.contains(ValidationFlags::VALUE_MISSING) && self.Required() {
950 let placeholder = self.get_placeholder_label_option();
951 let is_value_missing = !self
952 .list_of_options()
953 .any(|e| e.Selected() && placeholder != Some(e));
954 failed_flags.set(ValidationFlags::VALUE_MISSING, is_value_missing);
955 }
956
957 failed_flags
958 }
959}
960
961impl Activatable for HTMLSelectElement {
962 fn as_element(&self) -> &Element {
963 self.upcast()
964 }
965
966 fn is_instance_activatable(&self) -> bool {
967 !self.upcast::<Element>().disabled_state()
968 }
969
970 fn activation_behavior(
971 &self,
972 _cx: &mut js::context::JSContext,
973 event: &Event,
974 _target: &EventTarget,
975 ) {
976 if !event.IsTrusted() {
977 return;
978 }
979
980 self.show_menu();
981 }
982}
983
984enum Choice3<I, J, K> {
985 First(I),
986 Second(J),
987 Third(K),
988}
989
990impl<I, J, K, T> Iterator for Choice3<I, J, K>
991where
992 I: Iterator<Item = T>,
993 J: Iterator<Item = T>,
994 K: Iterator<Item = T>,
995{
996 type Item = T;
997
998 fn next(&mut self) -> Option<T> {
999 match *self {
1000 Choice3::First(ref mut i) => i.next(),
1001 Choice3::Second(ref mut j) => j.next(),
1002 Choice3::Third(ref mut k) => k.next(),
1003 }
1004 }
1005
1006 fn size_hint(&self) -> (usize, Option<usize>) {
1007 match *self {
1008 Choice3::First(ref i) => i.size_hint(),
1009 Choice3::Second(ref j) => j.size_hint(),
1010 Choice3::Third(ref k) => k.size_hint(),
1011 }
1012 }
1013}