com.gargoylesoftware.htmlunit.javascript.host.html.HTMLInputElement.java Source code

Java tutorial

Introduction

Here is the source code for com.gargoylesoftware.htmlunit.javascript.host.html.HTMLInputElement.java

Source

/*
 * Copyright (c) 2002-2016 Gargoyle Software Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gargoylesoftware.htmlunit.javascript.host.html;

import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.EVENT_ONCLICK_USES_POINTEREVENT;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.HTMLINPUT_FILES_UNDEFINED;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ALIGN_FOR_INPUT_IGNORES_VALUES;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INPUT_SET_TYPE_LOWERCASE;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INPUT_SET_VALUE_EMAIL_TRIMMED;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INPUT_SET_VALUE_URL_TRIMMED;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_SELECT_FILE_THROWS;
import static com.gargoylesoftware.htmlunit.html.DomElement.ATTRIBUTE_NOT_DEFINED;
import static com.gargoylesoftware.htmlunit.javascript.configuration.BrowserName.CHROME;
import static com.gargoylesoftware.htmlunit.javascript.configuration.BrowserName.EDGE;
import static com.gargoylesoftware.htmlunit.javascript.configuration.BrowserName.FF;
import static com.gargoylesoftware.htmlunit.javascript.configuration.BrowserName.IE;

import java.io.IOException;
import java.util.Locale;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.xml.sax.helpers.AttributesImpl;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlFileInput;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlRadioButtonInput;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
import com.gargoylesoftware.htmlunit.html.InputElementFactory;
import com.gargoylesoftware.htmlunit.html.impl.SelectableTextInput;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClasses;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxSetter;
import com.gargoylesoftware.htmlunit.javascript.configuration.WebBrowser;
import com.gargoylesoftware.htmlunit.javascript.host.event.Event;
import com.gargoylesoftware.htmlunit.javascript.host.event.MouseEvent;
import com.gargoylesoftware.htmlunit.javascript.host.event.PointerEvent;
import com.gargoylesoftware.htmlunit.javascript.host.file.FileList;

import net.sourceforge.htmlunit.corejs.javascript.Context;
import net.sourceforge.htmlunit.corejs.javascript.Undefined;

/**
 * The JavaScript object for {@code HTMLInputElement}.
 *
 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
 * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
 * @author Marc Guillemot
 * @author Chris Erskine
 * @author Ahmed Ashour
 * @author Daniel Gredler
 * @author Ronald Brill
 * @author Frank Danek
 */
@JsxClasses({ @JsxClass(domClass = HtmlInput.class, browsers = { @WebBrowser(CHROME), @WebBrowser(FF),
        @WebBrowser(IE), @WebBrowser(EDGE) }) })
public class HTMLInputElement extends FormField {

    /**
     * Creates an instance.
     */
    @JsxConstructor({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(EDGE) })
    public HTMLInputElement() {
    }

    /**
     * Returns the {@code type} property.
     * @return the {@code type} property
     */
    @JsxGetter
    public String getType() {
        return getDomNodeOrDie().getTypeAttribute().toLowerCase(Locale.ROOT);
    }

    /**
     * Sets the value of the attribute {@code type}.
     * Note: this replace the DOM node with a new one.
     * @param newType the new type to set
     */
    @JsxSetter
    public void setType(String newType) {
        HtmlInput input = getDomNodeOrDie();

        final String currentType = input.getAttribute("type");

        if (!currentType.equalsIgnoreCase(newType)) {
            if (newType != null && getBrowserVersion().hasFeature(JS_INPUT_SET_TYPE_LOWERCASE)) {
                newType = newType.toLowerCase(Locale.ROOT);
            }
            final AttributesImpl attributes = readAttributes(input);
            final int index = attributes.getIndex("type");
            if (index > -1) {
                attributes.setValue(index, newType);
            } else {
                attributes.addAttribute(null, "type", "type", null, newType);
            }

            // create a new one only if we have a new type
            if (ATTRIBUTE_NOT_DEFINED != currentType || !"text".equalsIgnoreCase(newType)) {
                final HtmlInput newInput = (HtmlInput) InputElementFactory.instance.createElement(input.getPage(),
                        "input", attributes);

                if (input.wasCreatedByJavascript()) {
                    newInput.markAsCreatedByJavascript();
                }

                if (input.getParentNode() == null) {
                    // the input hasn't yet been inserted into the DOM tree (likely has been
                    // created via document.createElement()), so simply replace it with the
                    // new Input instance created in the code above
                    input = newInput;
                } else {
                    input.getParentNode().replaceChild(newInput, input);
                }

                input.setScriptableObject(null);
                setDomNode(newInput, true);
            } else {
                super.setAttribute("type", newType);
            }
        }
    }

    /**
     * Sets the value of the JavaScript attribute {@code value}.
     *
     * @param newValue the new value
     */
    @JsxSetter
    @Override
    public void setValue(final Object newValue) {
        if (null == newValue) {
            getDomNodeOrDie().setAttribute("value", "");
            return;
        }

        String val = Context.toString(newValue);
        final BrowserVersion browserVersion = getBrowserVersion();
        if (StringUtils.isNotEmpty(val) && "file".equalsIgnoreCase(getType())) {
            if (browserVersion.hasFeature(JS_SELECT_FILE_THROWS)) {
                throw Context.reportRuntimeError(
                        "InvalidStateError: " + "Failed to set the 'value' property on 'HTMLInputElement'.");
            }
            return;
        }

        if (StringUtils.isBlank(val)) {
            if ("email".equalsIgnoreCase(getType())
                    && browserVersion.hasFeature(JS_INPUT_SET_VALUE_EMAIL_TRIMMED)) {
                val = "";
            } else if ("url".equalsIgnoreCase(getType())
                    && browserVersion.hasFeature(JS_INPUT_SET_VALUE_URL_TRIMMED)) {
                val = "";
            }
        }

        getDomNodeOrDie().setAttribute("value", val);
    }

    /**
     * Sets the checked property. Although this property is defined in Input it
     * doesn't make any sense for input's other than checkbox and radio. This
     * implementation does nothing. The implementations in Checkbox and Radio
     * actually do the work.
     *
     * @param checked True if this input should have the {@code checked} attribute set
     */
    @JsxSetter
    public void setChecked(final boolean checked) {
        getDomNodeOrDie().setChecked(checked);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public HtmlInput getDomNodeOrDie() {
        return (HtmlInput) super.getDomNodeOrDie();
    }

    /**
     * Returns the value of the checked property. Although this property is
     * defined in Input it doesn't make any sense for input's other than
     * checkbox and radio. This implementation does nothing. The
     * implementations in Checkbox and Radio actually do the work.
     *
     *@return the checked property
     */
    @JsxGetter
    public boolean getChecked() {
        return getDomNodeOrDie().isChecked();
    }

    /**
     * Select this element.
     */
    @JsxFunction
    public void select() {
        final HtmlInput input = getDomNodeOrDie();
        if (input instanceof HtmlTextInput) {
            ((HtmlTextInput) input).select();
        }
        // currently nothing for other input types
    }

    /**
     * Uses {@link #setType(String)} if attribute's name is type to
     * replace DOM node as well as long as we have subclasses of {@link HtmlInput}.
     * {@inheritDoc}
     */
    @Override
    public void setAttribute(final String name, final String value) {
        if ("type".equals(name)) {
            setType(value);
            return;
        }
        super.setAttribute(name, value);
    }

    /**
     * Returns the input's default value, used if the containing form gets reset.
     * @return the input's default value, used if the containing form gets reset
     * @see <a href="http://msdn.microsoft.com/en-us/library/ms533718.aspx">MSDN Documentation</a>
     */
    @JsxGetter
    public String getDefaultValue() {
        return getDomNodeOrDie().getDefaultValue();
    }

    /**
     * Sets the input's default value, used if the containing form gets reset.
     * @param defaultValue the input's default value, used if the containing form gets reset
     * @see <a href="http://msdn.microsoft.com/en-us/library/ms533718.aspx">MSDN Documentation</a>
     */
    @JsxSetter
    public void setDefaultValue(final String defaultValue) {
        getDomNodeOrDie().setDefaultValue(defaultValue);
    }

    /**
     * Returns the input's default checked value, used if the containing form gets reset.
     * @return the input's default checked value, used if the containing form gets reset
     * @see <a href="http://msdn.microsoft.com/en-us/library/ms533715.aspx">MSDN Documentation</a>
     */
    @JsxGetter
    public boolean getDefaultChecked() {
        return getDomNodeOrDie().isDefaultChecked();
    }

    /**
     * Sets the input's default checked value, used if the containing form gets reset.
     * @param defaultChecked the input's default checked value, used if the containing form gets reset
     * @see <a href="http://msdn.microsoft.com/en-us/library/ms533715.aspx">MSDN Documentation</a>
     */
    @JsxSetter
    public void setDefaultChecked(final boolean defaultChecked) {
        getDomNodeOrDie().setDefaultChecked(defaultChecked);
    }

    /**
     * Gets the value of {@code textLength} attribute.
     * @return the text length
     */
    @JsxGetter(@WebBrowser(FF))
    public int getTextLength() {
        return getValue().length();
    }

    /**
     * Gets the value of {@code selectionStart} attribute.
     * @return the selection start
     */
    @JsxGetter({ @WebBrowser(FF), @WebBrowser(IE), @WebBrowser(CHROME) })
    public int getSelectionStart() {
        return ((SelectableTextInput) getDomNodeOrDie()).getSelectionStart();
    }

    /**
     * Sets the value of {@code selectionStart} attribute.
     * @param start selection start
     */
    @JsxSetter({ @WebBrowser(FF), @WebBrowser(IE), @WebBrowser(CHROME) })
    public void setSelectionStart(final int start) {
        ((SelectableTextInput) getDomNodeOrDie()).setSelectionStart(start);
    }

    /**
     * Gets the value of {@code selectionEnd} attribute.
     * @return the selection end
     */
    @JsxGetter({ @WebBrowser(FF), @WebBrowser(IE), @WebBrowser(CHROME) })
    public int getSelectionEnd() {
        return ((SelectableTextInput) getDomNodeOrDie()).getSelectionEnd();
    }

    /**
     * Sets the value of {@code selectionEnd} attribute.
     * @param end selection end
     */
    @JsxSetter({ @WebBrowser(FF), @WebBrowser(IE), @WebBrowser(CHROME) })
    public void setSelectionEnd(final int end) {
        ((SelectableTextInput) getDomNodeOrDie()).setSelectionEnd(end);
    }

    /**
     * Gets the max length.
     * @return the max length
     */
    @JsxGetter
    public int getMaxLength() {
        final String attrValue = getDomNodeOrDie().getAttribute("maxLength");
        return NumberUtils.toInt(attrValue, -1);
    }

    /**
     * Sets the value of {@code maxLength} attribute.
     * @param length the new value
     */
    @JsxSetter
    public void setMaxLength(final int length) {
        getDomNodeOrDie().setMaxLength(length);
    }

    /**
     * Gets the {@code minLength}.
     * @return the {@code minLength}
     */
    @JsxGetter(@WebBrowser(CHROME))
    public int getMinLength() {
        final String attrValue = getDomNodeOrDie().getAttribute("minLength");
        return NumberUtils.toInt(attrValue, -1);
    }

    /**
     * Sets the value of {@code minLength} attribute.
     * @param length the new value
     */
    @JsxSetter(@WebBrowser(CHROME))
    public void setMinLength(final int length) {
        getDomNodeOrDie().setMinLength(length);
    }

    /**
     * Gets the {@code min} property.
     * @return the {@code min} property
     */
    @JsxGetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public String getMin() {
        return getDomNodeOrDie().getAttribute("min");
    }

    /**
     * Sets the {@code min} property.
     * @param min the {@code min} property
     */
    @JsxSetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public void setMin(final String min) {
        getDomNodeOrDie().setAttribute("min", min);
    }

    /**
     * Gets the {@code max} property.
     * @return the {@code max} property
     */
    @JsxGetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public String getMax() {
        return getDomNodeOrDie().getAttribute("max");
    }

    /**
     * Sets the {@code max} property.
     * @param max the {@code max} property
     */
    @JsxSetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public void setMax(final String max) {
        getDomNodeOrDie().setAttribute("max", max);
    }

    /**
     * Gets the value of {@code readOnly} attribute.
     * @return the readOnly attribute
     */
    @JsxGetter
    public boolean getReadOnly() {
        return getDomNodeOrDie().isReadOnly();
    }

    /**
     * Sets the value of {@code readOnly} attribute.
     * @param readOnly the new value
     */
    @JsxSetter
    public void setReadOnly(final boolean readOnly) {
        getDomNodeOrDie().setReadOnly(readOnly);
    }

    /**
     * Sets the selected portion of this input element.
     * @param start the index of the first character to select
     * @param end the index of the character after the selection
     */
    @JsxFunction({ @WebBrowser(FF), @WebBrowser(CHROME), @WebBrowser(IE) })
    public void setSelectionRange(final int start, final int end) {
        setSelectionStart(start);
        setSelectionEnd(end);
    }

    /**
     * Returns the value of the {@code alt} property.
     * @return the value of the {@code alt} property
     */
    @JsxGetter
    public String getAlt() {
        return getDomNodeOrDie().getAttribute("alt");
    }

    /**
     * Returns the value of the {@code alt} property.
     * @param alt the value
     */
    @JsxSetter
    public void setAlt(final String alt) {
        getDomNodeOrDie().setAttribute("alt", alt);
    }

    /**
     * Gets the {@code border} attribute.
     * @return the {@code border} attribute
     */
    @JsxGetter(@WebBrowser(IE))
    public String getBorder() {
        return getDomNodeOrDie().getAttribute("border");
    }

    /**
     * Sets the {@code border} attribute.
     * @param border the {@code border} attribute
     */
    @JsxSetter(@WebBrowser(IE))
    public void setBorder(final String border) {
        getDomNodeOrDie().setAttribute("border", border);
    }

    /**
     * Returns the value of the {@code align} property.
     * @return the value of the {@code align} property
     */
    @JsxGetter
    public String getAlign() {
        return getAlign(true);
    }

    /**
     * Sets the value of the {@code align} property.
     * @param align the value of the {@code align} property
     */
    @JsxSetter
    public void setAlign(final String align) {
        final boolean ignoreIfNoError = getBrowserVersion().hasFeature(JS_ALIGN_FOR_INPUT_IGNORES_VALUES);
        setAlign(align, ignoreIfNoError);
    }

    /**
     * Returns the value of the {@code src} attribute.
     * @return the value of the {@code src} attribute
     */
    @JsxGetter
    public String getSrc() {
        return getDomNodeOrDie().getSrcAttribute();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void click() throws IOException {
        final HtmlInput domNode = getDomNodeOrDie();
        final boolean originalState = domNode.isChecked();
        final Event event;
        if (getBrowserVersion().hasFeature(EVENT_ONCLICK_USES_POINTEREVENT)) {
            event = new PointerEvent(domNode, MouseEvent.TYPE_CLICK, false, false, false, MouseEvent.BUTTON_LEFT);
        } else {
            event = new MouseEvent(domNode, MouseEvent.TYPE_CLICK, false, false, false, MouseEvent.BUTTON_LEFT);
        }
        domNode.click(event);

        final boolean newState = domNode.isChecked();

        if (originalState != newState
                && (domNode instanceof HtmlRadioButtonInput || domNode instanceof HtmlCheckBoxInput)) {
            domNode.fireEvent(Event.TYPE_CHANGE);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected boolean isEndTagForbidden() {
        return true;
    }

    /**
     * Returns the {@code required} attribute.
     * @return the {@code required} attribute
     */
    @JsxGetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public boolean isRequired() {
        return getDomNodeOrDie().isRequired();
    }

    /**
     * Sets the {@code required} attribute.
     * @param required the new attribute value
     */
    @JsxSetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public void setRequired(final boolean required) {
        getDomNodeOrDie().setRequired(required);
    }

    /**
     * Returns the {@code size} attribute.
     * @return the {@code size} attribute
     */
    @JsxGetter
    public String getSize() {
        return getDomNodeOrDie().getSize();
    }

    /**
     * Sets the {@code size} attribute.
     * @param size the new {@code size} value
     */
    @JsxSetter
    public void setSize(final String size) {
        getDomNodeOrDie().setSize(size);
    }

    /**
     * Returns the {@code accept} attribute.
     * @return the {@code accept} attribute
     */
    @JsxGetter
    public String getAccept() {
        return getDomNodeOrDie().getAccept();
    }

    /**
     * Sets the {@code accept} attribute.
     * @param accept the new {@code accept} value
     */
    @JsxSetter
    public void setAccept(final String accept) {
        getDomNodeOrDie().setAccept(accept);
    }

    /**
     * Returns the {@code autocomplete} attribute.
     * @return the {@code autocomplete} attribute
     */
    @JsxGetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public String getAutocomplete() {
        return getDomNodeOrDie().getAutocomplete();
    }

    /**
     * Sets the {@code autocomplete} attribute.
     * @param autocomplete the new {@code autocomplete} value
     */
    @JsxSetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public void setAutocomplete(final String autocomplete) {
        getDomNodeOrDie().setAutocomplete(autocomplete);
    }

    /**
     * Returns the {@code files} property.
     * @return the {@code files} property
     */
    @JsxGetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public Object getFiles() {
        if (getDomNodeOrDie() instanceof HtmlFileInput) {
            final FileList list = new FileList(HtmlFileInput.splitFiles(getValue()));
            list.setParentScope(getParentScope());
            list.setPrototype(getPrototype(list.getClass()));
            return list;
        }
        if (getBrowserVersion().hasFeature(HTMLINPUT_FILES_UNDEFINED)) {
            return Undefined.instance;
        }
        return null;
    }

    /**
     * Returns the {@code placeholder} attribute.
     * @return the {@code placeholder} attribute
     */
    @JsxGetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public String getPlaceholder() {
        return getDomNodeOrDie().getPlaceholder();
    }

    /**
     * Sets the {@code placeholder} attribute.
     * @param placeholder the new {@code placeholder} value
     */
    @JsxSetter({ @WebBrowser(CHROME), @WebBrowser(FF), @WebBrowser(IE) })
    public void setPlaceholder(final String placeholder) {
        getDomNodeOrDie().setPlaceholder(placeholder);
    }

    /**
     * Returns the {@code width} property.
     * @return the {@code width} property
     */
    @Override
    @JsxGetter
    public int getWidth() {
        final String value = getDomNodeOrDie().getAttribute("width");
        final Integer intValue = HTMLCanvasElement.getValue(value);
        if (intValue != null) {
            return intValue;
        }
        return 0;
    }

    /**
     * Sets the {@code width} property.
     * @param width the {@code width} property
     */
    @JsxSetter
    public void setWidth(final int width) {
        getDomNodeOrDie().setAttribute("width", Integer.toString(width));
    }

    /**
     * Returns the {@code height} property.
     * @return the {@code height} property
     */
    @Override
    @JsxGetter
    public int getHeight() {
        final String value = getDomNodeOrDie().getAttribute("height");
        final Integer intValue = HTMLCanvasElement.getValue(value);
        if (intValue != null) {
            return intValue;
        }
        return 0;
    }

    /**
     * Sets the {@code height} property.
     * @param height the {@code height} property
     */
    @JsxSetter
    public void setHeight(final int height) {
        getDomNodeOrDie().setAttribute("height", Integer.toString(height));
    }

}