View Javadoc
1   /*
2    * Copyright (c) 2002-2017 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    * http://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 com.gargoylesoftware.htmlunit.javascript.host.html;
16  
17  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.EVENT_ONCLICK_USES_POINTEREVENT;
18  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.HTMLINPUT_FILES_UNDEFINED;
19  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.HTMLINPUT_FILE_SELECTION_START_END_NULL;
20  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.HTMLINPUT_FILE_VALUE_FAKEPATH;
21  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ALIGN_FOR_INPUT_IGNORES_VALUES;
22  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INPUT_NUMBER_SELECTION_START_END_NULL;
23  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INPUT_SET_TYPE_LOWERCASE;
24  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INPUT_SET_VALUE_DATE_SUPPORTED;
25  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_SELECT_FILE_THROWS;
26  import static com.gargoylesoftware.htmlunit.html.DomElement.ATTRIBUTE_NOT_DEFINED;
27  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
28  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
29  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF;
30  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF52;
31  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.IE;
32  
33  import java.io.File;
34  import java.io.IOException;
35  import java.util.Locale;
36  
37  import org.apache.commons.lang3.StringUtils;
38  import org.apache.commons.lang3.math.NumberUtils;
39  import org.xml.sax.helpers.AttributesImpl;
40  
41  import com.gargoylesoftware.htmlunit.BrowserVersion;
42  import com.gargoylesoftware.htmlunit.html.DomNode;
43  import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
44  import com.gargoylesoftware.htmlunit.html.HtmlFileInput;
45  import com.gargoylesoftware.htmlunit.html.HtmlInput;
46  import com.gargoylesoftware.htmlunit.html.HtmlRadioButtonInput;
47  import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
48  import com.gargoylesoftware.htmlunit.html.InputElementFactory;
49  import com.gargoylesoftware.htmlunit.html.impl.SelectableTextInput;
50  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
51  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor;
52  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction;
53  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
54  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxSetter;
55  import com.gargoylesoftware.htmlunit.javascript.host.dom.AbstractList;
56  import com.gargoylesoftware.htmlunit.javascript.host.dom.TextRange;
57  import com.gargoylesoftware.htmlunit.javascript.host.event.Event;
58  import com.gargoylesoftware.htmlunit.javascript.host.event.MouseEvent;
59  import com.gargoylesoftware.htmlunit.javascript.host.event.PointerEvent;
60  import com.gargoylesoftware.htmlunit.javascript.host.file.FileList;
61  
62  import net.sourceforge.htmlunit.corejs.javascript.Context;
63  import net.sourceforge.htmlunit.corejs.javascript.Undefined;
64  
65  /**
66   * The JavaScript object for {@code HTMLInputElement}.
67   *
68   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
69   * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
70   * @author Marc Guillemot
71   * @author Chris Erskine
72   * @author Ahmed Ashour
73   * @author Daniel Gredler
74   * @author Ronald Brill
75   * @author Frank Danek
76   */
77  @JsxClass(domClass = HtmlInput.class)
78  public class HTMLInputElement extends FormField {
79  
80      /** "Live" labels collection; has to be a member to have equality (==) working. */
81      private AbstractList labels_;
82  
83      /**
84       * Creates an instance.
85       */
86      @JsxConstructor({CHROME, FF, EDGE})
87      public HTMLInputElement() {
88      }
89  
90      /**
91       * Returns the {@code type} property.
92       * @return the {@code type} property
93       */
94      @JsxGetter
95      public String getType() {
96          String type = getDomNodeOrDie().getTypeAttribute();
97          final BrowserVersion browserVersion = getBrowserVersion();
98          type = type.toLowerCase(Locale.ROOT);
99          if (!InputElementFactory.isSupported(type)) {
100             type = "text";
101         }
102         else if (!browserVersion.hasFeature(JS_INPUT_SET_VALUE_DATE_SUPPORTED)) {
103             switch (type) {
104                 case "date":
105                 case "time":
106                 case "datetime-local":
107                 case "month":
108                 case "week":
109                     type = "text";
110                     break;
111 
112                 default:
113             }
114         }
115         if ("color".equals(type) && browserVersion.hasFeature(HTMLINPUT_FILES_UNDEFINED)) {
116             type = "text";
117         }
118         return type;
119     }
120 
121     /**
122      * Sets the value of the attribute {@code type}.
123      * Note: this replace the DOM node with a new one.
124      * @param newType the new type to set
125      */
126     @JsxSetter
127     public void setType(String newType) {
128         HtmlInput input = getDomNodeOrDie();
129 
130         final String currentType = input.getAttribute("type");
131 
132         if (!currentType.equalsIgnoreCase(newType)) {
133             if (newType != null && getBrowserVersion().hasFeature(JS_INPUT_SET_TYPE_LOWERCASE)) {
134                 newType = newType.toLowerCase(Locale.ROOT);
135             }
136             final AttributesImpl attributes = readAttributes(input);
137             final int index = attributes.getIndex("type");
138             if (index > -1) {
139                 attributes.setValue(index, newType);
140             }
141             else {
142                 attributes.addAttribute(null, "type", "type", null, newType);
143             }
144 
145             // create a new one only if we have a new type
146             if (ATTRIBUTE_NOT_DEFINED != currentType || !"text".equalsIgnoreCase(newType)) {
147                 final HtmlInput newInput = (HtmlInput) InputElementFactory.instance
148                         .createElement(input.getPage(), "input", attributes);
149 
150                 if (input.wasCreatedByJavascript()) {
151                     newInput.markAsCreatedByJavascript();
152                 }
153 
154                 if (input.getParentNode() == null) {
155                     // the input hasn't yet been inserted into the DOM tree (likely has been
156                     // created via document.createElement()), so simply replace it with the
157                     // new Input instance created in the code above
158                     input = newInput;
159                 }
160                 else {
161                     input.getParentNode().replaceChild(newInput, input);
162                 }
163 
164                 input.setScriptableObject(null);
165                 setDomNode(newInput, true);
166             }
167             else {
168                 super.setAttribute("type", newType);
169             }
170         }
171     }
172 
173     /**
174      * Sets the value of the JavaScript attribute {@code value}.
175      *
176      * @param newValue the new value
177      */
178     @Override
179     public void setValue(final Object newValue) {
180         if (null == newValue) {
181             getDomNodeOrDie().setValueAttribute("");
182             return;
183         }
184 
185         final String val = Context.toString(newValue);
186         final BrowserVersion browserVersion = getBrowserVersion();
187         if (StringUtils.isNotEmpty(val) && "file".equalsIgnoreCase(getType())) {
188             if (browserVersion.hasFeature(JS_SELECT_FILE_THROWS)) {
189                 throw Context.reportRuntimeError("InvalidStateError: "
190                         + "Failed to set the 'value' property on 'HTMLInputElement'.");
191             }
192             return;
193         }
194 
195         getDomNodeOrDie().setValueAttribute(val);
196     }
197 
198     /**
199      * Sets the checked property. Although this property is defined in Input it
200      * doesn't make any sense for input's other than checkbox and radio. This
201      * implementation does nothing. The implementations in Checkbox and Radio
202      * actually do the work.
203      *
204      * @param checked True if this input should have the {@code checked} attribute set
205      */
206     @JsxSetter
207     public void setChecked(final boolean checked) {
208         getDomNodeOrDie().setChecked(checked);
209     }
210 
211     /**
212      * {@inheritDoc}
213      */
214     @Override
215     public HtmlInput getDomNodeOrDie() {
216         return (HtmlInput) super.getDomNodeOrDie();
217     }
218 
219     /**
220      * Returns the value of the checked property. Although this property is
221      * defined in Input it doesn't make any sense for input's other than
222      * checkbox and radio. This implementation does nothing. The
223      * implementations in Checkbox and Radio actually do the work.
224      *
225      *@return the checked property
226      */
227     @JsxGetter
228     public boolean isChecked() {
229         return getDomNodeOrDie().isChecked();
230     }
231 
232     /**
233      * Select this element.
234      */
235     @JsxFunction
236     public void select() {
237         final HtmlInput input = getDomNodeOrDie();
238         if (input instanceof HtmlTextInput) {
239             ((HtmlTextInput) input).select();
240         }
241         // currently nothing for other input types
242     }
243 
244     /**
245      * Uses {@link #setType(String)} if attribute's name is type to
246      * replace DOM node as well as long as we have subclasses of {@link HtmlInput}.
247      * {@inheritDoc}
248      */
249     @Override
250     public void setAttribute(final String name, final String value) {
251         if ("type".equalsIgnoreCase(name)) {
252             setType(value);
253             return;
254         }
255         if ("value".equalsIgnoreCase(name)) {
256             setDefaultValue(value);
257         }
258         else {
259             super.setAttribute(name, value);
260         }
261     }
262 
263     /**
264      * Returns the input's default value, used if the containing form gets reset.
265      * @return the input's default value, used if the containing form gets reset
266      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533718.aspx">MSDN Documentation</a>
267      */
268     @JsxGetter
269     public String getDefaultValue() {
270         return getDomNodeOrDie().getDefaultValue();
271     }
272 
273     /**
274      * Sets the input's default value, used if the containing form gets reset.
275      * @param defaultValue the input's default value, used if the containing form gets reset
276      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533718.aspx">MSDN Documentation</a>
277      */
278     @JsxSetter
279     public void setDefaultValue(final String defaultValue) {
280         getDomNodeOrDie().setDefaultValue(defaultValue);
281     }
282 
283     /**
284      * Returns the input's default checked value, used if the containing form gets reset.
285      * @return the input's default checked value, used if the containing form gets reset
286      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533715.aspx">MSDN Documentation</a>
287      */
288     @JsxGetter
289     public boolean isDefaultChecked() {
290         return getDomNodeOrDie().isDefaultChecked();
291     }
292 
293     /**
294      * Sets the input's default checked value, used if the containing form gets reset.
295      * @param defaultChecked the input's default checked value, used if the containing form gets reset
296      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533715.aspx">MSDN Documentation</a>
297      */
298     @JsxSetter
299     public void setDefaultChecked(final boolean defaultChecked) {
300         getDomNodeOrDie().setDefaultChecked(defaultChecked);
301     }
302 
303     /**
304      * Gets the value of {@code textLength} attribute.
305      * @return the text length
306      */
307     @JsxGetter(FF)
308     public int getTextLength() {
309         return getValue().length();
310     }
311 
312     /**
313      * Gets the value of {@code selectionStart} attribute.
314      * @return the selection start
315      */
316     @JsxGetter
317     public Object getSelectionStart() {
318         final DomNode dom = getDomNodeOrDie();
319         if (dom instanceof SelectableTextInput) {
320             if ("number".equalsIgnoreCase(getType())
321                     && getBrowserVersion().hasFeature(JS_INPUT_NUMBER_SELECTION_START_END_NULL)) {
322                 return null;
323             }
324 
325             return ((SelectableTextInput) dom).getSelectionStart();
326         }
327 
328         if (getBrowserVersion().hasFeature(HTMLINPUT_FILE_SELECTION_START_END_NULL)) {
329             return null;
330         }
331         throw Context.reportRuntimeError("Failed to read the 'selectionStart' property from 'HTMLInputElement': "
332                 + "The input element's type (" + getType() + ") does not support selection.");
333     }
334 
335     /**
336      * Sets the value of {@code selectionStart} attribute.
337      * @param start selection start
338      */
339     @JsxSetter
340     public void setSelectionStart(final int start) {
341         final DomNode dom = getDomNodeOrDie();
342         if (dom instanceof SelectableTextInput) {
343             if ("number".equalsIgnoreCase(getType())
344                     && getBrowserVersion().hasFeature(JS_INPUT_NUMBER_SELECTION_START_END_NULL)) {
345                 throw Context.reportRuntimeError("Failed to set the 'selectionStart' property"
346                         + "from 'HTMLInputElement': "
347                         + "The input element's type ('number') does not support selection.");
348             }
349 
350             ((SelectableTextInput) dom).setSelectionStart(start);
351             return;
352         }
353 
354         throw Context.reportRuntimeError("Failed to set the 'selectionStart' property from 'HTMLInputElement': "
355                 + "The input element's type (" + getType() + ") does not support selection.");
356     }
357 
358     /**
359      * Gets the value of {@code selectionEnd} attribute.
360      * @return the selection end
361      */
362     @JsxGetter
363     public Object getSelectionEnd() {
364         final DomNode dom = getDomNodeOrDie();
365         if (dom instanceof SelectableTextInput) {
366             if ("number".equalsIgnoreCase(getType())
367                     && getBrowserVersion().hasFeature(JS_INPUT_NUMBER_SELECTION_START_END_NULL)) {
368                 return null;
369             }
370 
371             return ((SelectableTextInput) dom).getSelectionEnd();
372         }
373 
374         if (getBrowserVersion().hasFeature(HTMLINPUT_FILE_SELECTION_START_END_NULL)) {
375             return null;
376         }
377         throw Context.reportRuntimeError("Failed to read the 'selectionEnd' property from 'HTMLInputElement': "
378                 + "The input element's type (" + getType() + ") does not support selection.");
379     }
380 
381     /**
382      * Sets the value of {@code selectionEnd} attribute.
383      * @param end selection end
384      */
385     @JsxSetter
386     public void setSelectionEnd(final int end) {
387         final DomNode dom = getDomNodeOrDie();
388         if (dom instanceof SelectableTextInput) {
389             if ("number".equalsIgnoreCase(getType())
390                     && getBrowserVersion().hasFeature(JS_INPUT_NUMBER_SELECTION_START_END_NULL)) {
391                 throw Context.reportRuntimeError("Failed to set the 'selectionEnd' property"
392                         + "from 'HTMLInputElement': "
393                         + "The input element's type ('number') does not support selection.");
394             }
395 
396             ((SelectableTextInput) dom).setSelectionEnd(end);
397             return;
398         }
399 
400         throw Context.reportRuntimeError("Failed to set the 'selectionEnd' property from 'HTMLInputElement': "
401                 + "The input element's type (" + getType() + ") does not support selection.");
402     }
403 
404     /**
405      * Gets the max length.
406      * @return the max length
407      */
408     @JsxGetter
409     public int getMaxLength() {
410         final String attrValue = getDomNodeOrDie().getAttribute("maxLength");
411         return NumberUtils.toInt(attrValue, -1);
412     }
413 
414     /**
415      * Sets the value of {@code maxLength} attribute.
416      * @param length the new value
417      */
418     @JsxSetter
419     public void setMaxLength(final int length) {
420         getDomNodeOrDie().setMaxLength(length);
421     }
422 
423     /**
424      * Gets the {@code minLength}.
425      * @return the {@code minLength}
426      */
427     @JsxGetter({CHROME, FF52})
428     public int getMinLength() {
429         final String attrValue = getDomNodeOrDie().getAttribute("minLength");
430         return NumberUtils.toInt(attrValue, -1);
431     }
432 
433     /**
434      * Sets the value of {@code minLength} attribute.
435      * @param length the new value
436      */
437     @JsxSetter({CHROME, FF52})
438     public void setMinLength(final int length) {
439         getDomNodeOrDie().setMinLength(length);
440     }
441 
442     /**
443      * Gets the {@code min} property.
444      * @return the {@code min} property
445      */
446     @JsxGetter
447     public String getMin() {
448         return getDomNodeOrDie().getAttribute("min");
449     }
450 
451     /**
452      * Sets the {@code min} property.
453      * @param min the {@code min} property
454      */
455     @JsxSetter
456     public void setMin(final String min) {
457         getDomNodeOrDie().setAttribute("min", min);
458     }
459 
460     /**
461      * Gets the {@code max} property.
462      * @return the {@code max} property
463      */
464     @JsxGetter
465     public String getMax() {
466         return getDomNodeOrDie().getAttribute("max");
467     }
468 
469     /**
470      * Sets the {@code max} property.
471      * @param max the {@code max} property
472      */
473     @JsxSetter
474     public void setMax(final String max) {
475         getDomNodeOrDie().setAttribute("max", max);
476     }
477 
478     /**
479      * Gets the value of {@code readOnly} attribute.
480      * @return the readOnly attribute
481      */
482     @JsxGetter
483     public boolean isReadOnly() {
484         return getDomNodeOrDie().isReadOnly();
485     }
486 
487     /**
488      * Sets the value of {@code readOnly} attribute.
489      * @param readOnly the new value
490      */
491     @JsxSetter
492     public void setReadOnly(final boolean readOnly) {
493         getDomNodeOrDie().setReadOnly(readOnly);
494     }
495 
496     /**
497      * Sets the selected portion of this input element.
498      * @param start the index of the first character to select
499      * @param end the index of the character after the selection
500      */
501     @JsxFunction
502     public void setSelectionRange(final int start, final int end) {
503         setSelectionStart(start);
504         setSelectionEnd(end);
505     }
506 
507     /**
508      * Returns the value of the {@code alt} property.
509      * @return the value of the {@code alt} property
510      */
511     @JsxGetter
512     public String getAlt() {
513         return getDomNodeOrDie().getAttribute("alt");
514     }
515 
516     /**
517      * Returns the value of the {@code alt} property.
518      * @param alt the value
519      */
520     @JsxSetter
521     public void setAlt(final String alt) {
522         getDomNodeOrDie().setAttribute("alt", alt);
523     }
524 
525     /**
526      * Gets the {@code border} attribute.
527      * @return the {@code border} attribute
528      */
529     @JsxGetter(IE)
530     public String getBorder() {
531         return getDomNodeOrDie().getAttribute("border");
532     }
533 
534     /**
535      * Sets the {@code border} attribute.
536      * @param border the {@code border} attribute
537      */
538     @JsxSetter(IE)
539     public void setBorder(final String border) {
540         getDomNodeOrDie().setAttribute("border", border);
541     }
542 
543     /**
544      * Returns the value of the {@code align} property.
545      * @return the value of the {@code align} property
546      */
547     @JsxGetter
548     public String getAlign() {
549         if (getBrowserVersion().hasFeature(JS_ALIGN_FOR_INPUT_IGNORES_VALUES)) {
550             return "";
551         }
552         return getAlign(true);
553     }
554 
555     /**
556      * Sets the value of the {@code align} property.
557      * @param align the value of the {@code align} property
558      */
559     @JsxSetter
560     public void setAlign(final String align) {
561         final boolean ignoreIfNoError = getBrowserVersion().hasFeature(JS_ALIGN_FOR_INPUT_IGNORES_VALUES);
562         setAlign(align, ignoreIfNoError);
563     }
564 
565     /**
566      * Returns the value of the {@code src} attribute.
567      * @return the value of the {@code src} attribute
568      */
569     @JsxGetter
570     public String getSrc() {
571         return getDomNodeOrDie().getSrcAttribute();
572     }
573 
574     /**
575      * {@inheritDoc}
576      */
577     @Override
578     public String getValue() {
579         final HtmlInput htmlInput = getDomNodeOrDie();
580         if (htmlInput instanceof HtmlFileInput) {
581             final File[] files = ((HtmlFileInput) getDomNodeOrDie()).getFiles();
582             if (files == null || files.length == 0) {
583                 return ATTRIBUTE_NOT_DEFINED;
584             }
585             final File first = files[0];
586             final String name = first.getName();
587             if (name.isEmpty()) {
588                 return name;
589             }
590             if (getBrowserVersion().hasFeature(HTMLINPUT_FILE_VALUE_FAKEPATH)) {
591                 return "C:\\fakepath\\" + name;
592             }
593             return name;
594         }
595         return super.getValue();
596     }
597 
598     /**
599      * {@inheritDoc}
600      */
601     @Override
602     public String getAttribute(final String attributeName, final Integer flags) {
603         final String superAttribute = super.getAttribute(attributeName, flags);
604         if ("value".equalsIgnoreCase(attributeName)) {
605             if ((superAttribute == null || !superAttribute.isEmpty())
606                     && getDefaultValue().isEmpty()) {
607                 return null;
608             }
609             if (!"file".equals(getType())) {
610                 return getDefaultValue();
611             }
612         }
613         return superAttribute;
614     }
615 
616     /**
617      * {@inheritDoc}
618      */
619     @Override
620     public void click() throws IOException {
621         final HtmlInput domNode = getDomNodeOrDie();
622         final boolean originalState = domNode.isChecked();
623         final Event event;
624         if (getBrowserVersion().hasFeature(EVENT_ONCLICK_USES_POINTEREVENT)) {
625             event = new PointerEvent(domNode, MouseEvent.TYPE_CLICK, false, false, false, MouseEvent.BUTTON_LEFT);
626         }
627         else {
628             event = new MouseEvent(domNode, MouseEvent.TYPE_CLICK, false, false, false, MouseEvent.BUTTON_LEFT);
629         }
630         domNode.click(event, true);
631 
632         final boolean newState = domNode.isChecked();
633 
634         if (originalState != newState
635                 && (domNode instanceof HtmlRadioButtonInput || domNode instanceof HtmlCheckBoxInput)) {
636             domNode.fireEvent(Event.TYPE_CHANGE);
637         }
638     }
639 
640     /**
641      * {@inheritDoc}
642      */
643     @Override
644     protected boolean isEndTagForbidden() {
645         return true;
646     }
647 
648     /**
649      * Returns the {@code required} property.
650      * @return the {@code required} property
651      */
652     @JsxGetter
653     public boolean isRequired() {
654         return getDomNodeOrDie().isRequired();
655     }
656 
657     /**
658      * Sets the {@code required} property.
659      * @param required the new value
660      */
661     @JsxSetter
662     public void setRequired(final boolean required) {
663         getDomNodeOrDie().setRequired(required);
664     }
665 
666     /**
667      * Returns the {@code size} attribute.
668      * @return the {@code size} attribute
669      */
670     @JsxGetter
671     public String getSize() {
672         return getDomNodeOrDie().getSize();
673     }
674 
675     /**
676      * Sets the {@code size} attribute.
677      * @param size the new {@code size} value
678      */
679     @JsxSetter
680     public void setSize(final String size) {
681         getDomNodeOrDie().setSize(size);
682     }
683 
684     /**
685      * Returns the {@code accept} attribute.
686      * @return the {@code accept} attribute
687      */
688     @JsxGetter
689     public String getAccept() {
690         return getDomNodeOrDie().getAccept();
691     }
692 
693     /**
694      * Sets the {@code accept} attribute.
695      * @param accept the new {@code accept} value
696      */
697     @JsxSetter
698     public void setAccept(final String accept) {
699         getDomNodeOrDie().setAccept(accept);
700     }
701 
702     /**
703      * Returns the {@code autocomplete} attribute.
704      * @return the {@code autocomplete} attribute
705      */
706     @JsxGetter
707     public String getAutocomplete() {
708         return getDomNodeOrDie().getAutocomplete();
709     }
710 
711     /**
712      * Sets the {@code autocomplete} attribute.
713      * @param autocomplete the new {@code autocomplete} value
714      */
715     @JsxSetter
716     public void setAutocomplete(final String autocomplete) {
717         getDomNodeOrDie().setAutocomplete(autocomplete);
718     }
719 
720     /**
721      * Returns the {@code files} property.
722      * @return the {@code files} property
723      */
724     @JsxGetter
725     public Object getFiles() {
726         final HtmlInput htmlInput = getDomNodeOrDie();
727         if (htmlInput instanceof HtmlFileInput) {
728             final FileList list = new FileList(((HtmlFileInput) htmlInput).getFiles());
729             list.setParentScope(getParentScope());
730             list.setPrototype(getPrototype(list.getClass()));
731             return list;
732         }
733         if (getBrowserVersion().hasFeature(HTMLINPUT_FILES_UNDEFINED)) {
734             return Undefined.instance;
735         }
736         return null;
737     }
738 
739     /**
740      * Returns the {@code placeholder} attribute.
741      * @return the {@code placeholder} attribute
742      */
743     @JsxGetter
744     public String getPlaceholder() {
745         return getDomNodeOrDie().getPlaceholder();
746     }
747 
748     /**
749      * Sets the {@code placeholder} attribute.
750      * @param placeholder the new {@code placeholder} value
751      */
752     @JsxSetter
753     public void setPlaceholder(final String placeholder) {
754         getDomNodeOrDie().setPlaceholder(placeholder);
755     }
756 
757     /**
758      * Returns the {@code width} property.
759      * @return the {@code width} property
760      */
761     @Override
762     @JsxGetter
763     public int getWidth() {
764         final String value = getDomNodeOrDie().getAttribute("width");
765         final Integer intValue = HTMLCanvasElement.getValue(value);
766         if (intValue != null) {
767             return intValue;
768         }
769         return 0;
770     }
771 
772     /**
773      * Sets the {@code width} property.
774      * @param width the {@code width} property
775      */
776     @JsxSetter
777     public void setWidth(final int width) {
778         getDomNodeOrDie().setAttribute("width", Integer.toString(width));
779     }
780 
781     /**
782      * Returns the {@code height} property.
783      * @return the {@code height} property
784      */
785     @Override
786     @JsxGetter
787     public int getHeight() {
788         final String value = getDomNodeOrDie().getAttribute("height");
789         final Integer intValue = HTMLCanvasElement.getValue(value);
790         if (intValue != null) {
791             return intValue;
792         }
793         return 0;
794     }
795 
796     /**
797      * Sets the {@code height} property.
798      * @param height the {@code height} property
799      */
800     @JsxSetter
801     public void setHeight(final int height) {
802         getDomNodeOrDie().setAttribute("height", Integer.toString(height));
803     }
804 
805     /**
806      * Returns the labels associated with the element.
807      * @return the labels associated with the element
808      */
809     @JsxGetter(CHROME)
810     public AbstractList getLabels() {
811         if (labels_ == null) {
812             labels_ = new LabelsHelper(getDomNodeOrDie());
813         }
814         return labels_;
815     }
816 
817     /**
818      * Checks whether the element has any constraints and whether it satisfies them.
819      * @return if the element is valid
820      */
821     @JsxFunction
822     public boolean checkValidity() {
823         return getDomNodeOrDie().isValid();
824     }
825 
826     /**
827      * {@inheritDoc}
828      */
829     @Override
830     @JsxFunction(IE)
831     public TextRange createTextRange() {
832         return super.createTextRange();
833     }
834 }