View Javadoc
1   /*
2    * Copyright (c) 2002-2017 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package com.gargoylesoftware.htmlunit.javascript.host.html;
16  
17  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_TEXT_AREA_GET_MAXLENGTH_MAX_INT;
18  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_TEXT_AREA_SET_COLS_NEGATIVE_THROWS_EXCEPTION;
19  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_TEXT_AREA_SET_COLS_THROWS_EXCEPTION;
20  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_TEXT_AREA_SET_MAXLENGTH_NEGATIVE_THROWS_EXCEPTION;
21  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_TEXT_AREA_SET_ROWS_NEGATIVE_THROWS_EXCEPTION;
22  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_TEXT_AREA_SET_ROWS_THROWS_EXCEPTION;
23  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_TEXT_AREA_SET_VALUE_NULL;
24  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
25  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
26  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF;
27  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.IE;
28  
29  import com.gargoylesoftware.htmlunit.html.HtmlTextArea;
30  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
31  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor;
32  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction;
33  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
34  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxSetter;
35  import com.gargoylesoftware.htmlunit.javascript.host.dom.AbstractList;
36  import com.gargoylesoftware.htmlunit.javascript.host.dom.TextRange;
37  
38  import net.sourceforge.htmlunit.corejs.javascript.Context;
39  
40  /**
41   * The JavaScript object {@code HTMLTextAreaElement}.
42   *
43   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
44   * @author Marc Guillemot
45   * @author Chris Erskine
46   * @author Ahmed Ashour
47   * @author Daniel Gredler
48   * @author Ronald Brill
49   * @author Frank Danek
50   * @author Carsten Steul
51   */
52  @JsxClass(domClass = HtmlTextArea.class)
53  public class HTMLTextAreaElement extends FormField {
54  
55      /** "Live" labels collection; has to be a member to have equality (==) working. */
56      private AbstractList labels_;
57  
58      /**
59       * Creates an instance.
60       */
61      @JsxConstructor({CHROME, FF, EDGE})
62      public HTMLTextAreaElement() {
63      }
64  
65      /**
66       * Returns the type of this input.
67       * @return the type of this input
68       */
69      @JsxGetter
70      public String getType() {
71          return "textarea";
72      }
73  
74      /**
75       * Returns the value of the {@code value} attribute.
76       * @return the value of the {@code value} attribute
77       */
78      @Override
79      public String getValue() {
80          return ((HtmlTextArea) getDomNodeOrDie()).getText();
81      }
82  
83      /**
84       * Sets the value of the {@code value} attribute.
85       * @param value the new value
86       */
87      @Override
88      public void setValue(final Object value) {
89          if (null == value && getBrowserVersion().hasFeature(JS_TEXT_AREA_SET_VALUE_NULL)) {
90              ((HtmlTextArea) getDomNodeOrDie()).setText("");
91              return;
92          }
93  
94          ((HtmlTextArea) getDomNodeOrDie()).setText(Context.toString(value));
95      }
96  
97      /**
98       * Returns the number of columns in this text area.
99       * @return the number of columns in this text area
100      */
101     @JsxGetter
102     public int getCols() {
103         final String s = getDomNodeOrDie().getAttribute("cols");
104         try {
105             return Integer.parseInt(s);
106         }
107         catch (final NumberFormatException e) {
108             return 20;
109         }
110     }
111 
112     /**
113      * Sets the number of columns in this text area.
114      * @param cols the number of columns in this text area
115      */
116     @JsxSetter
117     public void setCols(final String cols) {
118         try {
119             final int i = Float.valueOf(cols).intValue();
120             if (i < 0) {
121                 if (getBrowserVersion().hasFeature(JS_TEXT_AREA_SET_COLS_NEGATIVE_THROWS_EXCEPTION)) {
122                     throw new NumberFormatException("New value for cols '" + cols + "' is smaller than zero.");
123                 }
124                 getDomNodeOrDie().setAttribute("cols", null);
125                 return;
126             }
127             getDomNodeOrDie().setAttribute("cols", Integer.toString(i));
128         }
129         catch (final NumberFormatException e) {
130             if (getBrowserVersion().hasFeature(JS_TEXT_AREA_SET_COLS_THROWS_EXCEPTION)) {
131                 throw Context.throwAsScriptRuntimeEx(e);
132             }
133             getDomNodeOrDie().setAttribute("cols", "20");
134         }
135     }
136 
137     /**
138      * Returns the number of rows in this text area.
139      * @return the number of rows in this text area
140      */
141     @JsxGetter
142     public int getRows() {
143         final String s = getDomNodeOrDie().getAttribute("rows");
144         try {
145             return Integer.parseInt(s);
146         }
147         catch (final NumberFormatException e) {
148             return 2;
149         }
150     }
151 
152     /**
153      * Sets the number of rows in this text area.
154      * @param rows the number of rows in this text area
155      */
156     @JsxSetter
157     public void setRows(final String rows) {
158         try {
159             final int i = new Float(rows).intValue();
160             if (i < 0) {
161                 if (getBrowserVersion().hasFeature(JS_TEXT_AREA_SET_ROWS_NEGATIVE_THROWS_EXCEPTION)) {
162                     throw new NumberFormatException("New value for rows '" + rows + "' is smaller than zero.");
163                 }
164                 getDomNodeOrDie().setAttribute("rows", null);
165                 return;
166             }
167             getDomNodeOrDie().setAttribute("rows", Integer.toString(i));
168         }
169         catch (final NumberFormatException e) {
170             if (getBrowserVersion().hasFeature(JS_TEXT_AREA_SET_ROWS_THROWS_EXCEPTION)) {
171                 throw Context.throwAsScriptRuntimeEx(e);
172             }
173 
174             getDomNodeOrDie().setAttribute("rows", "2");
175         }
176     }
177 
178     /**
179      * Returns the textarea's default value, used if the containing form gets reset.
180      * @return the textarea's default value, used if the containing form gets reset
181      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533718.aspx">MSDN Documentation</a>
182      */
183     @JsxGetter
184     public String getDefaultValue() {
185         return ((HtmlTextArea) getDomNodeOrDie()).getDefaultValue();
186     }
187 
188     /**
189      * Sets the textarea's default value, used if the containing form gets reset.
190      * @param defaultValue the textarea's default value, used if the containing form gets reset
191      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533718.aspx">MSDN Documentation</a>
192      */
193     @JsxSetter
194     public void setDefaultValue(final String defaultValue) {
195         ((HtmlTextArea) getDomNodeOrDie()).setDefaultValue(defaultValue);
196     }
197 
198     /**
199      * Gets the value of {@code textLength} attribute.
200      * @return the text length
201      */
202     @JsxGetter({CHROME, FF})
203     public int getTextLength() {
204         return getValue().length();
205     }
206 
207     /**
208      * Gets the value of {@code selectionStart} attribute.
209      * @return the selection start
210      */
211     @JsxGetter
212     public int getSelectionStart() {
213         return ((HtmlTextArea) getDomNodeOrDie()).getSelectionStart();
214     }
215 
216     /**
217      * Sets the value of {@code selectionStart} attribute.
218      * @param start selection start
219      */
220     @JsxSetter
221     public void setSelectionStart(final int start) {
222         ((HtmlTextArea) getDomNodeOrDie()).setSelectionStart(start);
223     }
224 
225     /**
226      * Gets the value of {@code selectionEnd} attribute.
227      * @return the selection end
228      */
229     @JsxGetter
230     public int getSelectionEnd() {
231         return ((HtmlTextArea) getDomNodeOrDie()).getSelectionEnd();
232     }
233 
234     /**
235      * Sets the value of {@code selectionEnd} attribute.
236      * @param end selection end
237      */
238     @JsxSetter
239     public void setSelectionEnd(final int end) {
240         ((HtmlTextArea) getDomNodeOrDie()).setSelectionEnd(end);
241     }
242 
243     /**
244      * Sets the selected portion of this input element.
245      * @param start the index of the first character to select
246      * @param end the index of the character after the selection
247      */
248     @JsxFunction
249     public void setSelectionRange(final int start, final int end) {
250         setSelectionStart(start);
251         setSelectionEnd(end);
252     }
253 
254     /**
255      * Selects this element.
256      */
257     @JsxFunction
258     public void select() {
259         ((HtmlTextArea) getDomNodeOrDie()).select();
260     }
261 
262     /**
263      * Gets the value of {@code readOnly} attribute.
264      * @return the readOnly attribute
265      */
266     @JsxGetter
267     public boolean isReadOnly() {
268         return ((HtmlTextArea) getDomNodeOrDie()).isReadOnly();
269     }
270 
271     /**
272      * Sets the value of {@code readOnly} attribute.
273      * @param readOnly the new value
274      */
275     @JsxSetter
276     public void setReadOnly(final boolean readOnly) {
277         ((HtmlTextArea) getDomNodeOrDie()).setReadOnly(readOnly);
278     }
279 
280     /**
281      * Returns the maximum number of characters in this text area.
282      * @return the maximum number of characters in this text area
283      */
284     @JsxGetter
285     public Object getMaxLength() {
286         final String maxLength = getDomNodeOrDie().getAttribute("maxLength");
287 
288         try {
289             return Integer.parseInt(maxLength);
290         }
291         catch (final NumberFormatException e) {
292             if (getBrowserVersion().hasFeature(JS_TEXT_AREA_GET_MAXLENGTH_MAX_INT)) {
293                 return Integer.MAX_VALUE;
294             }
295             return -1;
296         }
297     }
298 
299     /**
300      * Sets maximum number of characters in this text area.
301      * @param maxLength maximum number of characters in this text area.
302      */
303     @JsxSetter
304     public void setMaxLength(final String maxLength) {
305         try {
306             final int i = Integer.parseInt(maxLength);
307 
308             if (i < 0 && getBrowserVersion().hasFeature(JS_TEXT_AREA_SET_MAXLENGTH_NEGATIVE_THROWS_EXCEPTION)) {
309                 throw Context.throwAsScriptRuntimeEx(
310                     new NumberFormatException("New value for maxLength '" + maxLength + "' is smaller than zero."));
311             }
312             getDomNodeOrDie().setAttribute("maxLength", maxLength);
313         }
314         catch (final NumberFormatException e) {
315             getDomNodeOrDie().setAttribute("maxLength", "0");
316         }
317     }
318 
319     /**
320      * Returns the minimum number of characters in this text area.
321      * @return the minimum number of characters in this text area
322      */
323     @JsxGetter({CHROME, FF})
324     public Object getMinLength() {
325         final String minLength = getDomNodeOrDie().getAttribute("minLength");
326 
327         try {
328             return Integer.parseInt(minLength);
329         }
330         catch (final NumberFormatException e) {
331             return -1;
332         }
333     }
334 
335     /**
336      * Sets minimum number of characters in this text area.
337      * @param minLength minimum number of characters in this text area.
338      */
339     @JsxSetter({CHROME, FF})
340     public void setMinLength(final String minLength) {
341         try {
342             final int i = Integer.parseInt(minLength);
343 
344             if (i < 0) {
345                 throw Context.throwAsScriptRuntimeEx(
346                     new NumberFormatException("New value for minLength '" + minLength + "' is smaller than zero."));
347             }
348             getDomNodeOrDie().setAttribute("minLength", minLength);
349         }
350         catch (final NumberFormatException e) {
351             getDomNodeOrDie().setAttribute("minLength", "0");
352         }
353     }
354 
355     /**
356      * Returns the {@code placeholder} attribute.
357      * @return the {@code placeholder} attribute
358      */
359     @JsxGetter
360     public String getPlaceholder() {
361         return ((HtmlTextArea) getDomNodeOrDie()).getPlaceholder();
362     }
363 
364     /**
365      * Sets the {@code placeholder} attribute.
366      * @param placeholder the new {@code placeholder} value
367      */
368     @JsxSetter
369     public void setPlaceholder(final String placeholder) {
370         ((HtmlTextArea) getDomNodeOrDie()).setPlaceholder(placeholder);
371     }
372 
373     /**
374      * Returns the labels associated with the element.
375      * @return the labels associated with the element
376      */
377     @JsxGetter(CHROME)
378     public AbstractList getLabels() {
379         if (labels_ == null) {
380             labels_ = new LabelsHelper(getDomNodeOrDie());
381         }
382         return labels_;
383     }
384 
385     /**
386      * {@inheritDoc}
387      */
388     @Override
389     @JsxFunction(IE)
390     public TextRange createTextRange() {
391         return super.createTextRange();
392     }
393 
394     /**
395      * Checks whether the element has any constraints and whether it satisfies them.
396      * @return if the element is valid
397      */
398     @JsxFunction
399     public boolean checkValidity() {
400         return getDomNodeOrDie().isValid();
401     }
402 
403     /**
404      * Returns the {@code required} property.
405      * @return the {@code required} property
406      */
407     @JsxGetter
408     public boolean isRequired() {
409         return getDomNodeOrDie().isRequired();
410     }
411 
412     /**
413      * Sets the {@code required} property.
414      * @param required the new value
415      */
416     @JsxSetter
417     public void setRequired(final boolean required) {
418         getDomNodeOrDie().setRequired(required);
419     }
420 
421 }