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

org.htmlunit.html.HtmlTextArea Maven / Gradle / Ivy

Go to download

XLT (Xceptance LoadTest) is an extensive load and performance test tool developed and maintained by Xceptance.

The newest version!
/*
 * 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 org.htmlunit.BrowserVersionFeatures.EVENT_MOUSE_ON_DISABLED;
import static org.htmlunit.BrowserVersionFeatures.HTMLTEXTAREA_SET_DEFAULT_VALUE_UPDATES_VALUE;
import static org.htmlunit.BrowserVersionFeatures.HTMLTEXTAREA_USE_ALL_TEXT_CHILDREN;
import static org.htmlunit.BrowserVersionFeatures.HTMLTEXTAREA_WILL_VALIDATE_IGNORES_READONLY;
import static org.htmlunit.BrowserVersionFeatures.JS_INPUT_SET_VALUE_MOVE_SELECTION_TO_START;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.htmlunit.SgmlPage;
import org.htmlunit.html.impl.SelectableTextInput;
import org.htmlunit.html.impl.SelectableTextSelectionDelegate;
import org.htmlunit.javascript.host.event.Event;
import org.htmlunit.javascript.host.event.MouseEvent;
import org.htmlunit.util.NameValuePair;

/**
 * Wrapper for the HTML element "textarea".
 *
 * @author Mike Bowler
 * @author Barnaby Court
 * @author David K. Taylor
 * @author Christian Sell
 * @author David D. Kilzer
 * @author Marc Guillemot
 * @author Daniel Gredler
 * @author Ahmed Ashour
 * @author Sudhan Moghe
 * @author Amit Khanna
 * @author Ronald Brill
 * @author Frank Danek
 */
public class HtmlTextArea extends HtmlElement implements DisabledElement, SubmittableElement,
                LabelableElement, SelectableTextInput, FormFieldWithNameHistory, ValidatableElement {
    /** The HTML tag represented by this element. */
    public static final String TAG_NAME = "textarea";

    private String defaultValue_;
    private String valueAtFocus_;
    private final String originalName_;
    private Collection newNames_ = Collections.emptySet();
    private String customValidity_;

    private SelectableTextSelectionDelegate selectionDelegate_ = new SelectableTextSelectionDelegate(this);
    private DoTypeProcessor doTypeProcessor_ = new DoTypeProcessor(this);

    /**
     * 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
     */
    HtmlTextArea(final String qualifiedName, final SgmlPage page,
            final Map attributes) {
        super(qualifiedName, page, attributes);
        originalName_ = getNameAttribute();
    }

    /**
     * Initializes the default value if necessary. We cannot do it in the constructor
     * because the child node variable will not have been initialized yet. Must be called
     * from all methods that use the default value.
     */
    private void initDefaultValue() {
        if (defaultValue_ == null) {
            defaultValue_ = readValue();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean handles(final Event event) {
        if (event instanceof MouseEvent && hasFeature(EVENT_MOUSE_ON_DISABLED)) {
            return true;
        }

        return super.handles(event);
    }

    /**
     * Returns the value that would be displayed in the text area.
     *
     * @return the text
     */
    @Override
    public final String getText() {
        if (hasFeature(HTMLTEXTAREA_USE_ALL_TEXT_CHILDREN)) {
            return readValueIE();
        }
        return readValue();
    }

    private String readValue() {
        final StringBuilder builder = new StringBuilder();
        for (final DomNode node : getChildren()) {
            if (node instanceof DomText) {
                builder.append(((DomText) node).getData());
            }
        }
        // if content starts with new line, it is ignored (=> for the parser?)
        if (builder.length() != 0 && builder.charAt(0) == '\n') {
            builder.deleteCharAt(0);
        }
        return builder.toString();
    }

    private String readValueIE() {
        final StringBuilder builder = new StringBuilder();
        for (final DomNode node : getDescendants()) {
            if (node instanceof DomText) {
                builder.append(((DomText) node).getData());
            }
        }
        // if content starts with new line, it is ignored (=> for the parser?)
        if (builder.length() != 0 && builder.charAt(0) == '\n') {
            builder.deleteCharAt(0);
        }
        return builder.toString();
    }

    /**
     * Sets the new value of this text area.
     * 

* Note that this acts like 'pasting' the text, but to simulate characters entry * you should use {@link #type(String)}. * * @param newValue the new value */ @Override public final void setText(final String newValue) { setTextInternal(newValue); HtmlInput.executeOnChangeHandlerIfAppropriate(this); } private void setTextInternal(final String newValue) { initDefaultValue(); DomNode child = getFirstChild(); if (child == null) { final DomText newChild = new DomText(getPage(), newValue); appendChild(newChild); } else { if (hasFeature(HTMLTEXTAREA_USE_ALL_TEXT_CHILDREN)) { removeAllChildren(); final DomText newChild = new DomText(getPage(), newValue); appendChild(newChild); } else { DomNode next = child.getNextSibling(); while (next != null && !(next instanceof DomText)) { child = next; next = child.getNextSibling(); } if (next == null) { removeChild(child); final DomText newChild = new DomText(getPage(), newValue); appendChild(newChild); } else { ((DomText) next).setData(newValue); } } } int pos = 0; if (!hasFeature(JS_INPUT_SET_VALUE_MOVE_SELECTION_TO_START)) { pos = newValue.length(); } setSelectionStart(pos); setSelectionEnd(pos); } /** * {@inheritDoc} */ @Override public NameValuePair[] getSubmitNameValuePairs() { String text = getText(); text = text.replace("\r\n", "\n").replace("\n", "\r\n"); return new NameValuePair[]{new NameValuePair(getNameAttribute(), text)}; } /** * {@inheritDoc} * @see SubmittableElement#reset() */ @Override public void reset() { initDefaultValue(); setText(defaultValue_); } /** * {@inheritDoc} * @see SubmittableElement#setDefaultValue(String) */ @Override public void setDefaultValue(String defaultValue) { initDefaultValue(); if (defaultValue == null) { defaultValue = ""; } // for FF, if value is still default value, change value too if (hasFeature(HTMLTEXTAREA_SET_DEFAULT_VALUE_UPDATES_VALUE) && getText().equals(getDefaultValue())) { setTextInternal(defaultValue); } defaultValue_ = defaultValue; } /** * {@inheritDoc} * @see SubmittableElement#getDefaultValue() */ @Override public String getDefaultValue() { initDefaultValue(); return defaultValue_; } /** * {@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) */ @Override public void setDefaultChecked(final boolean defaultChecked) { // Empty. } /** * {@inheritDoc} This 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; } /** * 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(DomElement.NAME_ATTRIBUTE); } /** * Returns the value of the attribute {@code rows}. Refer to the * HTML 4.01 * documentation for details on the use of this attribute. * * @return the value of the attribute {@code rows} or an empty string if that attribute isn't defined */ public final String getRowsAttribute() { return getAttributeDirect("rows"); } /** * Returns the value of the attribute {@code cols}. Refer to the * HTML 4.01 * documentation for details on the use of this attribute. * * @return the value of the attribute {@code cols} or an empty string if that attribute isn't defined */ public final String getColumnsAttribute() { return getAttributeDirect("cols"); } /** * {@inheritDoc} */ @Override public final boolean isDisabled() { return hasAttribute(ATTRIBUTE_DISABLED); } /** * {@inheritDoc} */ @Override public final String getDisabledAttribute() { return getAttributeDirect(ATTRIBUTE_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 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"); } /** * {@inheritDoc} */ @Override public void select() { selectionDelegate_.select(); } /** * {@inheritDoc} */ @Override public String getSelectedText() { return selectionDelegate_.getSelectedText(); } /** * {@inheritDoc} */ @Override public int getSelectionStart() { return selectionDelegate_.getSelectionStart(); } /** * {@inheritDoc} */ @Override public void setSelectionStart(final int selectionStart) { selectionDelegate_.setSelectionStart(selectionStart); } /** * {@inheritDoc} */ @Override public int getSelectionEnd() { return selectionDelegate_.getSelectionEnd(); } /** * {@inheritDoc} */ @Override public void setSelectionEnd(final int selectionEnd) { selectionDelegate_.setSelectionEnd(selectionEnd); } /** * Recursively write the XML data for the node tree starting at node. * * @param indent white space to indent child nodes * @param printWriter writer where child nodes are written */ @Override protected void printXml(final String indent, final PrintWriter printWriter) { printWriter.print(indent + "<"); printOpeningTagContentAsXml(printWriter); printWriter.print(">"); printWriter.print(StringEscapeUtils.escapeXml10(getText())); printWriter.print(""); } /** * {@inheritDoc} */ @Override protected void doType(final char c, final boolean lastType) { doTypeProcessor_.doType(getText(), selectionDelegate_, c, this, lastType); } /** * {@inheritDoc} */ @Override protected void doType(final int keyCode, final boolean lastType) { doTypeProcessor_.doType(getText(), selectionDelegate_, keyCode, this, lastType); } /** * {@inheritDoc} */ @Override protected void typeDone(final String newValue, final boolean notifyAttributeChangeListeners) { setTextInternal(newValue); } /** * {@inheritDoc} */ @Override protected boolean acceptChar(final char c) { return super.acceptChar(c) || c == '\n' || c == '\r'; } /** * {@inheritDoc} */ @Override public void focus() { super.focus(); valueAtFocus_ = getText(); } /** * {@inheritDoc} */ @Override public void removeFocus() { super.removeFocus(); if (valueAtFocus_ != null && !valueAtFocus_.equals(getText())) { HtmlInput.executeOnChangeHandlerIfAppropriate(this); } valueAtFocus_ = null; } /** * 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 read only. * @return {@code true} if this element is read only */ public boolean isReadOnly() { return hasAttribute("readOnly"); } /** * {@inheritDoc} */ @Override protected void setAttributeNS(final String namespaceURI, final String qualifiedName, final String attributeValue, final boolean notifyAttributeChangeListeners, final boolean notifyMutationObservers) { final String qualifiedNameLC = org.htmlunit.util.StringUtils.toRootLowerCase(qualifiedName); if (DomElement.NAME_ATTRIBUTE.equals(qualifiedNameLC)) { if (newNames_.isEmpty()) { newNames_ = new HashSet<>(); } newNames_.add(attributeValue); } super.setAttributeNS(namespaceURI, qualifiedNameLC, attributeValue, notifyAttributeChangeListeners, notifyMutationObservers); } /** * {@inheritDoc} */ @Override public String getOriginalName() { return originalName_; } /** * {@inheritDoc} */ @Override public Collection getNewNames() { return newNames_; } /** * {@inheritDoc} * @return {@code true} to make generated XML readable as HTML */ @Override protected boolean isEmptyXmlTagExpanded() { return true; } /** * {@inheritDoc} */ @Override public DisplayStyle getDefaultStyleDisplay() { return DisplayStyle.INLINE_BLOCK; } /** * 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 HtmlTextArea newnode = (HtmlTextArea) super.cloneNode(deep); newnode.selectionDelegate_ = new SelectableTextSelectionDelegate(newnode); newnode.doTypeProcessor_ = new DoTypeProcessor(newnode); newnode.newNames_ = new HashSet<>(newNames_); return newnode; } /** * {@inheritDoc} */ @Override public boolean willValidate() { return !isDisabled() && (hasFeature(HTMLTEXTAREA_WILL_VALIDATE_IGNORES_READONLY) || !isReadOnly()); } /** * {@inheritDoc} */ @Override public void setCustomValidity(final String message) { customValidity_ = message; } /** * {@inheritDoc} */ @Override public boolean isValid() { return isValidValidityState(); } /** * {@inheritDoc} */ @Override public boolean isCustomErrorValidityState() { return !StringUtils.isEmpty(customValidity_); } @Override public boolean isValidValidityState() { return !isCustomErrorValidityState() && !isValueMissingValidityState(); } /** * {@inheritDoc} */ @Override public boolean isValueMissingValidityState() { return ATTRIBUTE_NOT_DEFINED != getAttributeDirect(ATTRIBUTE_REQUIRED) && getText().isEmpty(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy