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