View Javadoc
1   /*
2    * Copyright (c) 2002-2025 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 java.time.LocalDate;
18  import java.time.format.DateTimeFormatter;
19  import java.time.format.DateTimeParseException;
20  import java.util.Map;
21  
22  import org.apache.commons.lang3.StringUtils;
23  import org.htmlunit.SgmlPage;
24  
25  /**
26   * Wrapper for the HTML element "input" where type is "date".
27   *
28   * @author Ahmed Ashour
29   * @author Ronald Brill
30   * @author Frank Danek
31   * @author Anton Demydenko
32   */
33  public class HtmlDateInput extends HtmlSelectableTextInput implements LabelableElement {
34  
35      private static final DateTimeFormatter FORMATTER_ = DateTimeFormatter.ofPattern("yyyy-MM-dd");
36  
37      /**
38       * Creates an instance.
39       *
40       * @param qualifiedName the qualified name of the element type to instantiate
41       * @param page the page that contains this element
42       * @param attributes the initial attributes
43       */
44      HtmlDateInput(final String qualifiedName, final SgmlPage page,
45              final Map<String, DomAttr> attributes) {
46          super(qualifiedName, page, attributes);
47      }
48  
49      /**
50       * {@inheritDoc}
51       */
52      @Override
53      protected boolean isSubmittableByEnter() {
54          return true;
55      }
56  
57      /**
58       * {@inheritDoc}
59       */
60      @Override
61      public void setDefaultChecked(final boolean defaultChecked) {
62          // Empty.
63      }
64  
65      /**
66       * {@inheritDoc}
67       * @see HtmlInput#reset()
68       */
69      @Override
70      public void reset() {
71          super.reset();
72          setSelectionEnd(0);
73      }
74  
75      /**
76       * {@inheritDoc}
77       */
78      @Override
79      protected boolean isPatternSupported() {
80          return true;
81      }
82  
83      /**
84       * {@inheritDoc}
85       */
86      @Override
87      public boolean isValid() {
88          return super.isValid() && isMaxValid() && isMinValid();
89      }
90  
91      /**
92       * Returns if the input element has a valid min value. Refer to the
93       * <a href="https://www.w3.org/TR/html5/sec-forms.html">HTML 5</a> documentation
94       * for details.
95       *
96       * @return if the input element has a valid min value
97       */
98      private boolean isMinValid() {
99          if (!getMin().isEmpty()) {
100             try {
101                 final LocalDate dateValue = LocalDate.parse(getRawValue(), FORMATTER_);
102                 final LocalDate minDate = LocalDate.parse(getMin(), FORMATTER_);
103                 return minDate.isEqual(dateValue) || minDate.isBefore(dateValue);
104             }
105             catch (final DateTimeParseException ignored) {
106                 // ignore
107             }
108         }
109         return true;
110     }
111 
112     /**
113      * Returns if the input element has a valid max value. Refer to the
114      * <a href="https://www.w3.org/TR/html5/sec-forms.html">HTML 5</a> documentation
115      * for details.
116      *
117      * @return if the input element has a valid max value
118      */
119     private boolean isMaxValid() {
120         if (!getMax().isEmpty()) {
121             try {
122                 final LocalDate dateValue = LocalDate.parse(getRawValue(), FORMATTER_);
123                 final LocalDate maxDate = LocalDate.parse(getMax(), FORMATTER_);
124                 return maxDate.isEqual(dateValue) || maxDate.isAfter(dateValue);
125             }
126             catch (final DateTimeParseException ignored) {
127                 // ignore
128             }
129         }
130         return true;
131     }
132 
133     /**
134      * {@inheritDoc}
135      */
136     @Override
137     public void setValue(final String newValue) {
138         try {
139             if (StringUtils.isNotEmpty(newValue)) {
140                 FORMATTER_.parse(newValue);
141             }
142             super.setValue(newValue);
143         }
144         catch (final DateTimeParseException ignored) {
145             // ignore
146         }
147     }
148 }