1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html;
16
17 import static org.htmlunit.BrowserVersionFeatures.JS_INPUT_NUMBER_ACCEPT_ALL;
18 import static org.htmlunit.BrowserVersionFeatures.JS_INPUT_NUMBER_DOT_AT_END_IS_DOUBLE;
19
20 import java.math.BigDecimal;
21 import java.text.NumberFormat;
22 import java.text.ParseException;
23 import java.util.Locale;
24 import java.util.Map;
25
26 import org.apache.commons.lang3.StringUtils;
27 import org.htmlunit.SgmlPage;
28
29
30
31
32
33
34
35
36
37
38
39 public class HtmlNumberInput extends HtmlSelectableTextInput implements LabelableElement {
40
41 private static final char[] VALID_INT_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-'};
42 private static final String VALID_CHARS = "0123456789-+.eE";
43
44
45
46
47
48
49
50
51 HtmlNumberInput(final String qualifiedName, final SgmlPage page,
52 final Map<String, DomAttr> attributes) {
53 super(qualifiedName, page, attributes);
54
55 final String value = getValueAttribute();
56 if (!value.isEmpty()) {
57 if (!StringUtils.containsOnly(value, VALID_CHARS)) {
58 setRawValue("");
59 }
60 }
61 }
62
63
64
65
66 @Override
67 protected boolean isSubmittableByEnter() {
68 return true;
69 }
70
71
72
73
74 @Override
75 public void setDefaultChecked(final boolean defaultChecked) {
76
77 }
78
79
80
81
82 @Override
83 protected void doType(final char c, final boolean lastType) {
84 if (!hasFeature(JS_INPUT_NUMBER_ACCEPT_ALL)) {
85 if (VALID_CHARS.indexOf(c) == -1) {
86 return;
87 }
88 }
89 super.doType(c, lastType);
90 }
91
92
93
94
95 @Override
96 public String getValue() {
97 final String raw = getRawValue();
98
99 if (StringUtils.isBlank(raw)) {
100 return "";
101 }
102
103 if (org.htmlunit.util.StringUtils.equalsChar('-', raw)
104 || org.htmlunit.util.StringUtils.equalsChar('+', raw)) {
105 return raw;
106 }
107
108 try {
109 final String lang = getPage().getWebClient().getBrowserVersion().getBrowserLanguage();
110 final NumberFormat format = NumberFormat.getInstance(Locale.forLanguageTag(lang));
111 format.parse(raw);
112
113 return raw.trim();
114 }
115 catch (final ParseException ignored) {
116
117 }
118
119 if (hasFeature(JS_INPUT_NUMBER_ACCEPT_ALL)) {
120 return raw;
121 }
122
123 return "";
124 }
125
126
127
128
129 @Override
130 public boolean isValid() {
131 if (!super.isValid()) {
132 return false;
133 }
134
135 String rawValue = getRawValue();
136 if (StringUtils.isBlank(rawValue)) {
137 return true;
138 }
139
140 if (!hasFeature(JS_INPUT_NUMBER_ACCEPT_ALL)) {
141 rawValue = rawValue.replaceAll("\\s", "");
142 }
143 if (!rawValue.isEmpty()) {
144 if (org.htmlunit.util.StringUtils.equalsChar('-', rawValue)
145 || org.htmlunit.util.StringUtils.equalsChar('+', rawValue)) {
146 return false;
147 }
148
149
150 if (getStep().isEmpty()) {
151 String val = rawValue;
152 final int lastPos = val.length() - 1;
153 if (lastPos >= 0 && val.charAt(lastPos) == '.') {
154 if (hasFeature(JS_INPUT_NUMBER_DOT_AT_END_IS_DOUBLE)) {
155 return false;
156 }
157 val = val.substring(0, lastPos);
158 }
159 if (!StringUtils.containsOnly(val, VALID_INT_CHARS)) {
160 return false;
161 }
162 }
163
164 final BigDecimal value;
165 try {
166 value = new BigDecimal(rawValue);
167 }
168 catch (final NumberFormatException e) {
169 return false;
170 }
171
172 if (!getMin().isEmpty()) {
173 try {
174 final BigDecimal min = new BigDecimal(getMin());
175 if (value.compareTo(min) < 0) {
176 return false;
177 }
178
179 if (!getStep().isEmpty()) {
180 try {
181 final BigDecimal step = new BigDecimal(getStep());
182 if (value.subtract(min).abs().remainder(step).doubleValue() > 0.0) {
183 return false;
184 }
185 }
186 catch (final NumberFormatException ignored) {
187
188 }
189 }
190 }
191 catch (final NumberFormatException ignored) {
192
193 }
194 }
195 if (!getMax().isEmpty()) {
196 try {
197 final BigDecimal max = new BigDecimal(getMax());
198 if (value.compareTo(max) > 0) {
199 return false;
200 }
201 }
202 catch (final NumberFormatException ignored) {
203
204 }
205 }
206 }
207 return true;
208 }
209 }