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.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 */
33 public class HtmlDateTimeLocalInput extends HtmlInput implements LabelableElement {
34
35 private static final DateTimeFormatter FORMATTER_ = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm");
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 HtmlDateTimeLocalInput(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 public void setDefaultChecked(final boolean defaultChecked) {
54 // Empty.
55 }
56
57 /**
58 * {@inheritDoc}
59 */
60 @Override
61 public void setValue(final String newValue) {
62 try {
63 if (!StringUtils.isEmptyOrNull(newValue)) {
64 FORMATTER_.parse(newValue);
65 }
66 super.setValue(newValue);
67 }
68 catch (final DateTimeParseException ignored) {
69 // ignore
70 }
71 }
72
73 /**
74 * {@inheritDoc}
75 */
76 @Override
77 public boolean isValid() {
78 return super.isValid() && isMaxValid() && isMinValid();
79 }
80
81 /**
82 * Returns if the input element has a valid min value. Refer to the
83 * <a href="https://www.w3.org/TR/html5/sec-forms.html">HTML 5</a> documentation
84 * for details.
85 *
86 * @return if the input element has a valid min value
87 */
88 private boolean isMinValid() {
89 if (!getMin().isEmpty()) {
90 try {
91 final LocalDateTime dateValue = LocalDateTime.parse(getRawValue(), FORMATTER_);
92 final LocalDateTime minDate = LocalDateTime.parse(getMin(), FORMATTER_);
93 return minDate.isEqual(dateValue) || minDate.isBefore(dateValue);
94 }
95 catch (final DateTimeParseException ignored) {
96 // ignore
97 }
98 }
99 return true;
100 }
101
102 /**
103 * Returns if the input element has a valid max value. Refer to the
104 * <a href="https://www.w3.org/TR/html5/sec-forms.html">HTML 5</a> documentation
105 * for details.
106 *
107 * @return if the input element has a valid max value
108 */
109 private boolean isMaxValid() {
110 if (!getMax().isEmpty()) {
111 try {
112 final LocalDateTime dateValue = LocalDateTime.parse(getRawValue(), FORMATTER_);
113 final LocalDateTime maxDate = LocalDateTime.parse(getMax(), FORMATTER_);
114 return maxDate.isEqual(dateValue) || maxDate.isAfter(dateValue);
115 }
116 catch (final DateTimeParseException ignored) {
117 // ignore
118 }
119 }
120 return true;
121 }
122
123 @Override
124 protected void adjustValueAfterTypeChange(final HtmlInput oldInput, final BrowserVersion browserVersion) {
125 setValue("");
126 }
127 }