org.htmlunit.html.HtmlForm 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-2024 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
* https://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 org.htmlunit.html;
import static java.nio.charset.StandardCharsets.UTF_16;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.htmlunit.BrowserVersionFeatures.FORM_IGNORE_REL_NOREFERRER;
import static org.htmlunit.BrowserVersionFeatures.FORM_PARAMETRS_NOT_SUPPORTED_FOR_IMAGE;
import static org.htmlunit.BrowserVersionFeatures.FORM_SUBMISSION_DOWNLOWDS_ALSO_IF_ONLY_HASH_CHANGED;
import static org.htmlunit.BrowserVersionFeatures.FORM_SUBMISSION_HEADER_CACHE_CONTROL_MAX_AGE;
import static org.htmlunit.BrowserVersionFeatures.FORM_SUBMISSION_HEADER_CACHE_CONTROL_NO_CACHE;
import static org.htmlunit.BrowserVersionFeatures.FORM_SUBMISSION_HEADER_ORIGIN;
import static org.htmlunit.BrowserVersionFeatures.FORM_SUBMISSION_URL_WITHOUT_HASH;
import static org.htmlunit.BrowserVersionFeatures.JS_FORM_SUBMIT_FORCES_DOWNLOAD;
import static org.htmlunit.html.DisabledElement.ATTRIBUTE_DISABLED;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.htmlunit.BrowserVersion;
import org.htmlunit.ElementNotFoundException;
import org.htmlunit.FormEncodingType;
import org.htmlunit.HttpHeader;
import org.htmlunit.HttpMethod;
import org.htmlunit.Page;
import org.htmlunit.ScriptResult;
import org.htmlunit.SgmlPage;
import org.htmlunit.WebAssert;
import org.htmlunit.WebClient;
import org.htmlunit.WebRequest;
import org.htmlunit.WebWindow;
import org.htmlunit.httpclient.HttpClientConverter;
import org.htmlunit.javascript.host.event.Event;
import org.htmlunit.javascript.host.event.SubmitEvent;
import org.htmlunit.protocol.javascript.JavaScriptURLConnection;
import org.htmlunit.util.EncodingSniffer;
import org.htmlunit.util.NameValuePair;
import org.htmlunit.util.UrlUtils;
/**
* Wrapper for the HTML element "form".
*
* @author Mike Bowler
* @author David K. Taylor
* @author Brad Clarke
* @author Christian Sell
* @author Marc Guillemot
* @author George Murnock
* @author Kent Tong
* @author Ahmed Ashour
* @author Philip Graf
* @author Ronald Brill
* @author Frank Danek
* @author Anton Demydenko
*/
public class HtmlForm extends HtmlElement {
private static final Log LOG = LogFactory.getLog(HtmlForm.class);
/** The HTML tag represented by this element. */
public static final String TAG_NAME = "form";
/** The "novalidate" attribute name. */
private static final String ATTRIBUTE_NOVALIDATE = "novalidate";
/** The "formnovalidate" attribute name. */
public static final String ATTRIBUTE_FORMNOVALIDATE = "formnovalidate";
private static final HashSet SUBMITTABLE_ELEMENT_NAMES = new HashSet<>(Arrays.asList(HtmlInput.TAG_NAME,
HtmlButton.TAG_NAME, HtmlSelect.TAG_NAME, HtmlTextArea.TAG_NAME, HtmlIsIndex.TAG_NAME));
private static final Pattern SUBMIT_CHARSET_PATTERN = Pattern.compile("[ ,].*");
private boolean isPreventDefault_;
/**
* Creates an instance.
*
* @param qualifiedName the qualified name of the element type to instantiate
* @param htmlPage the page that contains this element
* @param attributes the initial attributes
*/
HtmlForm(final String qualifiedName, final SgmlPage htmlPage,
final Map attributes) {
super(qualifiedName, htmlPage, attributes);
}
/**
* INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.
*
* Submits this form to the server. If submitElement
is {@code null}, then
* the submission is treated as if it was triggered by JavaScript, and the onsubmit
* handler will not be executed.
*
* IMPORTANT: Using this method directly is not the preferred way of submitting forms.
* Most consumers should emulate the user's actions instead, probably by using something like
* {@link HtmlElement#click()} or {@link HtmlElement#dblClick()}.
*
* @param submitElement the element that caused the submit to occur
*/
public void submit(final SubmittableElement submitElement) {
final HtmlPage htmlPage = (HtmlPage) getPage();
final WebClient webClient = htmlPage.getWebClient();
if (webClient.isJavaScriptEnabled()) {
if (submitElement != null) {
isPreventDefault_ = false;
boolean validate = true;
if (submitElement instanceof HtmlSubmitInput
&& ((HtmlSubmitInput) submitElement).isFormNoValidate()) {
validate = false;
}
else if (submitElement instanceof HtmlButton) {
final HtmlButton htmlButton = (HtmlButton) submitElement;
if ("submit".equalsIgnoreCase(htmlButton.getType())
&& htmlButton.isFormNoValidate()) {
validate = false;
}
}
if (validate
&& getAttributeDirect(ATTRIBUTE_NOVALIDATE) != ATTRIBUTE_NOT_DEFINED) {
validate = false;
}
if (validate && !areChildrenValid()) {
return;
}
final ScriptResult scriptResult = fireEvent(new SubmitEvent(this,
((HtmlElement) submitElement).getScriptableObject()));
if (isPreventDefault_) {
// null means 'nothing executed'
if (scriptResult == null) {
return;
}
return;
}
}
final String action = getActionAttribute().trim();
if (StringUtils.startsWithIgnoreCase(action, JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
htmlPage.executeJavaScript(action, "Form action", getStartLineNumber());
return;
}
}
else {
if (StringUtils.startsWithIgnoreCase(getActionAttribute(), JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
// The action is JavaScript but JavaScript isn't enabled.
return;
}
}
// html5 attribute's support
if (submitElement != null) {
updateHtml5Attributes(submitElement);
}
// dialog support
final String methodAttribute = getMethodAttribute();
if ("dialog".equalsIgnoreCase(methodAttribute)) {
// find parent dialog
final HtmlElement dialog = getEnclosingElement("dialog");
if (dialog != null) {
((HtmlDialog) dialog).close("");
}
return;
}
final WebRequest request = getWebRequest(submitElement);
final String target = htmlPage.getResolvedTarget(getTargetAttribute());
final WebWindow webWindow = htmlPage.getEnclosingWindow();
final boolean forceDownload = webClient.getBrowserVersion().hasFeature(JS_FORM_SUBMIT_FORCES_DOWNLOAD);
// Calling form.submit() twice forces double download.
final boolean checkHash =
!webClient.getBrowserVersion().hasFeature(FORM_SUBMISSION_DOWNLOWDS_ALSO_IF_ONLY_HASH_CHANGED);
webClient.download(webWindow, target, request, checkHash, forceDownload, false, "JS form.submit()");
}
/**
* Check if element which cause submit contains new html5 attributes
* (formaction, formmethod, formtarget, formenctype)
* and override existing values
* @param submitElement the element to update
*/
private void updateHtml5Attributes(final SubmittableElement submitElement) {
if (submitElement instanceof HtmlElement) {
final HtmlElement element = (HtmlElement) submitElement;
final String type = element.getAttributeDirect(TYPE_ATTRIBUTE);
boolean typeImage = false;
final boolean isInput = HtmlInput.TAG_NAME.equals(element.getTagName());
if (isInput) {
typeImage = "image".equalsIgnoreCase(type);
}
// IE does not support formxxx attributes for input with 'image' types
final BrowserVersion browser = getPage().getWebClient().getBrowserVersion();
if (browser.hasFeature(FORM_PARAMETRS_NOT_SUPPORTED_FOR_IMAGE) && typeImage) {
return;
}
// could be excessive validation but support of html5 fromxxx
// attributes available for:
// - input with 'submit' and 'image' types
// - button with 'submit' or without type
final boolean typeSubmit = "submit".equalsIgnoreCase(type);
if (isInput && !typeSubmit && !typeImage) {
return;
}
else if (HtmlButton.TAG_NAME.equals(element.getTagName())
&& !"submit".equals(((HtmlButton) element).getType())) {
return;
}
final String formaction = element.getAttributeDirect("formaction");
if (DomElement.ATTRIBUTE_NOT_DEFINED != formaction) {
setActionAttribute(formaction);
}
final String formmethod = element.getAttributeDirect("formmethod");
if (DomElement.ATTRIBUTE_NOT_DEFINED != formmethod) {
setMethodAttribute(formmethod);
}
final String formtarget = element.getAttributeDirect("formtarget");
if (DomElement.ATTRIBUTE_NOT_DEFINED != formtarget) {
setTargetAttribute(formtarget);
}
final String formenctype = element.getAttributeDirect("formenctype");
if (DomElement.ATTRIBUTE_NOT_DEFINED != formenctype) {
setEnctypeAttribute(formenctype);
}
}
}
private boolean areChildrenValid() {
boolean valid = true;
for (final HtmlElement element : getElements()) {
if (element instanceof HtmlInput && !element.isValid()) {
if (LOG.isInfoEnabled()) {
LOG.info("Form validation failed; element '" + element + "' was not valid. Submit cancelled.");
}
valid = false;
break;
}
}
return valid;
}
/**
* INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.
*
* Gets the request for a submission of this form with the specified SubmittableElement.
* @param submitElement the element that caused the submit to occur
* @return the request
*/
public WebRequest getWebRequest(final SubmittableElement submitElement) {
final HtmlPage htmlPage = (HtmlPage) getPage();
final List parameters = getParameterListForSubmit(submitElement);
final HttpMethod method;
final String methodAttribute = getMethodAttribute();
if ("post".equalsIgnoreCase(methodAttribute)) {
method = HttpMethod.POST;
}
else {
if (!"get".equalsIgnoreCase(methodAttribute) && StringUtils.isNotBlank(methodAttribute)) {
notifyIncorrectness("Incorrect submit method >" + getMethodAttribute() + "<. Using >GET<.");
}
method = HttpMethod.GET;
}
final BrowserVersion browser = getPage().getWebClient().getBrowserVersion();
String actionUrl = getActionAttribute();
String anchor = null;
String queryFormFields = "";
Charset enc = getSubmitCharset();
if (UTF_16 == enc) {
enc = UTF_8;
}
if (HttpMethod.GET == method) {
if (actionUrl.contains("#")) {
anchor = StringUtils.substringAfter(actionUrl, "#");
}
queryFormFields = HttpClientConverter.toQueryFormFields(parameters, enc);
// action may already contain some query parameters: they have to be removed
actionUrl = StringUtils.substringBefore(actionUrl, "#");
actionUrl = StringUtils.substringBefore(actionUrl, "?");
parameters.clear(); // parameters have been added to query
}
URL url;
try {
if (actionUrl.isEmpty()) {
url = WebClient.expandUrl(htmlPage.getUrl(), actionUrl);
}
else {
url = htmlPage.getFullyQualifiedUrl(actionUrl);
}
if (!queryFormFields.isEmpty()) {
url = UrlUtils.getUrlWithNewQuery(url, queryFormFields);
}
if (HttpMethod.GET == method && browser.hasFeature(FORM_SUBMISSION_URL_WITHOUT_HASH)
&& UrlUtils.URL_ABOUT_BLANK != url) {
url = UrlUtils.getUrlWithNewRef(url, null);
}
else if (HttpMethod.POST == method
&& browser.hasFeature(FORM_SUBMISSION_URL_WITHOUT_HASH)
&& UrlUtils.URL_ABOUT_BLANK != url
&& StringUtils.isEmpty(actionUrl)) {
url = UrlUtils.getUrlWithNewRef(url, null);
}
else if (anchor != null
&& UrlUtils.URL_ABOUT_BLANK != url) {
url = UrlUtils.getUrlWithNewRef(url, anchor);
}
}
catch (final MalformedURLException e) {
throw new IllegalArgumentException("Not a valid url: " + actionUrl, e);
}
final WebRequest request = new WebRequest(url, browser.getHtmlAcceptHeader(),
browser.getAcceptEncodingHeader());
request.setHttpMethod(method);
request.setRequestParameters(parameters);
if (HttpMethod.POST == method) {
request.setEncodingType(FormEncodingType.getInstance(getEnctypeAttribute()));
}
request.setCharset(enc);
// forms are ignoring the rel='noreferrer'
if (browser.hasFeature(FORM_IGNORE_REL_NOREFERRER)
|| !relContainsNoreferrer()) {
request.setRefererlHeader(htmlPage.getUrl());
}
if (HttpMethod.POST == method
&& browser.hasFeature(FORM_SUBMISSION_HEADER_ORIGIN)) {
try {
request.setAdditionalHeader(HttpHeader.ORIGIN,
UrlUtils.getUrlWithProtocolAndAuthority(htmlPage.getUrl()).toExternalForm());
}
catch (final MalformedURLException e) {
if (LOG.isWarnEnabled()) {
LOG.info("Invalid origin url '" + htmlPage.getUrl() + "'");
}
}
}
if (HttpMethod.POST == method) {
if (browser.hasFeature(FORM_SUBMISSION_HEADER_CACHE_CONTROL_MAX_AGE)) {
request.setAdditionalHeader(HttpHeader.CACHE_CONTROL, "max-age=0");
}
if (browser.hasFeature(FORM_SUBMISSION_HEADER_CACHE_CONTROL_NO_CACHE)) {
request.setAdditionalHeader(HttpHeader.CACHE_CONTROL, "no-cache");
}
}
return request;
}
private boolean relContainsNoreferrer() {
String rel = getRelAttribute();
if (rel != null) {
rel = rel.toLowerCase(Locale.ROOT);
return ArrayUtils.contains(org.htmlunit.util.StringUtils.splitAtBlank(rel), "noreferrer");
}
return false;
}
/**
* Returns the charset to use for the form submission. This is the first one
* from the list provided in {@link #getAcceptCharsetAttribute()} if any
* or the page's charset else
* @return the charset to use for the form submission
*/
private Charset getSubmitCharset() {
String charset = getAcceptCharsetAttribute();
if (!charset.isEmpty()) {
charset = charset.trim();
return EncodingSniffer.toCharset(
SUBMIT_CHARSET_PATTERN.matcher(charset).replaceAll("").toUpperCase(Locale.ROOT));
}
return getPage().getCharset();
}
/**
* INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.
*
* Returns a list of {@link NameValuePair}s that represent the data that will be
* sent to the server when this form is submitted. This is primarily intended to aid
* debugging.
*
* @param submitElement the element used to submit the form, or {@code null} if the
* form was submitted by JavaScript
* @return the list of {@link NameValuePair}s that represent that data that will be sent
* to the server when this form is submitted
*/
public List getParameterListForSubmit(final SubmittableElement submitElement) {
final Collection submittableElements = getSubmittableElements(submitElement);
final List parameterList = new ArrayList<>(submittableElements.size());
for (final SubmittableElement element : submittableElements) {
parameterList.addAll(Arrays.asList(element.getSubmitNameValuePairs()));
}
return parameterList;
}
/**
* Resets this form to its initial values, returning the page contained by this form's window after the
* reset. Note that the returned page may or may not be the same as the original page, based on JavaScript
* event handlers, etc.
*
* @return the page contained by this form's window after the reset
*/
public Page reset() {
final SgmlPage htmlPage = getPage();
final ScriptResult scriptResult = fireEvent(Event.TYPE_RESET);
if (ScriptResult.isFalse(scriptResult)) {
return htmlPage.getWebClient().getCurrentWindow().getEnclosedPage();
}
for (final HtmlElement next : getHtmlElementDescendants()) {
if (next instanceof SubmittableElement) {
((SubmittableElement) next).reset();
}
}
return htmlPage;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isValid() {
for (final HtmlElement element : getElements()) {
if (!element.isValid()) {
return false;
}
}
return super.isValid();
}
/**
* Returns a collection of elements that represent all the "submittable" elements in this form,
* assuming that the specified element is used to submit the form.
*
* @param submitElement the element used to submit the form, or {@code null} if the
* form is submitted by JavaScript
* @return a collection of elements that represent all the "submittable" elements in this form
*/
Collection getSubmittableElements(final SubmittableElement submitElement) {
final List submittableElements = new ArrayList<>();
for (final HtmlElement element : getElements()) {
if (isSubmittable(element, submitElement)) {
submittableElements.add((SubmittableElement) element);
}
}
return submittableElements;
}
private static boolean isValidForSubmission(final HtmlElement element, final SubmittableElement submitElement) {
final String tagName = element.getTagName();
if (!SUBMITTABLE_ELEMENT_NAMES.contains(tagName)) {
return false;
}
if (element.hasAttribute(ATTRIBUTE_DISABLED)) {
return false;
}
// clicked input type="image" is submitted even if it hasn't a name
if (element == submitElement && element instanceof HtmlImageInput) {
return true;
}
if (!HtmlIsIndex.TAG_NAME.equals(tagName) && !element.hasAttribute(NAME_ATTRIBUTE)) {
return false;
}
if (!HtmlIsIndex.TAG_NAME.equals(tagName) && "".equals(element.getAttributeDirect(NAME_ATTRIBUTE))) {
return false;
}
if (element instanceof HtmlInput) {
final HtmlInput input = (HtmlInput) element;
if (input.isCheckable()) {
return ((HtmlInput) element).isChecked();
}
}
if (HtmlSelect.TAG_NAME.equals(tagName)) {
return ((HtmlSelect) element).isValidForSubmission();
}
return true;
}
/**
* Returns {@code true} if the specified element gets submitted when this form is submitted,
* assuming that the form is submitted using the specified submit element.
*
* @param element the element to check
* @param submitElement the element used to submit the form, or {@code null} if the form is
* submitted by JavaScript
* @return {@code true} if the specified element gets submitted when this form is submitted
*/
private static boolean isSubmittable(final HtmlElement element, final SubmittableElement submitElement) {
if (!isValidForSubmission(element, submitElement)) {
return false;
}
// The one submit button that was clicked can be submitted but no other ones
if (element == submitElement) {
return true;
}
if (element instanceof HtmlInput) {
final HtmlInput input = (HtmlInput) element;
if (!input.isSubmitable()) {
return false;
}
}
return !HtmlButton.TAG_NAME.equals(element.getTagName());
}
/**
* Returns all input elements which are members of this form and have the specified name.
*
* @param name the input name to search for
* @return all input elements which are members of this form and have the specified name
*/
public List getInputsByName(final String name) {
return getFormElementsByAttribute(HtmlInput.TAG_NAME, NAME_ATTRIBUTE, name);
}
/**
* Same as {@link #getElementsByAttribute(String, String, String)} but
* ignoring elements that are contained in a nested form.
*/
@SuppressWarnings("unchecked")
private List getFormElementsByAttribute(
final String elementName,
final String attributeName,
final String attributeValue) {
final List list = new ArrayList<>();
final String lowerCaseTagName = elementName.toLowerCase(Locale.ROOT);
for (final HtmlElement element : getElements()) {
if (element.getTagName().equals(lowerCaseTagName)) {
final String attValue = element.getAttribute(attributeName);
if (attValue.equals(attributeValue)) {
list.add((E) element);
}
}
}
return list;
}
/**
* @return returns a list of all form controls contained in the <form> element or referenced by formId
* but ignoring elements that are contained in a nested form
*/
public List getElements() {
final List elements = new ArrayList<>();
for (final HtmlElement element : getPage().getDocumentElement().getHtmlElementDescendants()) {
if (SUBMITTABLE_ELEMENT_NAMES.contains(element.getTagName())
&& element.getEnclosingForm() == this) {
elements.add(element);
}
}
return elements;
}
/**
* Returns the first input element which is a member of this form and has the specified name.
*
* @param name the input name to search for
* @param the input type
* @return the first input element which is a member of this form and has the specified name
* @throws ElementNotFoundException if there is not input in this form with the specified name
*/
@SuppressWarnings("unchecked")
public final I getInputByName(final String name) throws ElementNotFoundException {
final List inputs = getInputsByName(name);
if (inputs.isEmpty()) {
throw new ElementNotFoundException(HtmlInput.TAG_NAME, NAME_ATTRIBUTE, name);
}
return (I) inputs.get(0);
}
/**
* Returns all the {@link HtmlSelect} elements in this form that have the specified name.
*
* @param name the name to search for
* @return all the {@link HtmlSelect} elements in this form that have the specified name
*/
public List getSelectsByName(final String name) {
return getFormElementsByAttribute(HtmlSelect.TAG_NAME, NAME_ATTRIBUTE, name);
}
/**
* Returns the first {@link HtmlSelect} element in this form that has the specified name.
*
* @param name the name to search for
* @return the first {@link HtmlSelect} element in this form that has the specified name
* @throws ElementNotFoundException if this form does not contain a {@link HtmlSelect}
* element with the specified name
*/
public HtmlSelect getSelectByName(final String name) throws ElementNotFoundException {
final List list = getSelectsByName(name);
if (list.isEmpty()) {
throw new ElementNotFoundException(HtmlSelect.TAG_NAME, NAME_ATTRIBUTE, name);
}
return list.get(0);
}
/**
* Returns all the {@link HtmlButton} elements in this form that have the specified name.
*
* @param name the name to search for
* @return all the {@link HtmlButton} elements in this form that have the specified name
*/
public List getButtonsByName(final String name) {
return getFormElementsByAttribute(HtmlButton.TAG_NAME, NAME_ATTRIBUTE, name);
}
/**
* Returns the first {@link HtmlButton} element in this form that has the specified name.
*
* @param name the name to search for
* @return the first {@link HtmlButton} element in this form that has the specified name
* @throws ElementNotFoundException if this form does not contain a {@link HtmlButton}
* element with the specified name
*/
public HtmlButton getButtonByName(final String name) throws ElementNotFoundException {
final List list = getButtonsByName(name);
if (list.isEmpty()) {
throw new ElementNotFoundException(HtmlButton.TAG_NAME, NAME_ATTRIBUTE, name);
}
return list.get(0);
}
/**
* Returns all the {@link HtmlTextArea} elements in this form that have the specified name.
*
* @param name the name to search for
* @return all the {@link HtmlTextArea} elements in this form that have the specified name
*/
public List getTextAreasByName(final String name) {
return getFormElementsByAttribute(HtmlTextArea.TAG_NAME, NAME_ATTRIBUTE, name);
}
/**
* Returns the first {@link HtmlTextArea} element in this form that has the specified name.
*
* @param name the name to search for
* @return the first {@link HtmlTextArea} element in this form that has the specified name
* @throws ElementNotFoundException if this form does not contain a {@link HtmlTextArea}
* element with the specified name
*/
public HtmlTextArea getTextAreaByName(final String name) throws ElementNotFoundException {
final List list = getTextAreasByName(name);
if (list.isEmpty()) {
throw new ElementNotFoundException(HtmlTextArea.TAG_NAME, NAME_ATTRIBUTE, name);
}
return list.get(0);
}
/**
* Returns all the {@link HtmlRadioButtonInput} elements in this form that have the specified name.
*
* @param name the name to search for
* @return all the {@link HtmlRadioButtonInput} elements in this form that have the specified name
*/
public List getRadioButtonsByName(final String name) {
WebAssert.notNull("name", name);
final List results = new ArrayList<>();
for (final HtmlElement element : getInputsByName(name)) {
if (element instanceof HtmlRadioButtonInput) {
results.add((HtmlRadioButtonInput) element);
}
}
return results;
}
/**
* Selects the specified radio button in the form. Only a radio button that is actually contained
* in the form can be selected.
*
* @param radioButtonInput the radio button to select
*/
void setCheckedRadioButton(final HtmlRadioButtonInput radioButtonInput) {
if (radioButtonInput.getEnclosingForm() == null) {
throw new IllegalArgumentException("HtmlRadioButtonInput is not child of this HtmlForm");
}
final List radios = getRadioButtonsByName(radioButtonInput.getNameAttribute());
for (final HtmlRadioButtonInput input : radios) {
input.setCheckedInternal(input == radioButtonInput);
}
}
/**
* Returns the first checked radio button with the specified name. If none of
* the radio buttons by that name are checked, this method returns {@code null}.
*
* @param name the name of the radio button
* @return the first checked radio button with the specified name
*/
public HtmlRadioButtonInput getCheckedRadioButton(final String name) {
WebAssert.notNull("name", name);
for (final HtmlRadioButtonInput input : getRadioButtonsByName(name)) {
if (input.isChecked()) {
return input;
}
}
return null;
}
/**
* Returns the value of the attribute {@code action}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @return the value of the attribute {@code action} or an empty string if that attribute isn't defined
*/
public final String getActionAttribute() {
return getAttributeDirect("action");
}
/**
* Sets the value of the attribute {@code action}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @param action the value of the attribute {@code action}
*/
public final void setActionAttribute(final String action) {
setAttribute("action", action);
}
/**
* Returns the value of the attribute {@code method}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @return the value of the attribute {@code method} or an empty string if that attribute isn't defined
*/
public final String getMethodAttribute() {
return getAttributeDirect("method");
}
/**
* Sets the value of the attribute {@code method}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @param method the value of the attribute {@code method}
*/
public final void setMethodAttribute(final String method) {
setAttribute("method", method);
}
/**
* 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_ATTRIBUTE);
}
/**
* Sets the value of the attribute {@code name}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @param name the value of the attribute {@code name}
*/
public final void setNameAttribute(final String name) {
setAttribute(NAME_ATTRIBUTE, name);
}
/**
* Returns the value of the attribute {@code enctype}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute. "Enctype" is the encoding type
* used when submitting a form back to the server.
*
* @return the value of the attribute {@code enctype} or an empty string if that attribute isn't defined
*/
public final String getEnctypeAttribute() {
return getAttributeDirect("enctype");
}
/**
* Sets the value of the attribute {@code enctype}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute. "Enctype" is the encoding type
* used when submitting a form back to the server.
*
* @param encoding the value of the attribute {@code enctype}
*/
public final void setEnctypeAttribute(final String encoding) {
setAttribute("enctype", encoding);
}
/**
* Returns the value of the attribute {@code onsubmit}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @return the value of the attribute {@code onsubmit} or an empty string if that attribute isn't defined
*/
public final String getOnSubmitAttribute() {
return getAttributeDirect("onsubmit");
}
/**
* Returns the value of the attribute {@code onreset}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @return the value of the attribute {@code onreset} or an empty string if that attribute isn't defined
*/
public final String getOnResetAttribute() {
return getAttributeDirect("onreset");
}
/**
* 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 accept-charset}. Refer to the
* HTML 4.01 documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code accept-charset} or an empty string if that attribute isn't defined
*/
public final String getAcceptCharsetAttribute() {
return getAttribute("accept-charset");
}
/**
* Returns the value of the attribute {@code target}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @return the value of the attribute {@code target} or an empty string if that attribute isn't defined
*/
public final String getTargetAttribute() {
return getAttributeDirect("target");
}
/**
* Sets the value of the attribute {@code target}. Refer to the HTML 4.01 documentation for
* details on the use of this attribute.
*
* @param target the value of the attribute {@code target}
*/
public final void setTargetAttribute(final String target) {
setAttribute("target", target);
}
/**
* Returns the value of the attribute {@code rel}. Refer to the
* HTML 4.01
* documentation for details on the use of this attribute.
*
* @return the value of the attribute {@code rel} or an empty string if that attribute isn't defined
*/
public final String getRelAttribute() {
return getAttributeDirect("rel");
}
/**
* Returns the first input in this form with the specified value.
* @param value the value to search for
* @param the input type
* @return the first input in this form with the specified value
* @throws ElementNotFoundException if this form does not contain any inputs with the specified value
*/
@SuppressWarnings("unchecked")
public I getInputByValue(final String value) throws ElementNotFoundException {
final List list = getInputsByValue(value);
if (list.isEmpty()) {
throw new ElementNotFoundException(HtmlInput.TAG_NAME, VALUE_ATTRIBUTE, value);
}
return (I) list.get(0);
}
/**
* Returns all the inputs in this form with the specified value.
* @param value the value to search for
* @return all the inputs in this form with the specified value
*/
public List getInputsByValue(final String value) {
final List results = new ArrayList<>();
for (final HtmlElement element : getElements()) {
if (element instanceof HtmlInput
&& Objects.equals(((HtmlInput) element).getValue(), value)) {
results.add((HtmlInput) element);
}
}
return results;
}
/**
* {@inheritDoc}
*/
@Override
protected void preventDefault() {
isPreventDefault_ = true;
}
/**
* Browsers have problems with self closing form tags.
*/
@Override
protected boolean isEmptyXmlTagExpanded() {
return true;
}
/**
* @return the value of the attribute {@code novalidate} or an empty string if that attribute isn't defined
*/
public final boolean isNoValidate() {
return hasAttribute(ATTRIBUTE_NOVALIDATE);
}
/**
* Sets the value of the attribute {@code novalidate}.
*
* @param noValidate the value of the attribute {@code novalidate}
*/
public final void setNoValidate(final boolean noValidate) {
if (noValidate) {
setAttribute(ATTRIBUTE_NOVALIDATE, ATTRIBUTE_NOVALIDATE);
}
else {
removeAttribute(ATTRIBUTE_NOVALIDATE);
}
}
}