/*
* 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());
}
}