All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gargoylesoftware.htmlunit.html.HtmlSelect Maven / Gradle / Ivy

Go to download

Vaadin is a web application framework for Rich Internet Applications (RIA). Vaadin enables easy development and maintenance of fast and secure rich web applications with a stunning look and feel and a wide browser support. It features a server-side architecture with the majority of the logic running on the server. Ajax technology is used at the browser-side to ensure a rich and interactive user experience.

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright (c) 2002-2011 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Node;

import com.gargoylesoftware.htmlunit.BrowserVersionFeatures;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.SgmlPage;
import com.gargoylesoftware.htmlunit.WebAssert;
import com.gargoylesoftware.htmlunit.util.NameValuePair;

/**
 * Wrapper for the HTML element "select".
 *
 * @version $Revision: 6283 $
 * @author Mike Bowler
 * @author Mike J. Bresnahan
 * @author David K. Taylor
 * @author Christian Sell
 * @author David D. Kilzer
 * @author Marc Guillemot
 * @author Daniel Gredler
 * @author Ahmed Ashour
 */
public class HtmlSelect extends HtmlElement implements DisabledElement, SubmittableElement, FormFieldWithNameHistory {

    /** The HTML tag represented by this element. */
    public static final String TAG_NAME = "select";

    private String originalName_;
    private Collection previousNames_ = Collections.emptySet();

    /**
     * Creates an instance.
     *
     * @param namespaceURI the URI that identifies an XML namespace
     * @param qualifiedName the qualified name of the element type to instantiate
     * @param page the page that contains this element
     * @param attributes the initial attributes
     */
    HtmlSelect(final String namespaceURI, final String qualifiedName, final SgmlPage page,
            final Map attributes) {
        super(namespaceURI, qualifiedName, page, attributes);
        originalName_ = getNameAttribute();
    }

    /**
     * If we were given an invalid size attribute, normalize it.
     * Then set a default selected option if none was specified and the size is 1 or less
     * and this isn't a multiple selection input.
     * @param postponed whether to use {@link com.gargoylesoftware.htmlunit.javascript.PostponedAction} or no
     */
    @Override
    protected void onAllChildrenAddedToPage(final boolean postponed) {
        // Fix the size if necessary.
        int size;
        try {
            size = Integer.parseInt(getSizeAttribute());
            if (size < 0) {
                removeAttribute("size");
                size = 0;
            }
        }
        catch (final NumberFormatException e) {
            removeAttribute("size");
            size = 0;
        }

        // Set a default selected option if necessary.
        if (getSelectedOptions().isEmpty() && size <= 1 && !isMultipleSelectEnabled()) {
            final List options = getOptions();
            if (!options.isEmpty()) {
                final HtmlOption first = options.get(0);
                first.setSelectedInternal(true);
            }
        }
    }

    /**
     * 

Returns all of the currently selected options. The following special * conditions can occur if the element is in single select mode:

*
    *
  • if multiple options are erroneously selected, the last one is returned
  • *
  • if no options are selected, the first one is returned
  • *
* * @return the currently selected options */ public List getSelectedOptions() { List result; if (isMultipleSelectEnabled()) { // Multiple selections possible. result = new ArrayList(); for (final HtmlElement element : getHtmlElementDescendants()) { if (element instanceof HtmlOption && ((HtmlOption) element).isSelected()) { result.add((HtmlOption) element); } } } else { // Only a single selection is possible. result = new ArrayList(1); HtmlOption lastSelected = null; for (final HtmlElement element : getHtmlElementDescendants()) { if (element instanceof HtmlOption) { final HtmlOption option = (HtmlOption) element; if (option.isSelected()) { lastSelected = option; } } } if (lastSelected != null) { result.add(lastSelected); } } return Collections.unmodifiableList(result); } /** * Returns all of the options in this select element. * @return all of the options in this select element */ public List getOptions() { return Collections.unmodifiableList(this.getHtmlElementsByTagName("option")); } /** * Returns the indexed option. * * @param index the index * @return the option specified by the index */ public HtmlOption getOption(final int index) { return this.getHtmlElementsByTagName("option").get(index); } /** * Returns the number of options. * @return the number of options */ public int getOptionSize() { return getHtmlElementsByTagName("option").size(); } /** * Remove options by reducing the "length" property. This has no * effect if the length is set to the same or greater. * @param newLength the new length property value */ public void setOptionSize(final int newLength) { final List elementList = getHtmlElementsByTagName("option"); for (int i = elementList.size() - 1; i >= newLength; i--) { elementList.get(i).remove(); } } /** * Remove an option at the given index. * @param index the index of the option to remove */ public void removeOption(final int index) { final ChildElementsIterator iterator = new ChildElementsIterator(); for (int i = 0; iterator.hasNext();) { final HtmlElement element = iterator.nextElement(); if (element instanceof HtmlOption) { if (i == index) { element.remove(); return; } i++; } } } /** * Replace an option at the given index with a new option. * @param index the index of the option to remove * @param newOption the new option to replace to indexed option */ public void replaceOption(final int index, final HtmlOption newOption) { final ChildElementsIterator iterator = new ChildElementsIterator(); for (int i = 0; iterator.hasNext();) { final HtmlElement element = iterator.nextElement(); if (element instanceof HtmlOption) { if (i == index) { element.replace(newOption); return; } i++; } } if (newOption.isSelected()) { setSelectedAttribute(newOption, true); } } /** * Add a new option at the end. * @param newOption the new option to add */ public void appendOption(final HtmlOption newOption) { appendChild(newOption); } /** * {@inheritDoc} */ @Override public DomNode appendChild(final Node node) { final DomNode response = super.appendChild(node); if (node instanceof HtmlOption) { final HtmlOption option = (HtmlOption) node; if (option.isSelected()) { doSelectOption(option, true); } } return response; } /** * Sets the "selected" state of the specified option. If this "select" element * is single-select, then calling this method will deselect all other options. * * Only options that are actually in the document may be selected. * * @param isSelected true if the option is to become selected * @param optionValue the value of the option that is to change * @param

the page type * @return the page contained in the current window as returned * by {@link com.gargoylesoftware.htmlunit.WebClient#getCurrentWindow()} */ @SuppressWarnings("unchecked") public

P setSelectedAttribute(final String optionValue, final boolean isSelected) { try { return (P) setSelectedAttribute(getOptionByValue(optionValue), isSelected); } catch (final ElementNotFoundException e) { if (getPage().getWebClient().getBrowserVersion() .hasFeature(BrowserVersionFeatures.SELECT_DESELECT_ALL_IF_SWITCHING_UNKNOWN)) { for (final HtmlOption o : getSelectedOptions()) { o.setSelected(false); } } return (P) getPage(); } } /** * Sets the "selected" state of the specified option. If this "select" element * is single-select, then calling this method will deselect all other options. * * Only options that are actually in the document may be selected. * * @param isSelected true if the option is to become selected * @param selectedOption the value of the option that is to change * @param

the page type * @return the page contained in the current window as returned * by {@link com.gargoylesoftware.htmlunit.WebClient#getCurrentWindow()} */ @SuppressWarnings("unchecked") public

P setSelectedAttribute(final HtmlOption selectedOption, final boolean isSelected) { return (P) setSelectedAttribute(selectedOption, isSelected, true); } /** * INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.
* * Sets the "selected" state of the specified option. If this "select" element * is single-select, then calling this method will deselect all other options. * * Only options that are actually in the document may be selected. * * @param isSelected true if the option is to become selected * @param selectedOption the value of the option that is to change * @param invokeOnFocus whether to set focus or no. * @param

the page type * @return the page contained in the current window as returned * by {@link com.gargoylesoftware.htmlunit.WebClient#getCurrentWindow()} */ @SuppressWarnings("unchecked") public

P setSelectedAttribute(final HtmlOption selectedOption, final boolean isSelected, final boolean invokeOnFocus) { if (isSelected && invokeOnFocus) { ((HtmlPage) getPage()).setFocusedElement(this); } final boolean changeSelectedState = (selectedOption.isSelected() != isSelected); if (changeSelectedState) { doSelectOption(selectedOption, isSelected); HtmlInput.executeOnChangeHandlerIfAppropriate(this); } return (P) getPage().getWebClient().getCurrentWindow().getEnclosedPage(); } private void doSelectOption(final HtmlOption selectedOption, final boolean isSelected) { // caution the HtmlOption may have been created from js and therefore the select now need // to "know" that it is selected if (isMultipleSelectEnabled()) { selectedOption.setSelectedInternal(isSelected); } else { for (final HtmlOption option : getOptions()) { option.setSelectedInternal(option == selectedOption && isSelected); } } } /** * {@inheritDoc} */ public NameValuePair[] getSubmitKeyValuePairs() { final String name = getNameAttribute(); final List selectedOptions = getSelectedOptions(); final NameValuePair[] pairs = new NameValuePair[selectedOptions.size()]; int i = 0; for (final HtmlOption option : selectedOptions) { pairs[i++] = new NameValuePair(name, option.getValueAttribute()); } return pairs; } /** * Indicates if this select is submittable * @return false if not */ boolean isValidForSubmission() { return getOptionSize() > 0; } /** * Returns the value of this element to what it was at the time the page was loaded. */ public void reset() { for (final HtmlOption option : getOptions()) { option.reset(); } } /** * {@inheritDoc} * @see SubmittableElement#setDefaultValue(String) */ public void setDefaultValue(final String defaultValue) { setSelectedAttribute(defaultValue, true); } /** * {@inheritDoc} * @see SubmittableElement#setDefaultValue(String) */ public String getDefaultValue() { final List options = getSelectedOptions(); if (options.size() > 0) { return options.get(0).getValueAttribute(); } return ""; } /** * {@inheritDoc} * This implementation is empty; only checkboxes and radio buttons * really care what the default checked value is. * @see SubmittableElement#setDefaultChecked(boolean) * @see HtmlRadioButtonInput#setDefaultChecked(boolean) * @see HtmlCheckBoxInput#setDefaultChecked(boolean) */ public void setDefaultChecked(final boolean defaultChecked) { // Empty. } /** * {@inheritDoc} * This implementation returns false; only checkboxes and * radio buttons really care what the default checked value is. * @see SubmittableElement#isDefaultChecked() * @see HtmlRadioButtonInput#isDefaultChecked() * @see HtmlCheckBoxInput#isDefaultChecked() */ public boolean isDefaultChecked() { return false; } /** * Returns true if this select is using "multiple select". * @return true if this select is using "multiple select" */ public boolean isMultipleSelectEnabled() { return getAttribute("multiple") != ATTRIBUTE_NOT_DEFINED; } /** * Returns the {@link HtmlOption} object that corresponds to the specified value. * * @param value the value to search by * @return the {@link HtmlOption} object that corresponds to the specified value * @exception ElementNotFoundException If a particular element could not be found in the DOM model */ public HtmlOption getOptionByValue(final String value) throws ElementNotFoundException { WebAssert.notNull("value", value); for (final HtmlOption option : getOptions()) { if (option.getValueAttribute().equals(value)) { return option; } } throw new ElementNotFoundException("option", "value", value); } /** * Returns the {@link HtmlOption} object that has the specified text. * * @param text the text to search by * @return the {@link HtmlOption} object that has the specified text * @exception ElementNotFoundException If a particular element could not be found in the DOM model */ public HtmlOption getOptionByText(final String text) throws ElementNotFoundException { WebAssert.notNull("text", text); for (final HtmlOption option : getOptions()) { if (option.getText().equals(text)) { return option; } } throw new ElementNotFoundException("option", "text", text); } /** * Returns a text representation of this element that represents what would * be visible to the user if this page was shown in a web browser. If the user * can only select one option at a time, this method returns the selected option. * If the user can select multiple options, this method returns all options. * * @return the element as text */ // we need to preserve this method as it is there since many versions with the above documentation. @Override public String asText() { final List options; if (isMultipleSelectEnabled()) { options = getOptions(); } else { options = getSelectedOptions(); } final StringBuilder buffer = new StringBuilder(); for (final Iterator i = options.iterator(); i.hasNext();) { final HtmlOption currentOption = i.next(); if (currentOption != null) { buffer.append(currentOption.asText()); } if (i.hasNext()) { buffer.append("\n"); } } return buffer.toString(); } /** * Returns the value of the attribute "name". Refer to the HTML 4.01 documentation for details on the use of this attribute. * * @return the value of the attribute "name" or an empty string if that attribute isn't defined */ public final String getNameAttribute() { return getAttribute("name"); } /** * Returns the value of the attribute "size". Refer to the HTML 4.01 documentation for * details on the use of this attribute. * * @return the value of the attribute "size" or an empty string if that attribute isn't defined */ public final String getSizeAttribute() { return getAttribute("size"); } /** * Returns the value of the attribute "multiple". Refer to the HTML 4.01 documentation for details on the use of this attribute. * * @return the value of the attribute "multiple" or an empty string if that attribute isn't defined */ public final String getMultipleAttribute() { return getAttribute("multiple"); } /** * {@inheritDoc} */ public final String getDisabledAttribute() { return getAttribute("disabled"); } /** * {@inheritDoc} */ public final boolean isDisabled() { return hasAttribute("disabled"); } /** * Returns the value of the attribute "tabindex". Refer to the HTML 4.01 documentation for details on the use of this attribute. * * @return the value of the attribute "tabindex" or an empty string if that attribute isn't defined */ public final String getTabIndexAttribute() { return getAttribute("tabindex"); } /** * Returns the value of the attribute "onfocus". Refer to the HTML 4.01 documentation for details on the use of this attribute. * * @return the value of the attribute "onfocus" or an empty string if that attribute isn't defined */ public final String getOnFocusAttribute() { return getAttribute("onfocus"); } /** * Returns the value of the attribute "onblur". Refer to the HTML 4.01 documentation for details on the use of this attribute. * * @return the value of the attribute "onblur" or an empty string if that attribute isn't defined */ public final String getOnBlurAttribute() { return getAttribute("onblur"); } /** * Returns the value of the attribute "onchange". Refer to the HTML 4.01 documentation for details on the use of this attribute. * * @return the value of the attribute "onchange" or an empty string if that attribute isn't defined */ public final String getOnChangeAttribute() { return getAttribute("onchange"); } /** * {@inheritDoc} */ @Override public void setAttributeNS(final String namespaceURI, final String qualifiedName, final String attributeValue) { if ("name".equals(qualifiedName)) { if (previousNames_.isEmpty()) { previousNames_ = new HashSet(); } previousNames_.add(attributeValue); } super.setAttributeNS(namespaceURI, qualifiedName, attributeValue); } /** * {@inheritDoc} */ public String getOriginalName() { return originalName_; } /** * {@inheritDoc} */ public Collection getPreviousNames() { return previousNames_; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy