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