1 /*
2 * Copyright (c) 2002-2026 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 * https://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 org.htmlunit.javascript.host.html;
16
17 import org.htmlunit.html.HtmlTextArea;
18 import org.htmlunit.javascript.JavaScriptEngine;
19 import org.htmlunit.javascript.configuration.JsxClass;
20 import org.htmlunit.javascript.configuration.JsxConstructor;
21 import org.htmlunit.javascript.configuration.JsxFunction;
22 import org.htmlunit.javascript.configuration.JsxGetter;
23 import org.htmlunit.javascript.configuration.JsxSetter;
24 import org.htmlunit.javascript.host.dom.DOMException;
25 import org.htmlunit.javascript.host.dom.NodeList;
26
27 /**
28 * The JavaScript object {@code HTMLTextAreaElement}.
29 *
30 * @author Mike Bowler
31 * @author Marc Guillemot
32 * @author Chris Erskine
33 * @author Ahmed Ashour
34 * @author Daniel Gredler
35 * @author Ronald Brill
36 * @author Frank Danek
37 * @author Carsten Steul
38 *
39 * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement">MDN Documentation</a>
40 */
41 @JsxClass(domClass = HtmlTextArea.class)
42 public class HTMLTextAreaElement extends HTMLElement {
43
44 /** "Live" labels collection; has to be a member to have equality (==) working. */
45 private NodeList labels_;
46
47 /**
48 * JavaScript constructor.
49 */
50 @Override
51 @JsxConstructor
52 public void jsConstructor() {
53 super.jsConstructor();
54 }
55
56 /**
57 * Returns the type of this input.
58 * @return the type of this input
59 */
60 @JsxGetter
61 public String getType() {
62 return "textarea";
63 }
64
65 /**
66 * {@inheritDoc}
67 */
68 @Override
69 public HtmlTextArea getDomNodeOrDie() {
70 return (HtmlTextArea) super.getDomNodeOrDie();
71 }
72
73 /**
74 * Returns the value of the {@code value} attribute.
75 * @return the value of the {@code value} attribute
76 */
77 @JsxGetter
78 @Override
79 public String getValue() {
80 return getDomNodeOrDie().getText();
81 }
82
83 /**
84 * Sets the value of the {@code value} attribute.
85 * @param value the new value
86 */
87 @JsxSetter
88 @Override
89 public void setValue(final Object value) {
90 if (null == value) {
91 getDomNodeOrDie().setText("");
92 return;
93 }
94
95 getDomNodeOrDie().setText(JavaScriptEngine.toString(value));
96 }
97
98 /**
99 * Returns the number of columns in this text area.
100 * @return the number of columns in this text area
101 */
102 @JsxGetter
103 public int getCols() {
104 final String s = getDomNodeOrDie().getAttributeDirect("cols");
105 try {
106 return Integer.parseInt(s);
107 }
108 catch (final NumberFormatException e) {
109 return 20;
110 }
111 }
112
113 /**
114 * Sets the number of columns in this text area.
115 * @param cols the number of columns in this text area
116 */
117 @JsxSetter
118 public void setCols(final String cols) {
119 try {
120 final int i = Float.valueOf(cols).intValue();
121 if (i < 0) {
122 getDomNodeOrDie().setAttribute("cols", null);
123 return;
124 }
125 getDomNodeOrDie().setAttribute("cols", Integer.toString(i));
126 }
127 catch (final NumberFormatException e) {
128 getDomNodeOrDie().setAttribute("cols", "20");
129 }
130 }
131
132 /**
133 * Returns the number of rows in this text area.
134 * @return the number of rows in this text area
135 */
136 @JsxGetter
137 public int getRows() {
138 final String s = getDomNodeOrDie().getAttributeDirect("rows");
139 try {
140 return Integer.parseInt(s);
141 }
142 catch (final NumberFormatException e) {
143 return 2;
144 }
145 }
146
147 /**
148 * Sets the number of rows in this text area.
149 * @param rows the number of rows in this text area
150 */
151 @JsxSetter
152 public void setRows(final String rows) {
153 try {
154 final int i = Float.valueOf(rows).intValue();
155 if (i < 0) {
156 getDomNodeOrDie().setAttribute("rows", null);
157 return;
158 }
159 getDomNodeOrDie().setAttribute("rows", Integer.toString(i));
160 }
161 catch (final NumberFormatException e) {
162 getDomNodeOrDie().setAttribute("rows", "2");
163 }
164 }
165
166 /**
167 * Returns the textarea's default value, used if the containing form gets reset.
168 * @return the textarea's default value, used if the containing form gets reset
169 * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement/defaultValue">MDN Documentation</a>
170 */
171 @JsxGetter
172 public String getDefaultValue() {
173 return getDomNodeOrDie().getDefaultValue();
174 }
175
176 /**
177 * Sets the textarea's default value, used if the containing form gets reset.
178 * @param defaultValue the textarea's default value, used if the containing form gets reset
179 * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement/defaultValue">MDN Documentation</a>
180 */
181 @JsxSetter
182 public void setDefaultValue(final String defaultValue) {
183 getDomNodeOrDie().setDefaultValue(defaultValue);
184 }
185
186 /**
187 * Gets the value of {@code textLength} attribute.
188 * @return the text length
189 */
190 @JsxGetter
191 public int getTextLength() {
192 return getValue().length();
193 }
194
195 /**
196 * Gets the value of {@code selectionStart} attribute.
197 * @return the selection start
198 */
199 @JsxGetter
200 public int getSelectionStart() {
201 return getDomNodeOrDie().getSelectionStart();
202 }
203
204 /**
205 * Sets the value of {@code selectionStart} attribute.
206 * @param start selection start
207 */
208 @JsxSetter
209 public void setSelectionStart(final int start) {
210 getDomNodeOrDie().setSelectionStart(start);
211 }
212
213 /**
214 * Gets the value of {@code selectionEnd} attribute.
215 * @return the selection end
216 */
217 @JsxGetter
218 public int getSelectionEnd() {
219 return getDomNodeOrDie().getSelectionEnd();
220 }
221
222 /**
223 * Sets the value of {@code selectionEnd} attribute.
224 * @param end selection end
225 */
226 @JsxSetter
227 public void setSelectionEnd(final int end) {
228 getDomNodeOrDie().setSelectionEnd(end);
229 }
230
231 /**
232 * Sets the selected portion of this input element.
233 * @param start the index of the first character to select
234 * @param end the index of the character after the selection
235 */
236 @JsxFunction
237 public void setSelectionRange(final int start, final int end) {
238 setSelectionStart(start);
239 setSelectionEnd(end);
240 }
241
242 /**
243 * Selects this element.
244 */
245 @JsxFunction
246 public void select() {
247 getDomNodeOrDie().select();
248 }
249
250 /**
251 * Gets the value of {@code readOnly} attribute.
252 * @return the readOnly attribute
253 */
254 @JsxGetter
255 public boolean isReadOnly() {
256 return getDomNodeOrDie().isReadOnly();
257 }
258
259 /**
260 * Sets the value of {@code readOnly} attribute.
261 * @param readOnly the new value
262 */
263 @JsxSetter
264 public void setReadOnly(final boolean readOnly) {
265 getDomNodeOrDie().setReadOnly(readOnly);
266 }
267
268 /**
269 * Returns the maximum number of characters in this text area.
270 * @return the maximum number of characters in this text area
271 */
272 @JsxGetter
273 public int getMaxLength() {
274 final String maxLength = getDomNodeOrDie().getAttribute("maxLength");
275
276 try {
277 return Integer.parseInt(maxLength);
278 }
279 catch (final NumberFormatException e) {
280 return -1;
281 }
282 }
283
284 /**
285 * Sets maximum number of characters in this text area.
286 * @param maxLength maximum number of characters in this text area
287 */
288 @JsxSetter
289 public void setMaxLength(final String maxLength) {
290 try {
291 final int i = Integer.parseInt(maxLength);
292
293 if (i < 0) {
294 throw JavaScriptEngine.asJavaScriptException(getWindow(),
295 "New value for maxLength '" + maxLength + "' is smaller than zero.",
296 DOMException.INDEX_SIZE_ERR);
297 }
298 getDomNodeOrDie().setAttribute("maxLength", maxLength);
299 }
300 catch (final NumberFormatException e) {
301 getDomNodeOrDie().setAttribute("maxLength", "0");
302 }
303 }
304
305 /**
306 * Returns the minimum number of characters in this text area.
307 * @return the minimum number of characters in this text area
308 */
309 @JsxGetter
310 public int getMinLength() {
311 final String minLength = getDomNodeOrDie().getAttribute("minLength");
312
313 try {
314 return Integer.parseInt(minLength);
315 }
316 catch (final NumberFormatException e) {
317 return -1;
318 }
319 }
320
321 /**
322 * Sets minimum number of characters in this text area.
323 * @param minLength minimum number of characters in this text area
324 */
325 @JsxSetter
326 public void setMinLength(final String minLength) {
327 try {
328 final int i = Integer.parseInt(minLength);
329
330 if (i < 0) {
331 throw JavaScriptEngine.throwAsScriptRuntimeEx(
332 new NumberFormatException("New value for minLength '" + minLength + "' is smaller than zero."));
333 }
334 getDomNodeOrDie().setAttribute("minLength", minLength);
335 }
336 catch (final NumberFormatException e) {
337 getDomNodeOrDie().setAttribute("minLength", "0");
338 }
339 }
340
341 /**
342 * Returns the {@code placeholder} attribute.
343 * @return the {@code placeholder} attribute
344 */
345 @JsxGetter
346 public String getPlaceholder() {
347 return getDomNodeOrDie().getPlaceholder();
348 }
349
350 /**
351 * Sets the {@code placeholder} attribute.
352 * @param placeholder the new {@code placeholder} value
353 */
354 @JsxSetter
355 public void setPlaceholder(final String placeholder) {
356 getDomNodeOrDie().setPlaceholder(placeholder);
357 }
358
359 /**
360 * Returns the labels associated with the element.
361 * @return the labels associated with the element
362 */
363 @JsxGetter
364 public NodeList getLabels() {
365 if (labels_ == null) {
366 labels_ = new LabelsNodeList(getDomNodeOrDie());
367 }
368 return labels_;
369 }
370
371 /**
372 * Checks whether the element has any constraints and whether it satisfies them.
373 * @return {@code true} if the element is valid
374 */
375 @JsxFunction
376 public boolean checkValidity() {
377 return getDomNodeOrDie().isValid();
378 }
379
380 /**
381 * Returns the {@code required} property.
382 * @return the {@code required} property
383 */
384 @JsxGetter
385 public boolean isRequired() {
386 return getDomNodeOrDie().isRequired();
387 }
388
389 /**
390 * Sets the {@code required} property.
391 * @param required the new value
392 */
393 @JsxSetter
394 public void setRequired(final boolean required) {
395 getDomNodeOrDie().setRequired(required);
396 }
397
398 /**
399 * {@inheritDoc}
400 */
401 @JsxGetter
402 @Override
403 public String getName() {
404 return super.getName();
405 }
406
407 /**
408 * {@inheritDoc}
409 */
410 @JsxSetter
411 @Override
412 public void setName(final String newName) {
413 super.setName(newName);
414 }
415
416 /**
417 * {@inheritDoc} Overridden to modify browser configurations.
418 */
419 @Override
420 @JsxGetter
421 public boolean isDisabled() {
422 return super.isDisabled();
423 }
424
425 /**
426 * {@inheritDoc} Overridden to modify browser configurations.
427 */
428 @Override
429 @JsxSetter
430 public void setDisabled(final boolean disabled) {
431 super.setDisabled(disabled);
432 }
433
434 /**
435 * {@inheritDoc}
436 */
437 @JsxGetter
438 @Override
439 public HTMLFormElement getForm() {
440 return super.getForm();
441 }
442
443 /**
444 * Returns whether the element is a candidate for constraint validation.
445 * @return whether the element is a candidate for constraint validation
446 */
447 @JsxGetter
448 public boolean isWillValidate() {
449 return getDomNodeOrDie().willValidate();
450 }
451
452 /**
453 * Returns a {@link ValidityState} object representing the validity states of this element.
454 * @return a {@link ValidityState} object representing the validity states of this element
455 */
456 @JsxGetter
457 public ValidityState getValidity() {
458 final ValidityState validityState = new ValidityState();
459 validityState.setPrototype(getPrototype(validityState.getClass()));
460 validityState.setParentScope(getParentScope());
461 validityState.setDomNode(getDomNodeOrDie());
462 return validityState;
463 }
464
465 /**
466 * Sets the custom validity message for the element to the specified message.
467 * @param message the new message
468 */
469 @JsxFunction
470 public void setCustomValidity(final String message) {
471 getDomNodeOrDie().setCustomValidity(message);
472 }
473 }