1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  package org.htmlunit.html;
16  
17  import java.io.PrintWriter;
18  import java.util.Collection;
19  import java.util.Collections;
20  import java.util.HashSet;
21  import java.util.Map;
22  
23  import org.htmlunit.SgmlPage;
24  import org.htmlunit.html.impl.SelectableTextInput;
25  import org.htmlunit.html.impl.SelectableTextSelectionDelegate;
26  import org.htmlunit.javascript.host.event.Event;
27  import org.htmlunit.javascript.host.event.MouseEvent;
28  import org.htmlunit.util.NameValuePair;
29  import org.htmlunit.util.StringUtils;
30  import org.w3c.dom.Node;
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  public class HtmlTextArea extends HtmlElement implements DisabledElement, SubmittableElement,
49                  LabelableElement, SelectableTextInput, FormFieldWithNameHistory, ValidatableElement {
50      
51      public static final String TAG_NAME = "textarea";
52  
53      private String defaultValue_;
54      private String valueAtFocus_;
55      private final String originalName_;
56      private Collection<String> newNames_ = Collections.emptySet();
57      private String customValidity_;
58  
59      private SelectableTextSelectionDelegate selectionDelegate_ = new SelectableTextSelectionDelegate(this);
60      private DoTypeProcessor doTypeProcessor_ = new DoTypeProcessor(this);
61  
62      
63  
64  
65  
66  
67  
68  
69      HtmlTextArea(final String qualifiedName, final SgmlPage page,
70              final Map<String, DomAttr> attributes) {
71          super(qualifiedName, page, attributes);
72          originalName_ = getNameAttribute();
73      }
74  
75      
76  
77  
78  
79  
80      private void initDefaultValue() {
81          if (defaultValue_ == null) {
82              defaultValue_ = readValue();
83          }
84      }
85  
86      
87  
88  
89      @Override
90      public boolean handles(final Event event) {
91          if (event instanceof MouseEvent) {
92              return true;
93          }
94  
95          return super.handles(event);
96      }
97  
98      
99  
100 
101 
102 
103     @Override
104     public final String getText() {
105         return readValue();
106     }
107 
108     private String readValue() {
109         final StringBuilder builder = new StringBuilder();
110         for (final DomNode node : getChildren()) {
111             if (node instanceof DomText) {
112                 builder.append(((DomText) node).getData());
113             }
114         }
115         
116         if (builder.length() != 0 && builder.charAt(0) == '\n') {
117             builder.deleteCharAt(0);
118         }
119         return builder.toString();
120     }
121 
122     
123 
124 
125 
126 
127 
128 
129 
130     @Override
131     public final void setText(final String newValue) {
132         setTextInternal(newValue);
133 
134         HtmlInput.executeOnChangeHandlerIfAppropriate(this);
135     }
136 
137     private void setTextInternal(final String newValue) {
138         initDefaultValue();
139         DomNode child = getFirstChild();
140         if (child == null) {
141             final DomText newChild = new DomText(getPage(), newValue);
142             appendChild(newChild);
143         }
144         else {
145             DomNode next = child.getNextSibling();
146             while (next != null && !(next instanceof DomText)) {
147                 child = next;
148                 next = child.getNextSibling();
149             }
150 
151             if (next == null) {
152                 removeChild(child);
153                 final DomText newChild = new DomText(getPage(), newValue);
154                 appendChild(newChild);
155             }
156             else {
157                 ((DomText) next).setData(newValue);
158             }
159         }
160 
161         final int pos = newValue.length();
162         setSelectionStart(pos);
163         setSelectionEnd(pos);
164     }
165 
166     
167 
168 
169     @Override
170     public NameValuePair[] getSubmitNameValuePairs() {
171         String text = getText();
172         text = text.replace("\r\n", "\n").replace("\n", "\r\n");
173 
174         return new NameValuePair[]{new NameValuePair(getNameAttribute(), text)};
175     }
176 
177     
178 
179 
180 
181     @Override
182     public void reset() {
183         initDefaultValue();
184         setText(defaultValue_);
185     }
186 
187     
188 
189 
190 
191     @Override
192     public void setDefaultValue(String defaultValue) {
193         initDefaultValue();
194         if (defaultValue == null) {
195             defaultValue = "";
196         }
197 
198         
199         if (getText().equals(getDefaultValue())) {
200             setTextInternal(defaultValue);
201         }
202         defaultValue_ = defaultValue;
203     }
204 
205     
206 
207 
208 
209     @Override
210     public String getDefaultValue() {
211         initDefaultValue();
212         return defaultValue_;
213     }
214 
215     
216 
217 
218 
219 
220 
221 
222     @Override
223     public void setDefaultChecked(final boolean defaultChecked) {
224         
225     }
226 
227     
228 
229 
230 
231 
232 
233 
234     @Override
235     public boolean isDefaultChecked() {
236         return false;
237     }
238 
239     
240 
241 
242 
243 
244 
245 
246     public final String getNameAttribute() {
247         return getAttributeDirect(DomElement.NAME_ATTRIBUTE);
248     }
249 
250     
251 
252 
253 
254 
255 
256 
257     public final String getRowsAttribute() {
258         return getAttributeDirect("rows");
259     }
260 
261     
262 
263 
264 
265 
266 
267 
268     public final String getColumnsAttribute() {
269         return getAttributeDirect("cols");
270     }
271 
272     
273 
274 
275     @Override
276     public final boolean isDisabled() {
277         if (hasAttribute(ATTRIBUTE_DISABLED)) {
278             return true;
279         }
280 
281         Node node = getParentNode();
282         while (node != null) {
283             if (node instanceof DisabledElement
284                     && ((DisabledElement) node).isDisabled()) {
285                 return true;
286             }
287             node = node.getParentNode();
288         }
289 
290         return false;
291     }
292 
293     
294 
295 
296     @Override
297     public final String getDisabledAttribute() {
298         return getAttributeDirect(ATTRIBUTE_DISABLED);
299     }
300 
301     
302 
303 
304 
305 
306 
307 
308     public final String getReadOnlyAttribute() {
309         return getAttributeDirect("readonly");
310     }
311 
312     
313 
314 
315 
316 
317 
318 
319     public final String getTabIndexAttribute() {
320         return getAttributeDirect("tabindex");
321     }
322 
323     
324 
325 
326 
327 
328 
329 
330     public final String getAccessKeyAttribute() {
331         return getAttributeDirect("accesskey");
332     }
333 
334     
335 
336 
337 
338 
339 
340 
341     public final String getOnFocusAttribute() {
342         return getAttributeDirect("onfocus");
343     }
344 
345     
346 
347 
348 
349 
350 
351 
352     public final String getOnBlurAttribute() {
353         return getAttributeDirect("onblur");
354     }
355 
356     
357 
358 
359 
360 
361 
362 
363     public final String getOnSelectAttribute() {
364         return getAttributeDirect("onselect");
365     }
366 
367     
368 
369 
370 
371 
372 
373 
374     public final String getOnChangeAttribute() {
375         return getAttributeDirect("onchange");
376     }
377 
378     
379 
380 
381     @Override
382     public void select() {
383         selectionDelegate_.select();
384     }
385 
386     
387 
388 
389     @Override
390     public String getSelectedText() {
391         return selectionDelegate_.getSelectedText();
392     }
393 
394     
395 
396 
397     @Override
398     public int getSelectionStart() {
399         return selectionDelegate_.getSelectionStart();
400     }
401 
402     
403 
404 
405     @Override
406     public void setSelectionStart(final int selectionStart) {
407         selectionDelegate_.setSelectionStart(selectionStart);
408     }
409 
410     
411 
412 
413     @Override
414     public int getSelectionEnd() {
415         return selectionDelegate_.getSelectionEnd();
416     }
417 
418     
419 
420 
421     @Override
422     public void setSelectionEnd(final int selectionEnd) {
423         selectionDelegate_.setSelectionEnd(selectionEnd);
424     }
425 
426     
427 
428 
429     @Override
430     protected boolean printXml(final String indent, final boolean tagBefore, final PrintWriter printWriter) {
431         printWriter.print(indent + "<");
432         printOpeningTagContentAsXml(printWriter);
433 
434         printWriter.print(">");
435         printWriter.print(StringUtils.escapeXml(getText()));
436         printWriter.print("</textarea>");
437         return true;
438     }
439 
440     
441 
442 
443     @Override
444     protected void doType(final char c, final boolean lastType) {
445         doTypeProcessor_.doType(getText(), selectionDelegate_, c, this, lastType);
446     }
447 
448     
449 
450 
451     @Override
452     protected void doType(final int keyCode, final boolean lastType) {
453         doTypeProcessor_.doType(getText(), selectionDelegate_, keyCode, this, lastType);
454     }
455 
456     
457 
458 
459     @Override
460     protected void typeDone(final String newValue, final boolean notifyAttributeChangeListeners) {
461         setTextInternal(newValue);
462     }
463 
464     
465 
466 
467     @Override
468     protected boolean acceptChar(final char c) {
469         return super.acceptChar(c) || c == '\n' || c == '\r';
470     }
471 
472     
473 
474 
475     @Override
476     public void focus() {
477         super.focus();
478         valueAtFocus_ = getText();
479     }
480 
481     
482 
483 
484     @Override
485     public void removeFocus() {
486         super.removeFocus();
487         if (valueAtFocus_ != null && !valueAtFocus_.equals(getText())) {
488             HtmlInput.executeOnChangeHandlerIfAppropriate(this);
489         }
490         valueAtFocus_ = null;
491     }
492 
493     
494 
495 
496 
497 
498     public void setReadOnly(final boolean isReadOnly) {
499         if (isReadOnly) {
500             setAttribute("readOnly", "readOnly");
501         }
502         else {
503             removeAttribute("readOnly");
504         }
505     }
506 
507     
508 
509 
510 
511     public boolean isReadOnly() {
512         return hasAttribute("readOnly");
513     }
514 
515     
516 
517 
518     @Override
519     protected void setAttributeNS(final String namespaceURI, final String qualifiedName, final String attributeValue,
520             final boolean notifyAttributeChangeListeners, final boolean notifyMutationObservers) {
521         final String qualifiedNameLC = StringUtils.toRootLowerCase(qualifiedName);
522         if (DomElement.NAME_ATTRIBUTE.equals(qualifiedNameLC)) {
523             if (newNames_.isEmpty()) {
524                 newNames_ = new HashSet<>();
525             }
526             newNames_.add(attributeValue);
527         }
528         super.setAttributeNS(namespaceURI, qualifiedNameLC, attributeValue, notifyAttributeChangeListeners,
529                 notifyMutationObservers);
530     }
531 
532     
533 
534 
535     @Override
536     public String getOriginalName() {
537         return originalName_;
538     }
539 
540     
541 
542 
543     @Override
544     public Collection<String> getNewNames() {
545         return newNames_;
546     }
547 
548     
549 
550 
551 
552     @Override
553     protected boolean isEmptyXmlTagExpanded() {
554         return true;
555     }
556 
557     
558 
559 
560     @Override
561     public DisplayStyle getDefaultStyleDisplay() {
562         return DisplayStyle.INLINE_BLOCK;
563     }
564 
565     
566 
567 
568 
569 
570     public String getPlaceholder() {
571         return getAttributeDirect("placeholder");
572     }
573 
574     
575 
576 
577 
578 
579     public void setPlaceholder(final String placeholder) {
580         setAttribute("placeholder", placeholder);
581     }
582 
583     
584 
585 
586     @Override
587     protected boolean isRequiredSupported() {
588         return true;
589     }
590 
591     
592 
593 
594     @Override
595     public DomNode cloneNode(final boolean deep) {
596         final HtmlTextArea newnode = (HtmlTextArea) super.cloneNode(deep);
597         newnode.selectionDelegate_ = new SelectableTextSelectionDelegate(newnode);
598         newnode.doTypeProcessor_ = new DoTypeProcessor(newnode);
599         newnode.newNames_ = new HashSet<>(newNames_);
600 
601         return newnode;
602     }
603 
604     
605 
606 
607     @Override
608     public boolean willValidate() {
609         return !isDisabled() && !isReadOnly();
610     }
611 
612     
613 
614 
615     @Override
616     public void setCustomValidity(final String message) {
617         customValidity_ = message;
618     }
619 
620     
621 
622 
623     @Override
624     public boolean isValid() {
625         return isValidValidityState();
626     }
627 
628     
629 
630 
631     @Override
632     public boolean isCustomErrorValidityState() {
633         return !StringUtils.isEmptyOrNull(customValidity_);
634     }
635 
636     @Override
637     public boolean isValidValidityState() {
638         return !isCustomErrorValidityState()
639                 && !isValueMissingValidityState();
640     }
641 
642     
643 
644 
645     @Override
646     public boolean isValueMissingValidityState() {
647         return ATTRIBUTE_NOT_DEFINED != getAttributeDirect(ATTRIBUTE_REQUIRED)
648                 && getText().isEmpty();
649     }
650 }