View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html;
16  
17  import org.htmlunit.javascript.host.html.ValidatableHTMLElement;
18  
19  /**
20   * An {@link HtmlElement} that supports client-side validation using the Constraint Validation API.
21   * This uses {@link ValidatableHTMLElement}.
22   *
23   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Constraint_validation">
24   *      Constraint Validation API</a>
25   *
26   * @author Ronald Brill
27   */
28  public interface ValidatableHtmlElement {
29  
30      /**
31       * Returns whether the element is a candidate for constraint validation.
32       *
33       * @return whether the element is a candidate for constraint validation
34       */
35      boolean willValidate();
36  
37      /**
38       * Sets the custom validity message for the element.
39       *
40       * @param message the new message
41       */
42      void setCustomValidity(String message);
43  
44      /**
45       * Returns whether the user has provided input that the browser is unable to convert.
46       *
47       * @return {@code true} if the user has provided input that the browser is unable to convert
48       */
49      default boolean hasBadInputValidityState() {
50          return false;
51      }
52  
53      /**
54       * Returns whether the element has a custom validity message.
55       *
56       * @return {@code true} if the element's custom validity message has been set to a non-empty
57       *         string by calling {@link #setCustomValidity(String)}
58       */
59      boolean isCustomErrorValidityState();
60  
61      /**
62       * Returns whether the element's value does not match the specified pattern.
63       *
64       * @return {@code true} if the value does not match the specified pattern;
65       *         if {@code true}, the element matches the {@code :invalid} CSS pseudo-class
66       */
67      default boolean hasPatternMismatchValidityState() {
68          return false;
69      }
70  
71      /**
72       * Returns whether the element's value does not satisfy the {@code step} constraint.
73       *
74       * @return {@code true} if the value does not fit the rules determined by the
75       *         {@code step} attribute; if {@code true}, the element matches the
76       *         {@code :invalid} and {@code :out-of-range} CSS pseudo-classes
77       */
78      default boolean isStepMismatchValidityState() {
79          return false;
80      }
81  
82      /**
83       * Returns whether the element's value exceeds the maximum allowed length.
84       *
85       * @return {@code true} if the value is longer than the maximum length specified by the
86       *         {@code maxlength} attribute; if {@code true}, the element matches the
87       *         {@code :invalid} CSS pseudo-class
88       */
89      default boolean isTooLongValidityState() {
90          return false;
91      }
92  
93      /**
94       * Returns whether the element's value is shorter than the minimum required length.
95       *
96       * @return {@code true} if the value is shorter than the minimum length specified by the
97       *         {@code minlength} attribute; if {@code true}, the element matches the
98       *         {@code :invalid} CSS pseudo-class
99       */
100     default boolean isTooShortValidityState() {
101         return false;
102     }
103 
104     /**
105      * Returns whether the element's value has a type mismatch.
106      *
107      * @return {@code true} if the value is not in the required syntax (for example,
108      *         for {@code email} or {@code url}); if {@code true}, the element matches the
109      *         {@code :invalid} CSS pseudo-class
110      */
111     default boolean hasTypeMismatchValidityState() {
112         return false;
113     }
114 
115     /**
116      * Returns whether the element's value exceeds the maximum allowed value.
117      *
118      * @return {@code true} if the value is greater than the maximum specified by the
119      *         {@code max} attribute; if {@code true}, the element matches the
120      *         {@code :invalid} and {@code :out-of-range} CSS pseudo-classes
121      */
122     default boolean hasRangeOverflowValidityState() {
123         return false;
124     }
125 
126     /**
127      * Returns whether the element's value is less than the minimum allowed value.
128      *
129      * @return {@code true} if the value is less than the minimum specified by the
130      *         {@code min} attribute; if {@code true}, the element matches the
131      *         {@code :invalid} and {@code :out-of-range} CSS pseudo-classes
132      */
133     default boolean hasRangeUnderflowValidityState() {
134         return false;
135     }
136 
137     /**
138      * Returns whether the element satisfies all validation constraints.
139      *
140      * @return {@code true} if the element is valid; if {@code true}, the element matches the
141      *         {@code :valid} CSS pseudo-class, otherwise the {@code :invalid} CSS pseudo-class
142      */
143     boolean isValidValidityState();
144 
145     /**
146      * Returns whether the element is missing a required value.
147      *
148      * @return {@code true} if the element has a required attribute but no value;
149      *         if {@code true}, the element matches the {@code :invalid} CSS pseudo-class
150      */
151     default boolean isValueMissingValidityState() {
152         return false;
153     }
154 
155     /**
156      * Returns the raw custom validity message set via {@link #setCustomValidity(String)},
157      * or the empty string if none has been set.
158      * @return the custom validity message
159      */
160     String getCustomValidity();
161 
162     /**
163      * Returns the (potentially control-specific) message describing the
164      * currently failing constraint, in spec priority order:
165      * customError, patternMismatch, rangeOverflow, rangeUnderflow,
166      * stepMismatch, tooLong, tooShort, typeMismatch, badInput, valueMissing.
167      * Returns "" if barred from validation or currently valid.
168      * @return the validation message
169      */
170     default String getValidationMessage() {
171         if (!willValidate() || isValidValidityState()) {
172             return "";
173         }
174         if (isCustomErrorValidityState()) {
175             return getCustomValidity();
176         }
177         if (hasPatternMismatchValidityState()) {
178             return getPatternMismatchMessage();
179         }
180         if (hasRangeOverflowValidityState()) {
181             return getRangeOverflowMessage();
182         }
183         if (hasRangeUnderflowValidityState()) {
184             return getRangeUnderflowMessage();
185         }
186         if (isStepMismatchValidityState()) {
187             return getStepMismatchMessage();
188         }
189         if (isTooLongValidityState()) {
190             return getTooLongMessage();
191         }
192         if (isTooShortValidityState()) {
193             return getTooShortMessage();
194         }
195         if (hasTypeMismatchValidityState()) {
196             return getTypeMismatchMessage();
197         }
198         if (hasBadInputValidityState()) {
199             return getBadInputMessage();
200         }
201         if (isValueMissingValidityState()) {
202             return getValueMissingMessage();
203         }
204         return "";
205     }
206 
207     /**
208      * Returns the message describing a pattern mismatch (the element's value
209      * does not match the constraint specified by the {@code pattern}
210      * attribute). Generic, uniform wording -- override in a concrete class
211      * that can interpolate control-specific details (e.g. the {@code pattern}
212      * itself or a {@code title} hint) into the message.
213      * @return the pattern mismatch message
214      */
215     default String getPatternMismatchMessage() {
216         return "Please match the requested format.";
217     }
218 
219     /**
220      * Returns the message describing a range overflow (the element's value is
221      * greater than the maximum specified by the {@code max} attribute).
222      * Generic, uniform wording -- override in a concrete class that can
223      * interpolate the actual {@code max} value into the message.
224      * @return the range overflow message
225      */
226     default String getRangeOverflowMessage() {
227         return "Value must be less than or equal to the maximum.";
228     }
229 
230     /**
231      * Returns the message describing a range underflow (the element's value is
232      * less than the minimum specified by the {@code min} attribute). Generic,
233      * uniform wording -- override in a concrete class that can interpolate the
234      * actual {@code min} value into the message.
235      * @return the range underflow message
236      */
237     default String getRangeUnderflowMessage() {
238         return "Value must be greater than or equal to the minimum.";
239     }
240 
241     /**
242      * Returns the message describing a step mismatch (the element's value does
243      * not satisfy the constraint specified by the {@code step} attribute).
244      * Generic fallback wording -- real browsers typically also name the two
245      * nearest step-aligned valid values, which this default does not attempt
246      * to compute; override in a concrete class if that level of detail is
247      * needed.
248      * @return the step mismatch message
249      */
250     default String getStepMismatchMessage() {
251         return "Please enter a valid value.";
252     }
253 
254     /**
255      * Returns the message describing a too-long value (the element's value is
256      * longer than the maximum length specified by the {@code maxlength}
257      * attribute). Generic, uniform wording -- override in a concrete class
258      * that can interpolate the actual {@code maxlength} and current length
259      * into the message.
260      * @return the too-long message
261      */
262     default String getTooLongMessage() {
263         return "Please shorten this text.";
264     }
265 
266     /**
267      * Returns the message describing a too-short value (the element's value is
268      * shorter than the minimum length specified by the {@code minlength}
269      * attribute). Generic, uniform wording -- override in a concrete class
270      * that can interpolate the actual {@code minlength} and current length
271      * into the message.
272      * @return the too-short message
273      */
274     default String getTooShortMessage() {
275         return "Please lengthen this text.";
276     }
277 
278     /**
279      * Returns the message describing a type mismatch (the element's value is
280      * not in the syntax required by its {@code type}, e.g. {@code email} or
281      * {@code url}). Generic, uniform wording -- override in a concrete class
282      * that can produce a type-specific message.
283      * @return the type mismatch message
284      */
285     default String getTypeMismatchMessage() {
286         return "Please enter a valid value.";
287     }
288 
289     /**
290      * Returns the message describing bad input (the user has provided input
291      * that the browser is unable to convert, e.g. non-numeric text typed into
292      * a {@code number} input). Generic, uniform wording.
293      * @return the bad input message
294      */
295     default String getBadInputMessage() {
296         return "Please enter a valid value.";
297     }
298 
299     /**
300      * Returns the message describing a missing required value (the element has
301      * a {@code required} attribute but no value). Generic, uniform wording.
302      * @return the value missing message
303      */
304     default String getValueMissingMessage() {
305         return "Please fill out this field.";
306     }
307 }