001: /*
002: * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: * 2. Redistributions in binary form must reproduce the above copyright notice,
010: * this list of conditions and the following disclaimer in the documentation
011: * and/or other materials provided with the distribution.
012: * 3. The end-user documentation included with the redistribution, if any, must
013: * include the following acknowledgment:
014: *
015: * "This product includes software developed by Gargoyle Software Inc.
016: * (http://www.GargoyleSoftware.com/)."
017: *
018: * Alternately, this acknowledgment may appear in the software itself, if
019: * and wherever such third-party acknowledgments normally appear.
020: * 4. The name "Gargoyle Software" must not be used to endorse or promote
021: * products derived from this software without prior written permission.
022: * For written permission, please contact info@GargoyleSoftware.com.
023: * 5. Products derived from this software may not be called "HtmlUnit", nor may
024: * "HtmlUnit" appear in their name, without prior written permission of
025: * Gargoyle Software Inc.
026: *
027: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
028: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
029: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
030: * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
031: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
033: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
036: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: */
038: package com.gargoylesoftware.htmlunit.html;
039:
040: import java.io.IOException;
041: import java.io.PrintWriter;
042: import java.util.Map;
043:
044: import com.gargoylesoftware.htmlunit.KeyValuePair;
045: import com.gargoylesoftware.htmlunit.Page;
046:
047: /**
048: * Wrapper for the html element "textarea"
049: *
050: * @version $Revision: 2132 $
051: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
052: * @author <a href="mailto:BarnabyCourt@users.sourceforge.net">Barnaby Court</a>
053: * @author David K. Taylor
054: * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
055: * @author David D. Kilzer
056: * @author Marc Guillemot
057: * @author Daniel Gredler
058: * @author Ahmed Ashour
059: */
060: public class HtmlTextArea extends FocusableElement implements
061: DisabledElement, SubmittableElement {
062:
063: private static final long serialVersionUID = 4572856255042499634L;
064:
065: /** the HTML tag represented by this element */
066: public static final String TAG_NAME = "textarea";
067:
068: private String defaultValue_;
069:
070: private int selectionStart_;
071:
072: private int selectionEnd_;
073:
074: private boolean preventDefault_;
075:
076: /**
077: * Create an instance
078: *
079: * @param page The page that contains this element
080: * @param attributes the initial attributes
081: * @deprecated You should not directly construct HtmlTextArea.
082: */
083: //TODO: to be removed, deprecated after 1.11
084: public HtmlTextArea(final HtmlPage page, final Map attributes) {
085: this (null, TAG_NAME, page, attributes);
086: }
087:
088: /**
089: * Create an instance
090: *
091: * @param namespaceURI the URI that identifies an XML namespace.
092: * @param qualifiedName The qualified name of the element type to instantiate
093: * @param page The page that contains this element
094: * @param attributes the initial attributes
095: */
096: HtmlTextArea(final String namespaceURI, final String qualifiedName,
097: final HtmlPage page, final Map attributes) {
098: super (namespaceURI, qualifiedName, page, attributes);
099: }
100:
101: /**
102: * Initializes the default value if necessary. We cannot do it in the constructor
103: * because the child node variable will not have been initialized yet. Must be called
104: * from all methods that use the default value.
105: */
106: private void initDefaultValue() {
107: if (defaultValue_ == null) {
108: final DomText child = (DomText) getFirstDomChild();
109: if (child != null) {
110: defaultValue_ = child.getData();
111: if (defaultValue_ == null) {
112: defaultValue_ = "";
113: }
114: } else {
115: defaultValue_ = "";
116: }
117: }
118: }
119:
120: /**
121: * Return the value that would be displayed in the text area
122: *
123: * @return The text
124: */
125: public final String getText() {
126: return getChildrenAsText();
127: }
128:
129: /**
130: * Set the new value of this text area.
131: *
132: * @param newValue The new value.
133: */
134: public final void setText(final String newValue) {
135: initDefaultValue();
136: final DomText child = (DomText) getFirstDomChild();
137: if (child == null) {
138: final DomText newChild = new DomText(getPage(), newValue);
139: appendDomChild(newChild);
140: } else {
141: child.setData(newValue);
142: }
143:
144: HtmlInput.executeOnChangeHandlerIfAppropriate(this );
145:
146: setSelectionStart(newValue.length());
147: setSelectionEnd(newValue.length());
148: }
149:
150: /**
151: * Return an array of KeyValuePairs that are the values that will be sent
152: * back to the server whenever the current form is submitted.<p>
153: *
154: * THIS METHOD IS INTENDED FOR THE USE OF THE FRAMEWORK ONLY AND SHOULD NOT
155: * BE USED BY CONSUMERS OF HTMLUNIT. USE AT YOUR OWN RISK.
156: *
157: * @return See above
158: */
159: public KeyValuePair[] getSubmitKeyValuePairs() {
160: return new KeyValuePair[] { new KeyValuePair(
161: getNameAttribute(), getText()) };
162: }
163:
164: /**
165: * {@inheritDoc}
166: * @see SubmittableElement#reset()
167: */
168: public void reset() {
169: initDefaultValue();
170: setText(defaultValue_);
171: }
172:
173: /**
174: * {@inheritDoc}
175: * @see SubmittableElement#setDefaultValue(String)
176: */
177: public void setDefaultValue(final String defaultValue) {
178: initDefaultValue();
179: if (defaultValue == null) {
180: defaultValue_ = "";
181: } else {
182: defaultValue_ = defaultValue;
183: }
184: }
185:
186: /**
187: * {@inheritDoc}
188: * @see SubmittableElement#getDefaultValue()
189: */
190: public String getDefaultValue() {
191: initDefaultValue();
192: return defaultValue_;
193: }
194:
195: /**
196: * {@inheritDoc} This implementation is empty; only checkboxes and radio buttons
197: * really care what the default checked value is.
198: * @see SubmittableElement#setDefaultChecked(boolean)
199: * @see HtmlRadioButtonInput#setDefaultChecked(boolean)
200: * @see HtmlCheckBoxInput#setDefaultChecked(boolean)
201: */
202: public void setDefaultChecked(final boolean defaultChecked) {
203: // Empty.
204: }
205:
206: /**
207: * {@inheritDoc} This implementation returns <tt>false</tt>; only checkboxes and
208: * radio buttons really care what the default checked value is.
209: * @see SubmittableElement#isDefaultChecked()
210: * @see HtmlRadioButtonInput#isDefaultChecked()
211: * @see HtmlCheckBoxInput#isDefaultChecked()
212: */
213: public boolean isDefaultChecked() {
214: return false;
215: }
216:
217: /**
218: * Return the value of the attribute "name". Refer to the
219: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
220: * documentation for details on the use of this attribute.
221: *
222: * @return The value of the attribute "name"
223: * or an empty string if that attribute isn't defined.
224: */
225: public final String getNameAttribute() {
226: return getAttributeValue("name");
227: }
228:
229: /**
230: * Return the value of the attribute "rows". Refer to the
231: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
232: * documentation for details on the use of this attribute.
233: *
234: * @return The value of the attribute "rows"
235: * or an empty string if that attribute isn't defined.
236: */
237: public final String getRowsAttribute() {
238: return getAttributeValue("rows");
239: }
240:
241: /**
242: * Return the value of the attribute "cols". Refer to the
243: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
244: * documentation for details on the use of this attribute.
245: *
246: * @return The value of the attribute "cols"
247: * or an empty string if that attribute isn't defined.
248: */
249: public final String getColumnsAttribute() {
250: return getAttributeValue("cols");
251: }
252:
253: /**
254: * Return true if the disabled attribute is set for this element.
255: *
256: * @return Return true if this element is disabled.
257: */
258: public final boolean isDisabled() {
259: return isAttributeDefined("disabled");
260: }
261:
262: /**
263: * Return the value of the attribute "disabled". Refer to the
264: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
265: * documentation for details on the use of this attribute.
266: *
267: * @return The value of the attribute "disabled"
268: * or an empty string if that attribute isn't defined.
269: */
270: public final String getDisabledAttribute() {
271: return getAttributeValue("disabled");
272: }
273:
274: /**
275: * Return the value of the attribute "readonly". Refer to the
276: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
277: * documentation for details on the use of this attribute.
278: *
279: * @return The value of the attribute "readonly"
280: * or an empty string if that attribute isn't defined.
281: */
282: public final String getReadOnlyAttribute() {
283: return getAttributeValue("readonly");
284: }
285:
286: /**
287: * Return the value of the attribute "tabindex". Refer to the
288: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
289: * documentation for details on the use of this attribute.
290: *
291: * @return The value of the attribute "tabindex"
292: * or an empty string if that attribute isn't defined.
293: */
294: public final String getTabIndexAttribute() {
295: return getAttributeValue("tabindex");
296: }
297:
298: /**
299: * Return the value of the attribute "accesskey". Refer to the
300: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
301: * documentation for details on the use of this attribute.
302: *
303: * @return The value of the attribute "accesskey"
304: * or an empty string if that attribute isn't defined.
305: */
306: public final String getAccessKeyAttribute() {
307: return getAttributeValue("accesskey");
308: }
309:
310: /**
311: * Return the value of the attribute "onfocus". Refer to the
312: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
313: * documentation for details on the use of this attribute.
314: *
315: * @return The value of the attribute "onfocus"
316: * or an empty string if that attribute isn't defined.
317: */
318: public final String getOnFocusAttribute() {
319: return getAttributeValue("onfocus");
320: }
321:
322: /**
323: * Return the value of the attribute "onblur". Refer to the
324: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
325: * documentation for details on the use of this attribute.
326: *
327: * @return The value of the attribute "onblur"
328: * or an empty string if that attribute isn't defined.
329: */
330: public final String getOnBlurAttribute() {
331: return getAttributeValue("onblur");
332: }
333:
334: /**
335: * Return the value of the attribute "onselect". Refer to the
336: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
337: * documentation for details on the use of this attribute.
338: *
339: * @return The value of the attribute "onselect"
340: * or an empty string if that attribute isn't defined.
341: */
342: public final String getOnSelectAttribute() {
343: return getAttributeValue("onselect");
344: }
345:
346: /**
347: * Return the value of the attribute "onchange". Refer to the
348: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
349: * documentation for details on the use of this attribute.
350: *
351: * @return The value of the attribute "onchange"
352: * or an empty string if that attribute isn't defined.
353: */
354: public final String getOnChangeAttribute() {
355: return getAttributeValue("onchange");
356: }
357:
358: /**
359: * Returns the selected text contained in this HtmlTextArea, <code>null</code> if no selection (Firefox only).
360: * @return the text
361: */
362: public String getSelectedText() {
363: String text = null;
364: if (selectionStart_ != selectionEnd_) {
365: text = getText().substring(selectionStart_, selectionEnd_);
366: }
367: return text;
368: }
369:
370: /**
371: * Returns the selected text's start position (Firefox only).
372: * @return the start position >= 0
373: */
374: public int getSelectionStart() {
375: return selectionStart_;
376: }
377:
378: /**
379: * Sets the selection start to the specified position (Firefox only).
380: * @param selectionStart the start position of the text >= 0
381: */
382: public void setSelectionStart(int selectionStart) {
383: if (selectionStart < 0) {
384: selectionStart = 0;
385: }
386: final int length = getText().length();
387: if (selectionStart > length) {
388: selectionStart = length;
389: }
390: if (selectionEnd_ < selectionStart) {
391: selectionEnd_ = selectionStart;
392: }
393: this .selectionStart_ = selectionStart;
394: }
395:
396: /**
397: * Returns the selected text's end position (Firefox only).
398: * @return the end position >= 0
399: */
400: public int getSelectionEnd() {
401: return selectionEnd_;
402: }
403:
404: /**
405: * Sets the selection end to the specified position (Firefox only).
406: * @param selectionEnd the end position of the text >= 0
407:
408: */
409: public void setSelectionEnd(int selectionEnd) {
410: if (selectionEnd < 0) {
411: selectionEnd = 0;
412: }
413: final int length = getText().length();
414: if (selectionEnd > length) {
415: selectionEnd = length;
416: }
417: if (selectionEnd < selectionStart_) {
418: selectionStart_ = selectionEnd;
419: }
420: this .selectionEnd_ = selectionEnd;
421: }
422:
423: /**
424: * recursively write the XML data for the node tree starting at <code>node</code>
425: *
426: * @param indent white space to indent child nodes
427: * @param printWriter writer where child nodes are written
428: */
429: protected void printXml(final String indent,
430: final PrintWriter printWriter) {
431: printWriter.print(indent + "<");
432: printOpeningTagContentAsXml(printWriter);
433:
434: printWriter.print(">");
435: printWriter.print(getText());
436: printWriter.print(indent + "</textarea>");
437: }
438:
439: /**
440: * {@inheritDoc}
441: */
442: public Page type(final char c, final boolean shiftKey,
443: final boolean ctrlKey, final boolean altKey)
444: throws IOException {
445: if (this instanceof DisabledElement
446: && ((DisabledElement) this ).isDisabled()) {
447: return getPage();
448: }
449: preventDefault_ = false;
450: final Page page = super .type(c, shiftKey, ctrlKey, altKey);
451:
452: //TODO: handle backspace
453: if (!Character.isWhitespace(c) && !preventDefault_) {
454: setText(getText() + c);
455: }
456: return page;
457: }
458:
459: /**
460: * {@inheritDoc}
461: */
462: protected void preventDefault() {
463: preventDefault_ = true;
464: }
465: }
|