/* * Copyright (c) 2002-2008 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.io.IOException; import java.io.PrintWriter; import java.util.Map; import org.apache.commons.httpclient.NameValuePair; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.SgmlPage; /** * Wrapper for the HTML element "textarea". * * @version $Revision$ * @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 */ public class HtmlTextArea extends ClickableElement implements DisabledElement, SubmittableElement { private static final long serialVersionUID = 4572856255042499634L; /** The HTML tag represented by this element. */ public static final String TAG_NAME = "textarea"; private String defaultValue_; private int selectionStart_; private int selectionEnd_; private boolean preventDefault_; /** * 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 */ HtmlTextArea(final String namespaceURI, final String qualifiedName, final SgmlPage page, final Map attributes) { super(namespaceURI, qualifiedName, page, attributes); } /** * 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) { final DomText child = (DomText) getFirstChild(); if (child != null) { defaultValue_ = child.getData(); if (defaultValue_ == null) { defaultValue_ = ""; } } else { defaultValue_ = ""; } } } /** * Returns the value that would be displayed in the text area. * * @return the text */ public final String getText() { final StringBuilder buffer = new StringBuilder(); for (final DomNode node : getChildren()) { if (node instanceof DomText) { buffer.append(((DomText) node).getData()); } } return buffer.toString(); } /** * {@inheritDoc} */ @Override public String asText() { if (isStyleVisible()) { return getText(); } return ""; } /** * Sets the new value of this text area. * * @param newValue the new value */ public final void setText(final String newValue) { initDefaultValue(); final DomText child = (DomText) getFirstChild(); if (child == null) { final DomText newChild = new DomText(getPage(), newValue); appendChild(newChild); } else { child.setData(newValue); } HtmlInput.executeOnChangeHandlerIfAppropriate(this); setSelectionStart(newValue.length()); setSelectionEnd(newValue.length()); } /** * {@inheritDoc} */ public NameValuePair[] getSubmitKeyValuePairs() { return new NameValuePair[]{new NameValuePair(getNameAttribute(), getText())}; } /** * {@inheritDoc} * @see SubmittableElement#reset() */ public void reset() { initDefaultValue(); setText(defaultValue_); } /** * {@inheritDoc} * @see SubmittableElement#setDefaultValue(String) */ public void setDefaultValue(final String defaultValue) { initDefaultValue(); if (defaultValue == null) { defaultValue_ = ""; } else { defaultValue_ = defaultValue; } } /** * {@inheritDoc} * @see SubmittableElement#getDefaultValue() */ 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) */ 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 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 getAttributeValue("name"); } /** * Returns the value of the attribute "rows". Refer to the * HTML 4.01 * documentation for details on the use of this attribute. * * @return the value of the attribute "rows" or an empty string if that attribute isn't defined */ public final String getRowsAttribute() { return getAttributeValue("rows"); } /** * Returns the value of the attribute "cols". Refer to the * HTML 4.01 * documentation for details on the use of this attribute. * * @return the value of the attribute "cols" or an empty string if that attribute isn't defined */ public final String getColumnsAttribute() { return getAttributeValue("cols"); } /** * {@inheritDoc} */ public final boolean isDisabled() { return isAttributeDefined("disabled"); } /** * {@inheritDoc} */ public final String getDisabledAttribute() { return getAttributeValue("disabled"); } /** * Returns the value of the attribute "readonly". Refer to the * HTML 4.01 * documentation for details on the use of this attribute. * * @return the value of the attribute "readonly" or an empty string if that attribute isn't defined */ public final String getReadOnlyAttribute() { return getAttributeValue("readonly"); } /** * 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 getAttributeValue("tabindex"); } /** * Returns the value of the attribute "accesskey". Refer to the * HTML 4.01 * documentation for details on the use of this attribute. * * @return the value of the attribute "accesskey" or an empty string if that attribute isn't defined */ public final String getAccessKeyAttribute() { return getAttributeValue("accesskey"); } /** * 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 getAttributeValue("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 getAttributeValue("onblur"); } /** * Returns the value of the attribute "onselect". Refer to the * HTML 4.01 * documentation for details on the use of this attribute. * * @return the value of the attribute "onselect" or an empty string if that attribute isn't defined */ public final String getOnSelectAttribute() { return getAttributeValue("onselect"); } /** * 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 getAttributeValue("onchange"); } /** * Returns the selected text contained in this text area, or null if no selection (Firefox only). * @return the selected text contained in this text area */ public String getSelectedText() { String text = null; if (selectionStart_ != selectionEnd_) { text = getText().substring(selectionStart_, selectionEnd_); } return text; } /** * Returns the selected text's start position (Firefox only). * @return the start position >= 0 */ public int getSelectionStart() { return selectionStart_; } /** * Sets the selection start to the specified position (Firefox only). * @param selectionStart the start position of the text >= 0 */ public void setSelectionStart(int selectionStart) { if (selectionStart < 0) { selectionStart = 0; } final int length = getText().length(); if (selectionStart > length) { selectionStart = length; } if (selectionEnd_ < selectionStart) { selectionEnd_ = selectionStart; } this.selectionStart_ = selectionStart; } /** * Returns the selected text's end position (Firefox only). * @return the end position >= 0 */ public int getSelectionEnd() { return selectionEnd_; } /** * Sets the selection end to the specified position (Firefox only). * @param selectionEnd the end position of the text >= 0 */ public void setSelectionEnd(int selectionEnd) { if (selectionEnd < 0) { selectionEnd = 0; } final int length = getText().length(); if (selectionEnd > length) { selectionEnd = length; } if (selectionEnd < selectionStart_) { selectionStart_ = selectionEnd; } this.selectionEnd_ = 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(getText()); printWriter.print(indent + ""); } /** * {@inheritDoc} */ @Override public Page type(final char c, final boolean shiftKey, final boolean ctrlKey, final boolean altKey) throws IOException { if (isDisabled()) { return getPage(); } preventDefault_ = false; return super.type(c, shiftKey, ctrlKey, altKey); } /** * {@inheritDoc} */ @Override protected void doType(final char c, final boolean shiftKey, final boolean ctrlKey, final boolean altKey) { if (preventDefault_) { return; } final String text = getText(); if (c == '\b') { if (text.length() > 0) { setText(text.substring(0, text.length() - 1)); } } else if ((c == ' ' || c == '\n' || c == '\r' || !Character.isWhitespace(c))) { setText(text + c); } } /** * {@inheritDoc} */ @Override protected void preventDefault() { preventDefault_ = true; } /** * Select all the text in this input. */ public void select() { focus(); setSelectionStart(0); setSelectionEnd(getText().length()); } }