com.gargoylesoftware.htmlunit.html.HtmlInput Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xlt Show documentation
Show all versions of xlt Show documentation
XLT (Xceptance LoadTest) is an extensive load and performance test tool developed and maintained by Xceptance.
/*
* Copyright (c) 2002-2020 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.html;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.CSS_INPUT_DISPLAY_INLINE_BLOCK;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.CSS_INPUT_DISPLAY_RADIO_CHECKBOX_INLINE_BLOCK;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.EVENT_MOUSE_ON_DISABLED;
import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.HTMLINPUT_DOES_NOT_CLICK_SURROUNDING_ANCHOR;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import com.gargoylesoftware.htmlunit.HttpHeader;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.ScriptResult;
import com.gargoylesoftware.htmlunit.SgmlPage;
import com.gargoylesoftware.htmlunit.WebAssert;
import com.gargoylesoftware.htmlunit.javascript.AbstractJavaScriptEngine;
import com.gargoylesoftware.htmlunit.javascript.host.event.Event;
import com.gargoylesoftware.htmlunit.javascript.host.event.MouseEvent;
import com.gargoylesoftware.htmlunit.util.NameValuePair;
/**
* Wrapper for the HTML element "input".
*
* @author Mike Bowler
* @author David K. Taylor
* @author Christian Sell
* @author David D. Kilzer
* @author Marc Guillemot
* @author Daniel Gredler
* @author Ahmed Ashour
* @author Ronald Brill
* @author Frank Danek
*/
public abstract class HtmlInput extends HtmlElement implements DisabledElement, SubmittableElement,
FormFieldWithNameHistory {
/** The HTML tag represented by this element. */
public static final String TAG_NAME = "input";
private String defaultValue_;
private String originalName_;
private Collection newNames_ = Collections.emptySet();
private boolean createdByJavascript_;
private Object valueAtFocus_;
/**
* Creates an instance.
*
* @param page the page that contains this element
* @param attributes the initial attributes
*/
public HtmlInput(final SgmlPage page, final Map attributes) {
this(TAG_NAME, page, attributes);
}
/**
* Creates an instance.
*
* @param qualifiedName the qualified name of the element type to instantiate
* @param page the page that contains this element
* @param attributes the initial attributes
*/
public HtmlInput(final String qualifiedName, final SgmlPage page,
final Map attributes) {
super(qualifiedName, page, attributes);
defaultValue_ = getValueAttribute();
originalName_ = getNameAttribute();
}
/**
* {@inheritDoc}
*/
@Override
public void setAttribute(final String attributeName, final String attributeValue) {
if ("value".equals(attributeName)) {
setValueAttribute(attributeValue);
}
else {
super.setAttribute(attributeName, attributeValue);
}
}
/**
* Sets the content of the {@code value} attribute.
*
* @param newValue the new value
*/
public void setValueAttribute(final String newValue) {
WebAssert.notNull("newValue", newValue);
super.setAttribute("value", newValue);
}
/**
* {@inheritDoc}
*/
@Override
public NameValuePair[] getSubmitNameValuePairs() {
return new NameValuePair[]{new NameValuePair(getNameAttribute(), getValueAttribute())};
}
/**
* Returns the value of the attribute {@code type}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code type} or an empty string if that attribute isn't defined
*/
public final String getTypeAttribute() {
final String type = getAttributeDirect("type");
if (ATTRIBUTE_NOT_DEFINED == type) {
return "text";
}
return type;
}
/**
* Returns the value of the attribute {@code name}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code name} or an empty string if that attribute isn't defined
*/
public final String getNameAttribute() {
return getAttributeDirect("name");
}
/**
* Return the value of the attribute "value". Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code value} or an empty string if that attribute isn't defined
*/
public final String getValueAttribute() {
return getAttributeDirect("value");
}
/**
* Returns the value of the attribute {@code checked}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code checked} or an empty string if that attribute isn't defined
*/
public final String getCheckedAttribute() {
return getAttributeDirect("checked");
}
/**
* {@inheritDoc}
*/
@Override
public final String getDisabledAttribute() {
return getAttributeDirect("disabled");
}
/**
* {@inheritDoc}
*/
@Override
public final boolean isDisabled() {
return hasAttribute("disabled");
}
/**
* Returns the value of the attribute {@code readonly}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code readonly}
* or an empty string if that attribute isn't defined.
*/
public final String getReadOnlyAttribute() {
return getAttributeDirect("readonly");
}
/**
* Returns the value of the attribute {@code size}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code size}
* or an empty string if that attribute isn't defined.
*/
public final String getSizeAttribute() {
return getAttributeDirect("size");
}
/**
* Returns the value of the attribute {@code maxlength}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code maxlength}
* or an empty string if that attribute isn't defined.
*/
public final String getMaxLengthAttribute() {
return getAttribute("maxLength");
}
/**
* Gets the max length if defined, Integer.MAX_VALUE if none.
* @return the max length
*/
protected int getMaxLength() {
final String maxLength = getMaxLengthAttribute();
if (maxLength.isEmpty()) {
return Integer.MAX_VALUE;
}
try {
return Integer.parseInt(maxLength.trim());
}
catch (final NumberFormatException e) {
return Integer.MAX_VALUE;
}
}
/**
* Returns the value of the attribute {@code src}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code src}
* or an empty string if that attribute isn't defined.
*/
public final String getSrcAttribute() {
return getSrcAttributeNormalized();
}
/**
* Returns the value of the attribute {@code alt}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code alt}
* or an empty string if that attribute isn't defined.
*/
public final String getAltAttribute() {
return getAttributeDirect("alt");
}
/**
* Returns the value of the attribute {@code usemap}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code usemap}
* or an empty string if that attribute isn't defined.
*/
public final String getUseMapAttribute() {
return getAttributeDirect("usemap");
}
/**
* Returns the value of the attribute {@code tabindex}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code tabindex}
* or an empty string if that attribute isn't defined.
*/
public final String getTabIndexAttribute() {
return getAttributeDirect("tabindex");
}
/**
* Returns the value of the attribute {@code accesskey}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code accesskey}
* or an empty string if that attribute isn't defined.
*/
public final String getAccessKeyAttribute() {
return getAttributeDirect("accesskey");
}
/**
* Returns the value of the attribute {@code onfocus}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code onfocus}
* or an empty string if that attribute isn't defined.
*/
public final String getOnFocusAttribute() {
return getAttributeDirect("onfocus");
}
/**
* Returns the value of the attribute {@code onblur}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code onblur}
* or an empty string if that attribute isn't defined.
*/
public final String getOnBlurAttribute() {
return getAttributeDirect("onblur");
}
/**
* Returns the value of the attribute {@code onselect}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code onselect}
* or an empty string if that attribute isn't defined.
*/
public final String getOnSelectAttribute() {
return getAttributeDirect("onselect");
}
/**
* Returns the value of the attribute {@code onchange}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code onchange}
* or an empty string if that attribute isn't defined.
*/
public final String getOnChangeAttribute() {
return getAttributeDirect("onchange");
}
/**
* Returns the value of the attribute {@code accept}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code accept}
* or an empty string if that attribute isn't defined.
*/
public final String getAcceptAttribute() {
return getAttribute(HttpHeader.ACCEPT_LC);
}
/**
* Returns the value of the attribute {@code align}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code align}
* or an empty string if that attribute isn't defined.
*/
public final String getAlignAttribute() {
return getAttributeDirect("align");
}
/**
* {@inheritDoc}
* @see SubmittableElement#reset()
*/
@Override
public void reset() {
setValueAttribute(defaultValue_);
}
/**
* {@inheritDoc}
*
* @see SubmittableElement#setDefaultValue(String)
*/
@Override
public void setDefaultValue(final String defaultValue) {
setDefaultValue(defaultValue, true);
}
/**
* Sets the default value, optionally also modifying the current value.
* @param defaultValue the new default value
* @param modifyValue Whether or not to set the current value to the default value
*/
protected void setDefaultValue(final String defaultValue, final boolean modifyValue) {
final String oldAttributeValue = defaultValue_;
final HtmlAttributeChangeEvent event;
if (defaultValue_ == ATTRIBUTE_NOT_DEFINED) {
event = new HtmlAttributeChangeEvent(this, "value", defaultValue);
}
else {
event = new HtmlAttributeChangeEvent(this, "value", oldAttributeValue);
}
defaultValue_ = defaultValue;
if (modifyValue) {
if (this instanceof HtmlFileInput) {
super.setAttribute("value", defaultValue);
}
else {
setValueAttribute(defaultValue);
}
}
notifyAttributeChangeListeners(event, this, oldAttributeValue, true);
}
/**
* {@inheritDoc}
* @see SubmittableElement#getDefaultValue()
*/
@Override
public String getDefaultValue() {
return defaultValue_;
}
/**
* {@inheritDoc} The default implementation returns {@code false}; only checkboxes and
* radio buttons really care what the default checked value is.
* @see SubmittableElement#isDefaultChecked()
* @see HtmlRadioButtonInput#isDefaultChecked()
* @see HtmlCheckBoxInput#isDefaultChecked()
*/
@Override
public boolean isDefaultChecked() {
return false;
}
/**
* Sets the {@code checked} attribute, returning the page that occupies this input's window after setting
* the attribute. Note that the returned page may or may not be the original page, depending on
* the presence of JavaScript event handlers, etc.
*
* @param isChecked {@code true} if this element is to be selected
* @return the page that occupies this input's window after setting the attribute
*/
public Page setChecked(final boolean isChecked) {
// By default this returns the current page. Derived classes will override.
return getPage();
}
/**
* Sets the {@code readOnly} attribute.
*
* @param isReadOnly {@code true} if this element is read only
*/
public void setReadOnly(final boolean isReadOnly) {
if (isReadOnly) {
setAttribute("readOnly", "readOnly");
}
else {
removeAttribute("readOnly");
}
}
/**
* Returns {@code true} if this element is currently selected.
* @return {@code true} if this element is currently selected
*/
public boolean isChecked() {
return hasAttribute("checked");
}
/**
* Returns {@code true} if this element is read only.
* @return {@code true} if this element is read only
*/
public boolean isReadOnly() {
return hasAttribute("readOnly");
}
/**
* {@inheritDoc}
*/
@Override
protected boolean propagateClickStateUpdateToParent() {
return !hasFeature(HTMLINPUT_DOES_NOT_CLICK_SURROUNDING_ANCHOR);
}
/**
* {@inheritDoc}
*/
@Override
public boolean handles(final Event event) {
if (event instanceof MouseEvent && hasFeature(EVENT_MOUSE_ON_DISABLED)) {
return true;
}
return super.handles(event);
}
/**
* Executes the onchange script code for this element if this is appropriate.
* This means that the element must have an onchange script, script must be enabled
* and the change in the element must not have been triggered by a script.
*
* @param htmlElement the element that contains the onchange attribute
* @return the page that occupies this window after this method completes (may or
* may not be the same as the original page)
*/
static Page executeOnChangeHandlerIfAppropriate(final HtmlElement htmlElement) {
final SgmlPage page = htmlElement.getPage();
final AbstractJavaScriptEngine engine = htmlElement.getPage().getWebClient().getJavaScriptEngine();
if (engine.isScriptRunning()) {
return page;
}
final ScriptResult scriptResult = htmlElement.fireEvent(Event.TYPE_CHANGE);
if (page.getWebClient().containsWebWindow(page.getEnclosingWindow())) {
// may be itself or a newly loaded one
return page.getEnclosingWindow().getEnclosedPage();
}
if (scriptResult != null) {
// current window doesn't exist anymore
return page.getWebClient().getCurrentWindow().getEnclosedPage();
}
return page;
}
/**
* {@inheritDoc}
*/
@Override
protected void setAttributeNS(final String namespaceURI, final String qualifiedName, final String attributeValue,
final boolean notifyAttributeChangeListeners, final boolean notifyMutationObservers) {
if ("name".equals(qualifiedName)) {
if (newNames_.isEmpty()) {
newNames_ = new HashSet<>();
}
newNames_.add(attributeValue);
}
super.setAttributeNS(namespaceURI, qualifiedName, attributeValue, notifyAttributeChangeListeners,
notifyMutationObservers);
}
/**
* {@inheritDoc}
*/
@Override
public String getOriginalName() {
return originalName_;
}
/**
* {@inheritDoc}
*/
@Override
public Collection getNewNames() {
return newNames_;
}
/**
* INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.
*
* Marks this frame as created by javascript. This is needed to handle
* some special IE behavior.
*/
public void markAsCreatedByJavascript() {
createdByJavascript_ = true;
}
/**
* INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.
*
* Returns true if this frame was created by javascript. This is needed to handle
* some special IE behavior.
* @return true or false
*/
public boolean wasCreatedByJavascript() {
return createdByJavascript_;
}
/**
* {@inheritDoc}
*/
@Override
public final void focus() {
super.focus();
// store current value to trigger onchange when needed at focus lost
valueAtFocus_ = getInternalValue();
}
/**
* {@inheritDoc}
*/
@Override
public final void removeFocus() {
super.removeFocus();
if (valueAtFocus_ != null && !valueAtFocus_.equals(getInternalValue())) {
handleFocusLostValueChanged();
}
valueAtFocus_ = null;
}
void handleFocusLostValueChanged() {
executeOnChangeHandlerIfAppropriate(this);
}
Object getInternalValue() {
return getValueAttribute();
}
/**
* {@inheritDoc}
*/
@Override
public DisplayStyle getDefaultStyleDisplay() {
if (hasFeature(CSS_INPUT_DISPLAY_INLINE_BLOCK)) {
return DisplayStyle.INLINE_BLOCK;
}
if (hasFeature(CSS_INPUT_DISPLAY_RADIO_CHECKBOX_INLINE_BLOCK)) {
final String type = getTypeAttribute();
if ("radio".equals(type)
|| "checkbox".equals(type)) {
return DisplayStyle.INLINE_BLOCK;
}
}
return DisplayStyle.INLINE;
}
/**
* Returns the value of the {@code size} attribute.
*
* @return the value of the {@code size} attribute
*/
public String getSize() {
return getAttributeDirect("size");
}
/**
* Sets the {@code size} attribute.
*
* @param size the {@code size} attribute
*/
public void setSize(final String size) {
setAttribute("size", size);
}
/**
* Sets the {@code maxLength} attribute.
*
* @param maxLength the {@code maxLength} attribute
*/
public void setMaxLength(final int maxLength) {
setAttribute("maxLength", String.valueOf(maxLength));
}
/**
* Sets the {@code minLength} attribute.
*
* @param minLength the {@code minLength} attribute
*/
public void setMinLength(final int minLength) {
setAttribute("minLength", String.valueOf(minLength));
}
/**
* Returns the value of the {@code accept} attribute.
*
* @return the value of the {@code accept} attribute
*/
public String getAccept() {
return getAttribute(HttpHeader.ACCEPT_LC);
}
/**
* Sets the {@code accept} attribute.
*
* @param accept the {@code accept} attribute
*/
public void setAccept(final String accept) {
setAttribute(HttpHeader.ACCEPT_LC, accept);
}
/**
* Returns the value of the {@code autocomplete} attribute.
*
* @return the value of the {@code autocomplete} attribute
*/
public String getAutocomplete() {
return getAttributeDirect("autocomplete");
}
/**
* Sets the {@code autocomplete} attribute.
*
* @param autocomplete the {@code autocomplete} attribute
*/
public void setAutocomplete(final String autocomplete) {
setAttribute("autocomplete", autocomplete);
}
/**
* Returns the value of the {@code placeholder} attribute.
*
* @return the value of the {@code placeholder} attribute
*/
public String getPlaceholder() {
return getAttributeDirect("placeholder");
}
/**
* Sets the {@code placeholder} attribute.
*
* @param placeholder the {@code placeholder} attribute
*/
public void setPlaceholder(final String placeholder) {
setAttribute("placeholder", placeholder);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isRequiredSupported() {
return true;
}
/**
* {@inheritDoc}
*/
@Override
public DomNode cloneNode(final boolean deep) {
final HtmlInput newnode = (HtmlInput) super.cloneNode(deep);
newnode.newNames_ = new HashSet<>(newNames_);
return newnode;
}
}