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