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 }