1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.html;
16
17 import static org.htmlunit.BrowserVersionFeatures.JS_INPUT_NUMBER_DOT_AT_END_IS_DOUBLE;
18 import static org.htmlunit.javascript.configuration.SupportedBrowser.FF;
19 import static org.htmlunit.javascript.configuration.SupportedBrowser.FF_ESR;
20
21 import java.io.IOException;
22
23 import org.apache.commons.lang3.StringUtils;
24 import org.apache.commons.lang3.math.NumberUtils;
25 import org.htmlunit.html.DomElement;
26 import org.htmlunit.html.DomNode;
27 import org.htmlunit.html.HtmlCheckBoxInput;
28 import org.htmlunit.html.HtmlFileInput;
29 import org.htmlunit.html.HtmlInput;
30 import org.htmlunit.html.HtmlNumberInput;
31 import org.htmlunit.html.HtmlRadioButtonInput;
32 import org.htmlunit.html.HtmlTextInput;
33 import org.htmlunit.html.impl.SelectableTextInput;
34 import org.htmlunit.javascript.JavaScriptEngine;
35 import org.htmlunit.javascript.configuration.JsxClass;
36 import org.htmlunit.javascript.configuration.JsxConstructor;
37 import org.htmlunit.javascript.configuration.JsxFunction;
38 import org.htmlunit.javascript.configuration.JsxGetter;
39 import org.htmlunit.javascript.configuration.JsxSetter;
40 import org.htmlunit.javascript.host.dom.DOMException;
41 import org.htmlunit.javascript.host.dom.NodeList;
42 import org.htmlunit.javascript.host.event.Event;
43 import org.htmlunit.javascript.host.file.FileList;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 @JsxClass(domClass = HtmlInput.class)
59 public class HTMLInputElement extends HTMLElement {
60
61
62 private NodeList labels_;
63
64
65
66
67 @Override
68 @JsxConstructor
69 public void jsConstructor() {
70 super.jsConstructor();
71 }
72
73
74
75
76
77 @JsxGetter
78 public String getType() {
79 return getDomNodeOrDie().getType();
80 }
81
82
83
84
85
86
87 @JsxSetter
88 public void setType(final String newType) {
89 getDomNodeOrDie().changeType(newType, false);
90 }
91
92
93
94
95
96
97 @JsxSetter
98 @Override
99 public void setValue(final Object newValue) {
100 if (null == newValue) {
101 getDomNodeOrDie().setValue("");
102 getDomNodeOrDie().valueModifiedByJavascript();
103 return;
104 }
105
106 final String val = JavaScriptEngine.toString(newValue);
107 if ("file".equalsIgnoreCase(getType())) {
108 if (StringUtils.isNotEmpty(val)) {
109 throw JavaScriptEngine.asJavaScriptException(
110 getWindow(),
111 "Failed to set the 'value' property on 'HTMLInputElement'.",
112 DOMException.INVALID_STATE_ERR);
113 }
114 return;
115 }
116
117 getDomNodeOrDie().setValue(val);
118 getDomNodeOrDie().valueModifiedByJavascript();
119 }
120
121
122
123
124
125
126
127
128
129 @JsxSetter
130 public void setChecked(final boolean checked) {
131 getDomNodeOrDie().setChecked(checked);
132 }
133
134
135
136
137 @Override
138 public HtmlInput getDomNodeOrDie() {
139 return (HtmlInput) super.getDomNodeOrDie();
140 }
141
142
143
144
145
146
147
148
149
150 @JsxGetter
151 public boolean isChecked() {
152 return getDomNodeOrDie().isChecked();
153 }
154
155
156
157
158 @JsxFunction
159 public void select() {
160 final HtmlInput input = getDomNodeOrDie();
161 if (input instanceof HtmlTextInput) {
162 ((HtmlTextInput) input).select();
163 }
164
165 }
166
167
168
169
170
171
172 @JsxGetter
173 public String getDefaultValue() {
174 return getDomNodeOrDie().getDefaultValue();
175 }
176
177
178
179
180
181
182 @JsxSetter
183 public void setDefaultValue(final String defaultValue) {
184 getDomNodeOrDie().setDefaultValue(defaultValue);
185 }
186
187
188
189
190
191
192 @JsxGetter
193 public boolean isDefaultChecked() {
194 return getDomNodeOrDie().isDefaultChecked();
195 }
196
197
198
199
200
201
202 @JsxSetter
203 public void setDefaultChecked(final boolean defaultChecked) {
204 getDomNodeOrDie().setDefaultChecked(defaultChecked);
205 }
206
207
208
209
210
211 @JsxGetter({FF, FF_ESR})
212 public int getTextLength() {
213 return getValue().length();
214 }
215
216
217
218
219
220 @JsxGetter
221 public Integer getSelectionStart() {
222 final DomNode dom = getDomNodeOrDie();
223 if (dom instanceof SelectableTextInput) {
224 if ("number".equalsIgnoreCase(getType())) {
225 return null;
226 }
227
228 return ((SelectableTextInput) dom).getSelectionStart();
229 }
230
231 return null;
232 }
233
234
235
236
237
238 @JsxSetter
239 public void setSelectionStart(final int start) {
240 final DomNode dom = getDomNodeOrDie();
241 if (dom instanceof SelectableTextInput) {
242 if ("number".equalsIgnoreCase(getType())) {
243 throw JavaScriptEngine.asJavaScriptException(
244 getWindow(),
245 "Failed to set the 'selectionStart' property"
246 + "from 'HTMLInputElement': "
247 + "The input element's type ('number') does not support selection.",
248 DOMException.INVALID_STATE_ERR);
249 }
250
251 ((SelectableTextInput) dom).setSelectionStart(start);
252 return;
253 }
254
255 throw JavaScriptEngine.asJavaScriptException(
256 getWindow(),
257 "Failed to set the 'selectionStart' property from 'HTMLInputElement': "
258 + "The input element's type (" + getType() + ") does not support selection.",
259 DOMException.INVALID_STATE_ERR);
260 }
261
262
263
264
265
266 @JsxGetter
267 public Integer getSelectionEnd() {
268 final DomNode dom = getDomNodeOrDie();
269 if (dom instanceof SelectableTextInput) {
270 if ("number".equalsIgnoreCase(getType())) {
271 return null;
272 }
273
274 return ((SelectableTextInput) dom).getSelectionEnd();
275 }
276
277 return null;
278 }
279
280
281
282
283
284 @JsxSetter
285 public void setSelectionEnd(final int end) {
286 final DomNode dom = getDomNodeOrDie();
287 if (dom instanceof SelectableTextInput) {
288 if ("number".equalsIgnoreCase(getType())) {
289 throw JavaScriptEngine.asJavaScriptException(
290 getWindow(),
291 "Failed to set the 'selectionEnd' property"
292 + "from 'HTMLInputElement': "
293 + "The input element's type ('number') does not support selection.",
294 DOMException.INVALID_STATE_ERR);
295 }
296
297 ((SelectableTextInput) dom).setSelectionEnd(end);
298 return;
299 }
300
301 throw JavaScriptEngine.asJavaScriptException(
302 getWindow(),
303 "Failed to set the 'selectionEnd' property from 'HTMLInputElement': "
304 + "The input element's type (" + getType() + ") does not support selection.",
305 DOMException.INVALID_STATE_ERR);
306 }
307
308
309
310
311
312 @JsxGetter
313 public int getMaxLength() {
314 final String attrValue = getDomNodeOrDie().getAttribute("maxLength");
315 return NumberUtils.toInt(attrValue, -1);
316 }
317
318
319
320
321
322 @JsxSetter
323 public void setMaxLength(final int length) {
324 getDomNodeOrDie().setMaxLength(length);
325 }
326
327
328
329
330
331 @JsxGetter
332 public int getMinLength() {
333 final String attrValue = getDomNodeOrDie().getAttribute("minLength");
334 return NumberUtils.toInt(attrValue, -1);
335 }
336
337
338
339
340
341 @JsxSetter
342 public void setMinLength(final int length) {
343 getDomNodeOrDie().setMinLength(length);
344 }
345
346
347
348
349
350 @JsxGetter
351 public String getMin() {
352 return getDomNodeOrDie().getAttributeDirect("min");
353 }
354
355
356
357
358
359 @JsxSetter
360 public void setMin(final String min) {
361 getDomNodeOrDie().setAttribute("min", min);
362 }
363
364
365
366
367
368 @JsxGetter
369 public String getMax() {
370 return getDomNodeOrDie().getAttributeDirect("max");
371 }
372
373
374
375
376
377 @JsxSetter
378 public void setMax(final String max) {
379 getDomNodeOrDie().setAttribute("max", max);
380 }
381
382
383
384
385
386 @JsxGetter
387 public String getStep() {
388 return getDomNodeOrDie().getAttributeDirect("step");
389 }
390
391
392
393
394
395 @JsxSetter
396 public void setStep(final String step) {
397 getDomNodeOrDie().setAttribute("step", step);
398 }
399
400
401
402
403
404 @JsxGetter
405 public boolean isReadOnly() {
406 return getDomNodeOrDie().isReadOnly();
407 }
408
409
410
411
412
413 @JsxSetter
414 public void setReadOnly(final boolean readOnly) {
415 getDomNodeOrDie().setReadOnly(readOnly);
416 }
417
418
419
420
421
422
423 @JsxFunction
424 public void setSelectionRange(final int start, final int end) {
425 setSelectionStart(start);
426 setSelectionEnd(end);
427 }
428
429
430
431
432
433 @JsxGetter
434 public String getAlt() {
435 return getDomNodeOrDie().getAttributeDirect("alt");
436 }
437
438
439
440
441
442 @JsxSetter
443 public void setAlt(final String alt) {
444 getDomNodeOrDie().setAttribute("alt", alt);
445 }
446
447
448
449
450
451 @JsxGetter
452 public String getAlign() {
453 return getAlign(true);
454 }
455
456
457
458
459
460 @JsxSetter
461 public void setAlign(final String align) {
462 setAlign(align, false);
463 }
464
465
466
467
468
469 @JsxGetter
470 public String getSrc() {
471 return getDomNodeOrDie().getSrc();
472 }
473
474
475
476
477
478 @JsxSetter
479 public void setSrc(final String src) {
480 getDomNodeOrDie().setSrcAttribute(src);
481 }
482
483
484
485
486
487
488 @JsxGetter
489 @Override
490 public String getValue() {
491 final HtmlInput htmlInput = getDomNodeOrDie();
492
493 if (htmlInput instanceof HtmlNumberInput) {
494 final String valueAttr = htmlInput.getValue();
495 if (!valueAttr.isEmpty()) {
496 if (org.htmlunit.util.StringUtils.equalsChar('-', valueAttr)
497 || org.htmlunit.util.StringUtils.equalsChar('+', valueAttr)) {
498 return "";
499 }
500
501 final int lastPos = valueAttr.length() - 1;
502 if (lastPos >= 0 && valueAttr.charAt(lastPos) == '.') {
503 if (htmlInput.hasFeature(JS_INPUT_NUMBER_DOT_AT_END_IS_DOUBLE)) {
504 return "";
505 }
506 }
507 try {
508 Double.parseDouble(valueAttr);
509 }
510 catch (final NumberFormatException e) {
511 return "";
512 }
513 }
514 }
515
516 return htmlInput.getValue();
517 }
518
519
520
521
522 @Override
523 public String getAttribute(final String attributeName) {
524 final String superAttribute = super.getAttribute(attributeName);
525 if (DomElement.VALUE_ATTRIBUTE.equalsIgnoreCase(attributeName)) {
526 if ((superAttribute == null || !superAttribute.isEmpty())
527 && getDefaultValue().isEmpty()) {
528 return null;
529 }
530 if (!"file".equals(getType())) {
531 return getDefaultValue();
532 }
533 }
534 return superAttribute;
535 }
536
537
538
539
540 @Override
541 public void click() throws IOException {
542 final HtmlInput domNode = getDomNodeOrDie();
543 final boolean originalState = domNode.isChecked();
544
545 domNode.click(false, false, false, false, false, true, false);
546
547 final boolean newState = domNode.isChecked();
548
549 if (originalState != newState
550 && (domNode instanceof HtmlRadioButtonInput || domNode instanceof HtmlCheckBoxInput)) {
551 domNode.fireEvent(Event.TYPE_CHANGE);
552 }
553 }
554
555
556
557
558 @Override
559 protected boolean isEndTagForbidden() {
560 return true;
561 }
562
563
564
565
566
567 @JsxGetter
568 public boolean isRequired() {
569 return getDomNodeOrDie().isRequired();
570 }
571
572
573
574
575
576 @JsxSetter
577 public void setRequired(final boolean required) {
578 getDomNodeOrDie().setRequired(required);
579 }
580
581
582
583
584
585 @JsxGetter
586 public String getSize() {
587 return getDomNodeOrDie().getSize();
588 }
589
590
591
592
593
594 @JsxSetter
595 public void setSize(final String size) {
596 getDomNodeOrDie().setSize(size);
597 }
598
599
600
601
602
603 @JsxGetter
604 public String getAccept() {
605 return getDomNodeOrDie().getAccept();
606 }
607
608
609
610
611
612 @JsxSetter
613 public void setAccept(final String accept) {
614 getDomNodeOrDie().setAccept(accept);
615 }
616
617
618
619
620
621 @JsxGetter
622 public String getAutocomplete() {
623 return getDomNodeOrDie().getAutocomplete();
624 }
625
626
627
628
629
630 @JsxSetter
631 public void setAutocomplete(final String autocomplete) {
632 getDomNodeOrDie().setAutocomplete(autocomplete);
633 }
634
635
636
637
638
639 @JsxGetter
640 public FileList getFiles() {
641 final HtmlInput htmlInput = getDomNodeOrDie();
642 if (htmlInput instanceof HtmlFileInput) {
643 final FileList list = new FileList(((HtmlFileInput) htmlInput).getFiles());
644 list.setParentScope(getParentScope());
645 list.setPrototype(getPrototype(list.getClass()));
646 return list;
647 }
648 return null;
649 }
650
651
652
653
654
655 @JsxGetter
656 public String getPlaceholder() {
657 return getDomNodeOrDie().getPlaceholder();
658 }
659
660
661
662
663
664 @JsxSetter
665 public void setPlaceholder(final String placeholder) {
666 getDomNodeOrDie().setPlaceholder(placeholder);
667 }
668
669
670
671
672
673 @JsxGetter
674 public int getWidth() {
675 final String value = getDomNodeOrDie().getAttributeDirect("width");
676 final Integer intValue = HTMLCanvasElement.getValue(value);
677 if (intValue != null) {
678 return intValue;
679 }
680 return 0;
681 }
682
683
684
685
686
687 @JsxSetter
688 public void setWidth(final int width) {
689 getDomNodeOrDie().setAttribute("width", Integer.toString(width));
690 }
691
692
693
694
695
696 @JsxGetter
697 public int getHeight() {
698 final String value = getDomNodeOrDie().getAttributeDirect("height");
699 final Integer intValue = HTMLCanvasElement.getValue(value);
700 if (intValue != null) {
701 return intValue;
702 }
703 return 0;
704 }
705
706
707
708
709
710 @JsxSetter
711 public void setHeight(final int height) {
712 getDomNodeOrDie().setAttribute("height", Integer.toString(height));
713 }
714
715
716
717
718
719 @JsxGetter
720 public NodeList getLabels() {
721 if (labels_ == null) {
722 labels_ = new LabelsNodeList(getDomNodeOrDie());
723 }
724 return labels_;
725 }
726
727
728
729
730
731 @JsxFunction
732 public boolean checkValidity() {
733 return getDomNodeOrDie().isValid();
734 }
735
736
737
738
739 @JsxGetter
740 @Override
741 public String getName() {
742 return super.getName();
743 }
744
745
746
747
748 @JsxSetter
749 @Override
750 public void setName(final String newName) {
751 super.setName(newName);
752 }
753
754
755
756
757 @Override
758 @JsxGetter
759 public boolean isDisabled() {
760 return super.isDisabled();
761 }
762
763
764
765
766 @Override
767 @JsxSetter
768 public void setDisabled(final boolean disabled) {
769 super.setDisabled(disabled);
770 }
771
772
773
774
775 @JsxGetter
776 @Override
777 public HTMLFormElement getForm() {
778 return super.getForm();
779 }
780
781
782
783
784 @JsxGetter
785 public ValidityState getValidity() {
786 final ValidityState validityState = new ValidityState();
787 validityState.setPrototype(getPrototype(validityState.getClass()));
788 validityState.setParentScope(getParentScope());
789 validityState.setDomNode(getDomNodeOrDie());
790 return validityState;
791 }
792
793
794
795
796 @JsxGetter
797 public boolean getWillValidate() {
798 return getDomNodeOrDie().willValidate();
799 }
800
801
802
803
804
805 @JsxFunction
806 public void setCustomValidity(final String message) {
807 getDomNodeOrDie().setCustomValidity(message);
808 }
809
810
811
812
813
814 @JsxGetter
815 public boolean isFormNoValidate() {
816 return getDomNodeOrDie().isFormNoValidate();
817 }
818
819
820
821
822
823 @JsxSetter
824 public void setFormNoValidate(final boolean value) {
825 getDomNodeOrDie().setFormNoValidate(value);
826 }
827 }