1use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
5use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
6use crate::dom::bindings::inheritance::Castable;
7use crate::dom::bindings::root::DomRoot;
8use crate::dom::bindings::str::DOMString;
9use crate::dom::element::Element;
10use crate::dom::eventtarget::EventTarget;
11use crate::dom::html::htmldatalistelement::HTMLDataListElement;
12use crate::dom::html::htmlelement::HTMLElement;
13use crate::dom::node::Node;
14use crate::dom::validitystate::{ValidationFlags, ValidityState};
15use crate::script_runtime::CanGc;
16
17pub(crate) trait Validatable {
19 fn as_element(&self) -> ∈
20
21 fn validity_state(&self) -> DomRoot<ValidityState>;
23
24 fn is_instance_validatable(&self) -> bool;
26
27 fn perform_validation(
29 &self,
30 _validate_flags: ValidationFlags,
31 _can_gc: CanGc,
32 ) -> ValidationFlags {
33 ValidationFlags::empty()
34 }
35
36 fn satisfies_constraints(&self) -> bool {
38 self.validity_state().invalid_flags().is_empty()
39 }
40
41 fn check_validity(&self, can_gc: CanGc) -> bool {
43 if self.is_instance_validatable() && !self.satisfies_constraints() {
44 self.as_element()
45 .upcast::<EventTarget>()
46 .fire_cancelable_event(atom!("invalid"), can_gc);
47 false
48 } else {
49 true
50 }
51 }
52
53 fn report_validity(&self, can_gc: CanGc) -> bool {
55 if !self.is_instance_validatable() {
57 return true;
58 }
59
60 if self.satisfies_constraints() {
61 return true;
62 }
63
64 let report = self
67 .as_element()
68 .upcast::<EventTarget>()
69 .fire_cancelable_event(atom!("invalid"), can_gc);
70
71 if report {
74 let flags = self.validity_state().invalid_flags();
75 println!(
76 "Validation error: {}",
77 validation_message_for_flags(&self.validity_state(), flags)
78 );
79 if let Some(html_elem) = self.as_element().downcast::<HTMLElement>() {
80 html_elem.Focus(&FocusOptions::default(), can_gc);
82 }
83 }
84
85 false
87 }
88
89 fn validation_message(&self) -> DOMString {
91 if self.is_instance_validatable() {
92 let flags = self.validity_state().invalid_flags();
93 validation_message_for_flags(&self.validity_state(), flags)
94 } else {
95 DOMString::new()
96 }
97 }
98}
99
100pub(crate) fn is_barred_by_datalist_ancestor(elem: &Node) -> bool {
102 elem.upcast::<Node>()
103 .ancestors()
104 .any(|node| node.is::<HTMLDataListElement>())
105}
106
107fn validation_message_for_flags(state: &ValidityState, failed_flags: ValidationFlags) -> DOMString {
109 if failed_flags.contains(ValidationFlags::CUSTOM_ERROR) {
110 state.custom_error_message().clone()
111 } else {
112 DOMString::from(failed_flags.to_string())
113 }
114}