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