Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/html/HTMLTextAreaElement.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/dom/HTMLTextAreaElement.h"
8
9
#include "mozAutoDocUpdate.h"
10
#include "mozilla/AsyncEventDispatcher.h"
11
#include "mozilla/Attributes.h"
12
#include "mozilla/dom/HTMLFormSubmission.h"
13
#include "mozilla/dom/HTMLTextAreaElementBinding.h"
14
#include "mozilla/EventDispatcher.h"
15
#include "mozilla/EventStates.h"
16
#include "mozilla/MappedDeclarations.h"
17
#include "mozilla/MouseEvents.h"
18
#include "nsAttrValueInlines.h"
19
#include "nsContentCID.h"
20
#include "nsContentCreatorFunctions.h"
21
#include "nsError.h"
22
#include "nsFocusManager.h"
23
#include "nsIComponentManager.h"
24
#include "nsIConstraintValidation.h"
25
#include "nsIControllers.h"
26
#include "nsIDocument.h"
27
#include "nsIFormControlFrame.h"
28
#include "nsIFormControl.h"
29
#include "nsIForm.h"
30
#include "nsIFrame.h"
31
#include "nsISupportsPrimitives.h"
32
#include "nsITextControlFrame.h"
33
#include "nsLayoutUtils.h"
34
#include "nsLinebreakConverter.h"
35
#include "nsMappedAttributes.h"
36
#include "nsPIDOMWindow.h"
37
#include "nsPresContext.h"
38
#include "mozilla/PresState.h"
39
#include "nsReadableUtils.h"
40
#include "nsStyleConsts.h"
41
#include "nsTextEditorState.h"
42
#include "nsIController.h"
43
#include "nsBaseCommandController.h"
44
#include "nsXULControllers.h"
45
46
0
#define NS_NO_CONTENT_DISPATCH (1 << 0)
47
48
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(TextArea)
49
50
namespace mozilla {
51
namespace dom {
52
53
HTMLTextAreaElement::HTMLTextAreaElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
54
                                         FromParser aFromParser)
55
  : nsGenericHTMLFormElementWithState(std::move(aNodeInfo), NS_FORM_TEXTAREA),
56
    mValueChanged(false),
57
    mLastValueChangeWasInteractive(false),
58
    mHandlingSelect(false),
59
    mDoneAddingChildren(!aFromParser),
60
    mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
61
    mDisabledChanged(false),
62
    mCanShowInvalidUI(true),
63
    mCanShowValidUI(true),
64
    mIsPreviewEnabled(false),
65
    mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
66
    mState(this)
67
0
{
68
0
  AddMutationObserver(this);
69
0
70
0
  // Set up our default state.  By default we're enabled (since we're
71
0
  // a control type that can be disabled but not actually disabled
72
0
  // right now), optional, and valid.  We are NOT readwrite by default
73
0
  // until someone calls UpdateEditableState on us, apparently!  Also
74
0
  // by default we don't have to show validity UI and so forth.
75
0
  AddStatesSilently(NS_EVENT_STATE_ENABLED |
76
0
                    NS_EVENT_STATE_OPTIONAL |
77
0
                    NS_EVENT_STATE_VALID);
78
0
}
79
80
81
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLTextAreaElement,
82
                                   nsGenericHTMLFormElementWithState,
83
                                   mValidity,
84
                                   mControllers,
85
                                   mState)
86
87
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLTextAreaElement,
88
                                             nsGenericHTMLFormElementWithState,
89
                                             nsITextControlElement,
90
                                             nsIMutationObserver,
91
                                             nsIConstraintValidation)
92
93
// nsIDOMHTMLTextAreaElement
94
95
nsresult
96
HTMLTextAreaElement::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const
97
0
{
98
0
  *aResult = nullptr;
99
0
  RefPtr<HTMLTextAreaElement> it =
100
0
    new HTMLTextAreaElement(do_AddRef(aNodeInfo));
101
0
102
0
  nsresult rv = const_cast<HTMLTextAreaElement*>(this)->CopyInnerTo(it);
103
0
  NS_ENSURE_SUCCESS(rv, rv);
104
0
105
0
  if (mValueChanged) {
106
0
    // Set our value on the clone.
107
0
    nsAutoString value;
108
0
    GetValueInternal(value, true);
109
0
110
0
    // SetValueInternal handles setting mValueChanged for us
111
0
    rv = it->SetValueInternal(value, nsTextEditorState::eSetValue_Notify);
112
0
    NS_ENSURE_SUCCESS(rv, rv);
113
0
  }
114
0
115
0
  it->mLastValueChangeWasInteractive = mLastValueChangeWasInteractive;
116
0
  it.forget(aResult);
117
0
  return NS_OK;
118
0
}
119
120
// nsIContent
121
122
void
123
HTMLTextAreaElement::Select()
124
0
{
125
0
  // XXX Bug?  We have to give the input focus before contents can be
126
0
  // selected
127
0
128
0
  FocusTristate state = FocusState();
129
0
  if (state == eUnfocusable) {
130
0
    return;
131
0
  }
132
0
133
0
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
134
0
135
0
  RefPtr<nsPresContext> presContext = GetPresContext(eForComposedDoc);
136
0
  if (state == eInactiveWindow) {
137
0
    if (fm)
138
0
      fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
139
0
    SelectAll(presContext);
140
0
    return;
141
0
  }
142
0
143
0
  nsEventStatus status = nsEventStatus_eIgnore;
144
0
  WidgetGUIEvent event(true, eFormSelect, nullptr);
145
0
  // XXXbz HTMLInputElement guards against this reentering; shouldn't we?
146
0
  EventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext,
147
0
                            &event, nullptr, &status);
148
0
149
0
  // If the DOM event was not canceled (e.g. by a JS event handler
150
0
  // returning false)
151
0
  if (status == nsEventStatus_eIgnore) {
152
0
    if (fm) {
153
0
      fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
154
0
155
0
      // ensure that the element is actually focused
156
0
      if (this == fm->GetFocusedElement()) {
157
0
        // Now Select all the text!
158
0
        SelectAll(presContext);
159
0
      }
160
0
    }
161
0
  }
162
0
}
163
164
NS_IMETHODIMP
165
HTMLTextAreaElement::SelectAll(nsPresContext* aPresContext)
166
0
{
167
0
  nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
168
0
169
0
  if (formControlFrame) {
170
0
    formControlFrame->SetFormProperty(nsGkAtoms::select, EmptyString());
171
0
  }
172
0
173
0
  return NS_OK;
174
0
}
175
176
bool
177
HTMLTextAreaElement::IsHTMLFocusable(bool aWithMouse,
178
                                     bool *aIsFocusable, int32_t *aTabIndex)
179
0
{
180
0
  if (nsGenericHTMLFormElementWithState::IsHTMLFocusable(aWithMouse, aIsFocusable,
181
0
                                                         aTabIndex))
182
0
  {
183
0
    return true;
184
0
  }
185
0
186
0
  // disabled textareas are not focusable
187
0
  *aIsFocusable = !IsDisabled();
188
0
  return false;
189
0
}
190
191
int32_t
192
HTMLTextAreaElement::TabIndexDefault()
193
0
{
194
0
  return 0;
195
0
}
196
197
void
198
HTMLTextAreaElement::GetType(nsAString& aType)
199
0
{
200
0
  aType.AssignLiteral("textarea");
201
0
}
202
203
void
204
HTMLTextAreaElement::GetValue(nsAString& aValue)
205
0
{
206
0
  nsAutoString value;
207
0
  GetValueInternal(value, true);
208
0
209
0
  // Normalize CRLF and CR to LF
210
0
  nsContentUtils::PlatformToDOMLineBreaks(value);
211
0
212
0
  aValue = value;
213
0
}
214
215
void
216
HTMLTextAreaElement::GetValueInternal(nsAString& aValue, bool aIgnoreWrap) const
217
0
{
218
0
  mState.GetValue(aValue, aIgnoreWrap);
219
0
}
220
221
NS_IMETHODIMP_(TextEditor*)
222
HTMLTextAreaElement::GetTextEditor()
223
0
{
224
0
  return mState.GetTextEditor();
225
0
}
226
227
NS_IMETHODIMP_(nsISelectionController*)
228
HTMLTextAreaElement::GetSelectionController()
229
0
{
230
0
  return mState.GetSelectionController();
231
0
}
232
233
NS_IMETHODIMP_(nsFrameSelection*)
234
HTMLTextAreaElement::GetConstFrameSelection()
235
0
{
236
0
  return mState.GetConstFrameSelection();
237
0
}
238
239
NS_IMETHODIMP
240
HTMLTextAreaElement::BindToFrame(nsTextControlFrame* aFrame)
241
0
{
242
0
  return mState.BindToFrame(aFrame);
243
0
}
244
245
NS_IMETHODIMP_(void)
246
HTMLTextAreaElement::UnbindFromFrame(nsTextControlFrame* aFrame)
247
0
{
248
0
  if (aFrame) {
249
0
    mState.UnbindFromFrame(aFrame);
250
0
  }
251
0
}
252
253
NS_IMETHODIMP
254
HTMLTextAreaElement::CreateEditor()
255
0
{
256
0
  return mState.PrepareEditor();
257
0
}
258
259
NS_IMETHODIMP_(void)
260
HTMLTextAreaElement::UpdateOverlayTextVisibility(bool aNotify)
261
0
{
262
0
  mState.UpdateOverlayTextVisibility(aNotify);
263
0
}
264
265
NS_IMETHODIMP_(bool)
266
HTMLTextAreaElement::GetPlaceholderVisibility()
267
0
{
268
0
  return mState.GetPlaceholderVisibility();
269
0
}
270
271
NS_IMETHODIMP_(void)
272
HTMLTextAreaElement::SetPreviewValue(const nsAString& aValue)
273
0
{
274
0
  mState.SetPreviewText(aValue, true);
275
0
}
276
277
NS_IMETHODIMP_(void)
278
HTMLTextAreaElement::GetPreviewValue(nsAString& aValue)
279
0
{
280
0
  mState.GetPreviewText(aValue);
281
0
}
282
283
NS_IMETHODIMP_(void)
284
HTMLTextAreaElement::EnablePreview()
285
0
{
286
0
  if (mIsPreviewEnabled) {
287
0
    return;
288
0
  }
289
0
290
0
  mIsPreviewEnabled = true;
291
0
  // Reconstruct the frame to append an anonymous preview node
292
0
  nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), nsChangeHint_ReconstructFrame);
293
0
}
294
295
NS_IMETHODIMP_(bool)
296
HTMLTextAreaElement::IsPreviewEnabled()
297
0
{
298
0
  return mIsPreviewEnabled;
299
0
}
300
301
NS_IMETHODIMP_(bool)
302
HTMLTextAreaElement::GetPreviewVisibility()
303
0
{
304
0
  return mState.GetPreviewVisibility();
305
0
}
306
307
nsresult
308
HTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
309
                                      uint32_t aFlags)
310
0
{
311
0
  // Need to set the value changed flag here if our value has in fact changed
312
0
  // (i.e. if eSetValue_Notify is in aFlags), so that
313
0
  // nsTextControlFrame::UpdateValueDisplay retrieves the correct value if
314
0
  // needed.
315
0
  if (aFlags & nsTextEditorState::eSetValue_Notify) {
316
0
    SetValueChanged(true);
317
0
  }
318
0
319
0
  if (!mState.SetValue(aValue, aFlags)) {
320
0
    return NS_ERROR_OUT_OF_MEMORY;
321
0
  }
322
0
323
0
  return NS_OK;
324
0
}
325
326
void
327
HTMLTextAreaElement::SetValue(const nsAString& aValue, ErrorResult& aError)
328
0
{
329
0
  // If the value has been set by a script, we basically want to keep the
330
0
  // current change event state. If the element is ready to fire a change
331
0
  // event, we should keep it that way. Otherwise, we should make sure the
332
0
  // element will not fire any event because of the script interaction.
333
0
  //
334
0
  // NOTE: this is currently quite expensive work (too much string
335
0
  // manipulation). We should probably optimize that.
336
0
  nsAutoString currentValue;
337
0
  GetValueInternal(currentValue, true);
338
0
339
0
  nsresult rv =
340
0
    SetValueInternal(aValue,
341
0
      nsTextEditorState::eSetValue_ByContent |
342
0
      nsTextEditorState::eSetValue_Notify |
343
0
      nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
344
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
345
0
    aError.Throw(rv);
346
0
    return;
347
0
  }
348
0
349
0
  if (mFocusedValue.Equals(currentValue)) {
350
0
    GetValueInternal(mFocusedValue, true);
351
0
  }
352
0
}
353
354
void HTMLTextAreaElement::SetUserInput(const nsAString& aValue,
355
                                       nsIPrincipal& aSubjectPrincipal)
356
0
{
357
0
  SetValueInternal(aValue,
358
0
    nsTextEditorState::eSetValue_BySetUserInput |
359
0
    nsTextEditorState::eSetValue_Notify|
360
0
    nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
361
0
}
362
363
NS_IMETHODIMP
364
HTMLTextAreaElement::SetValueChanged(bool aValueChanged)
365
0
{
366
0
  bool previousValue = mValueChanged;
367
0
368
0
  mValueChanged = aValueChanged;
369
0
  if (!aValueChanged && !mState.IsEmpty()) {
370
0
    mState.EmptyValue();
371
0
  }
372
0
373
0
  if (mValueChanged != previousValue) {
374
0
    UpdateState(true);
375
0
  }
376
0
377
0
  return NS_OK;
378
0
}
379
380
void
381
HTMLTextAreaElement::GetDefaultValue(nsAString& aDefaultValue, ErrorResult& aError)
382
0
{
383
0
  if (!nsContentUtils::GetNodeTextContent(this, false, aDefaultValue, fallible)) {
384
0
    aError.Throw(NS_ERROR_OUT_OF_MEMORY);
385
0
  }
386
0
}
387
388
void
389
HTMLTextAreaElement::SetDefaultValue(const nsAString& aDefaultValue, ErrorResult& aError)
390
0
{
391
0
  nsresult rv = nsContentUtils::SetNodeTextContent(this, aDefaultValue, true);
392
0
  if (NS_SUCCEEDED(rv) && !mValueChanged) {
393
0
    Reset();
394
0
  }
395
0
  if (NS_FAILED(rv)) {
396
0
    aError.Throw(rv);
397
0
  }
398
0
}
399
400
bool
401
HTMLTextAreaElement::ParseAttribute(int32_t aNamespaceID,
402
                                    nsAtom* aAttribute,
403
                                    const nsAString& aValue,
404
                                    nsIPrincipal* aMaybeScriptedPrincipal,
405
                                    nsAttrValue& aResult)
406
0
{
407
0
  if (aNamespaceID == kNameSpaceID_None) {
408
0
    if (aAttribute == nsGkAtoms::maxlength ||
409
0
        aAttribute == nsGkAtoms::minlength) {
410
0
      return aResult.ParseNonNegativeIntValue(aValue);
411
0
    } else if (aAttribute == nsGkAtoms::cols) {
412
0
      aResult.ParseIntWithFallback(aValue, DEFAULT_COLS);
413
0
      return true;
414
0
    } else if (aAttribute == nsGkAtoms::rows) {
415
0
      aResult.ParseIntWithFallback(aValue, DEFAULT_ROWS_TEXTAREA);
416
0
      return true;
417
0
    } else if (aAttribute == nsGkAtoms::autocomplete) {
418
0
      aResult.ParseAtomArray(aValue);
419
0
      return true;
420
0
    }
421
0
  }
422
0
  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
423
0
                                              aMaybeScriptedPrincipal, aResult);
424
0
}
425
426
void
427
HTMLTextAreaElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
428
                                           MappedDeclarations& aDecls)
429
0
{
430
0
  // wrap=off
431
0
  if (!aDecls.PropertyIsSet(eCSSProperty_white_space)) {
432
0
    const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::wrap);
433
0
    if (value && value->Type() == nsAttrValue::eString &&
434
0
        value->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
435
0
      aDecls.SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Pre);
436
0
    }
437
0
  }
438
0
439
0
  nsGenericHTMLFormElementWithState::MapDivAlignAttributeInto(aAttributes, aDecls);
440
0
  nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aDecls);
441
0
}
442
443
nsChangeHint
444
HTMLTextAreaElement::GetAttributeChangeHint(const nsAtom* aAttribute,
445
                                            int32_t aModType) const
446
0
{
447
0
  nsChangeHint retval =
448
0
      nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
449
0
  if (aAttribute == nsGkAtoms::rows ||
450
0
      aAttribute == nsGkAtoms::cols) {
451
0
    retval |= NS_STYLE_HINT_REFLOW;
452
0
  } else if (aAttribute == nsGkAtoms::wrap) {
453
0
    retval |= nsChangeHint_ReconstructFrame;
454
0
  } else if (aAttribute == nsGkAtoms::placeholder) {
455
0
    retval |= nsChangeHint_ReconstructFrame;
456
0
  }
457
0
  return retval;
458
0
}
459
460
NS_IMETHODIMP_(bool)
461
HTMLTextAreaElement::IsAttributeMapped(const nsAtom* aAttribute) const
462
0
{
463
0
  static const MappedAttributeEntry attributes[] = {
464
0
    { &nsGkAtoms::wrap },
465
0
    { nullptr }
466
0
  };
467
0
468
0
  static const MappedAttributeEntry* const map[] = {
469
0
    attributes,
470
0
    sDivAlignAttributeMap,
471
0
    sCommonAttributeMap,
472
0
  };
473
0
474
0
  return FindAttributeDependence(aAttribute, map);
475
0
}
476
477
nsMapRuleToAttributesFunc
478
HTMLTextAreaElement::GetAttributeMappingFunction() const
479
0
{
480
0
  return &MapAttributesIntoRule;
481
0
}
482
483
bool
484
HTMLTextAreaElement::IsDisabledForEvents(EventMessage aMessage)
485
0
{
486
0
  nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
487
0
  nsIFrame* formFrame = do_QueryFrame(formControlFrame);
488
0
  return IsElementDisabledForEvents(aMessage, formFrame);
489
0
}
490
491
void
492
HTMLTextAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
493
0
{
494
0
  aVisitor.mCanHandle = false;
495
0
  if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
496
0
    return;
497
0
  }
498
0
499
0
  // Don't dispatch a second select event if we are already handling
500
0
  // one.
501
0
  if (aVisitor.mEvent->mMessage == eFormSelect) {
502
0
    if (mHandlingSelect) {
503
0
      return;
504
0
    }
505
0
    mHandlingSelect = true;
506
0
  }
507
0
508
0
  // If noContentDispatch is true we will not allow content to handle
509
0
  // this event.  But to allow middle mouse button paste to work we must allow
510
0
  // middle clicks to go to text fields anyway.
511
0
  if (aVisitor.mEvent->mFlags.mNoContentDispatch) {
512
0
    aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH;
513
0
  }
514
0
  if (aVisitor.mEvent->mMessage == eMouseClick &&
515
0
      aVisitor.mEvent->AsMouseEvent()->button ==
516
0
        WidgetMouseEvent::eMiddleButton) {
517
0
    aVisitor.mEvent->mFlags.mNoContentDispatch = false;
518
0
  }
519
0
520
0
  if (aVisitor.mEvent->mMessage == eBlur) {
521
0
    // Set mWantsPreHandleEvent and fire change event in PreHandleEvent to
522
0
    // prevent it breaks event target chain creation.
523
0
    aVisitor.mWantsPreHandleEvent = true;
524
0
  }
525
0
526
0
  nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
527
0
}
528
529
nsresult
530
HTMLTextAreaElement::PreHandleEvent(EventChainVisitor& aVisitor)
531
0
{
532
0
  if (aVisitor.mEvent->mMessage == eBlur) {
533
0
    // Fire onchange (if necessary), before we do the blur, bug 370521.
534
0
    FireChangeEventIfNeeded();
535
0
  }
536
0
  return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
537
0
}
538
539
void
540
HTMLTextAreaElement::FireChangeEventIfNeeded()
541
0
{
542
0
  nsString value;
543
0
  GetValueInternal(value, true);
544
0
545
0
  if (mFocusedValue.Equals(value)) {
546
0
    return;
547
0
  }
548
0
549
0
  // Dispatch the change event.
550
0
  mFocusedValue = value;
551
0
  nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
552
0
                                       static_cast<nsIContent*>(this),
553
0
                                       NS_LITERAL_STRING("change"),
554
0
                                       CanBubble::eYes,
555
0
                                       Cancelable::eNo);
556
0
}
557
558
nsresult
559
HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
560
0
{
561
0
  if (aVisitor.mEvent->mMessage == eFormSelect) {
562
0
    mHandlingSelect = false;
563
0
  }
564
0
565
0
  if (aVisitor.mEvent->mMessage == eFocus ||
566
0
      aVisitor.mEvent->mMessage == eBlur) {
567
0
    if (aVisitor.mEvent->mMessage == eFocus) {
568
0
      // If the invalid UI is shown, we should show it while focusing (and
569
0
      // update). Otherwise, we should not.
570
0
      GetValueInternal(mFocusedValue, true);
571
0
      mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
572
0
573
0
      // If neither invalid UI nor valid UI is shown, we shouldn't show the valid
574
0
      // UI while typing.
575
0
      mCanShowValidUI = ShouldShowValidityUI();
576
0
    } else { // eBlur
577
0
      mCanShowInvalidUI = true;
578
0
      mCanShowValidUI = true;
579
0
    }
580
0
581
0
    UpdateState(true);
582
0
  }
583
0
584
0
  // Reset the flag for other content besides this text field
585
0
  aVisitor.mEvent->mFlags.mNoContentDispatch =
586
0
    ((aVisitor.mItemFlags & NS_NO_CONTENT_DISPATCH) != 0);
587
0
588
0
  return NS_OK;
589
0
}
590
591
void
592
HTMLTextAreaElement::DoneAddingChildren(bool aHaveNotified)
593
0
{
594
0
  if (!mValueChanged) {
595
0
    if (!mDoneAddingChildren) {
596
0
      // Reset now that we're done adding children if the content sink tried to
597
0
      // sneak some text in without calling AppendChildTo.
598
0
      Reset();
599
0
    }
600
0
601
0
    if (!mInhibitStateRestoration) {
602
0
      nsresult rv = GenerateStateKey();
603
0
      if (NS_SUCCEEDED(rv)) {
604
0
        RestoreFormControlState();
605
0
      }
606
0
    }
607
0
  }
608
0
609
0
  mDoneAddingChildren = true;
610
0
}
611
612
bool
613
HTMLTextAreaElement::IsDoneAddingChildren()
614
0
{
615
0
  return mDoneAddingChildren;
616
0
}
617
618
// Controllers Methods
619
620
nsIControllers*
621
HTMLTextAreaElement::GetControllers(ErrorResult& aError)
622
0
{
623
0
  if (!mControllers)
624
0
  {
625
0
    mControllers = new nsXULControllers();
626
0
    if (!mControllers) {
627
0
      aError.Throw(NS_ERROR_FAILURE);
628
0
      return nullptr;
629
0
    }
630
0
631
0
    nsCOMPtr<nsIController> controller =
632
0
      nsBaseCommandController::CreateEditorController();
633
0
    if (!controller) {
634
0
      aError.Throw(NS_ERROR_FAILURE);
635
0
      return nullptr;
636
0
    }
637
0
638
0
    mControllers->AppendController(controller);
639
0
640
0
    controller = nsBaseCommandController::CreateEditingController();
641
0
    if (!controller) {
642
0
      aError.Throw(NS_ERROR_FAILURE);
643
0
      return nullptr;
644
0
    }
645
0
646
0
    mControllers->AppendController(controller);
647
0
  }
648
0
649
0
  return mControllers;
650
0
}
651
652
nsresult
653
HTMLTextAreaElement::GetControllers(nsIControllers** aResult)
654
0
{
655
0
  NS_ENSURE_ARG_POINTER(aResult);
656
0
657
0
  ErrorResult error;
658
0
  *aResult = GetControllers(error);
659
0
  NS_IF_ADDREF(*aResult);
660
0
661
0
  return error.StealNSResult();
662
0
}
663
664
uint32_t
665
HTMLTextAreaElement::GetTextLength()
666
0
{
667
0
  nsAutoString val;
668
0
  GetValue(val);
669
0
  return val.Length();
670
0
}
671
672
Nullable<uint32_t>
673
HTMLTextAreaElement::GetSelectionStart(ErrorResult& aError)
674
0
{
675
0
  uint32_t selStart, selEnd;
676
0
  GetSelectionRange(&selStart, &selEnd, aError);
677
0
  return Nullable<uint32_t>(selStart);
678
0
}
679
680
void
681
HTMLTextAreaElement::SetSelectionStart(const Nullable<uint32_t>& aSelectionStart,
682
                                       ErrorResult& aError)
683
0
{
684
0
  mState.SetSelectionStart(aSelectionStart, aError);
685
0
}
686
687
Nullable<uint32_t>
688
HTMLTextAreaElement::GetSelectionEnd(ErrorResult& aError)
689
0
{
690
0
  uint32_t selStart, selEnd;
691
0
  GetSelectionRange(&selStart, &selEnd, aError);
692
0
  return Nullable<uint32_t>(selEnd);
693
0
}
694
695
void
696
HTMLTextAreaElement::SetSelectionEnd(const Nullable<uint32_t>& aSelectionEnd,
697
                                     ErrorResult& aError)
698
0
{
699
0
  mState.SetSelectionEnd(aSelectionEnd, aError);
700
0
}
701
702
void
703
HTMLTextAreaElement::GetSelectionRange(uint32_t* aSelectionStart,
704
                                       uint32_t* aSelectionEnd,
705
                                       ErrorResult& aRv)
706
0
{
707
0
  return mState.GetSelectionRange(aSelectionStart, aSelectionEnd, aRv);
708
0
}
709
710
void
711
HTMLTextAreaElement::GetSelectionDirection(nsAString& aDirection, ErrorResult& aError)
712
0
{
713
0
  mState.GetSelectionDirectionString(aDirection, aError);
714
0
}
715
716
void
717
HTMLTextAreaElement::SetSelectionDirection(const nsAString& aDirection,
718
                                           ErrorResult& aError)
719
0
{
720
0
  mState.SetSelectionDirection(aDirection, aError);
721
0
}
722
723
void
724
HTMLTextAreaElement::SetSelectionRange(uint32_t aSelectionStart,
725
                                       uint32_t aSelectionEnd,
726
                                       const Optional<nsAString>& aDirection,
727
                                       ErrorResult& aError)
728
0
{
729
0
  mState.SetSelectionRange(aSelectionStart, aSelectionEnd,
730
0
                           aDirection, aError);
731
0
}
732
733
void
734
HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
735
                                  ErrorResult& aRv)
736
0
{
737
0
  mState.SetRangeText(aReplacement, aRv);
738
0
}
739
740
void
741
HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
742
                                  uint32_t aStart, uint32_t aEnd,
743
                                  SelectionMode aSelectMode,
744
                                  ErrorResult& aRv)
745
0
{
746
0
  mState.SetRangeText(aReplacement, aStart, aEnd, aSelectMode, aRv);
747
0
}
748
749
void
750
HTMLTextAreaElement::GetValueFromSetRangeText(nsAString& aValue)
751
0
{
752
0
  GetValueInternal(aValue, false);
753
0
}
754
755
nsresult
756
HTMLTextAreaElement::SetValueFromSetRangeText(const nsAString& aValue)
757
0
{
758
0
  return SetValueInternal(aValue,
759
0
                          nsTextEditorState::eSetValue_ByContent |
760
0
                          nsTextEditorState::eSetValue_Notify);
761
0
}
762
763
nsresult
764
HTMLTextAreaElement::Reset()
765
0
{
766
0
  nsAutoString resetVal;
767
0
  GetDefaultValue(resetVal, IgnoreErrors());
768
0
  SetValueChanged(false);
769
0
770
0
  nsresult rv = SetValueInternal(resetVal,
771
0
                                 nsTextEditorState::eSetValue_Internal);
772
0
  NS_ENSURE_SUCCESS(rv, rv);
773
0
774
0
  return NS_OK;
775
0
}
776
777
NS_IMETHODIMP
778
HTMLTextAreaElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
779
0
{
780
0
  // Disabled elements don't submit
781
0
  if (IsDisabled()) {
782
0
    return NS_OK;
783
0
  }
784
0
785
0
  //
786
0
  // Get the name (if no name, no submit)
787
0
  //
788
0
  nsAutoString name;
789
0
  GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
790
0
  if (name.IsEmpty()) {
791
0
    return NS_OK;
792
0
  }
793
0
794
0
  //
795
0
  // Get the value
796
0
  //
797
0
  nsAutoString value;
798
0
  GetValueInternal(value, false);
799
0
800
0
  //
801
0
  // Submit
802
0
  //
803
0
  return aFormSubmission->AddNameValuePair(name, value);
804
0
}
805
806
NS_IMETHODIMP
807
HTMLTextAreaElement::SaveState()
808
0
{
809
0
  nsresult rv = NS_OK;
810
0
811
0
  // Only save if value != defaultValue (bug 62713)
812
0
  PresState *state = nullptr;
813
0
  if (mValueChanged) {
814
0
    state = GetPrimaryPresState();
815
0
    if (state) {
816
0
      nsAutoString value;
817
0
      GetValueInternal(value, true);
818
0
819
0
      rv = nsLinebreakConverter::ConvertStringLineBreaks(
820
0
               value,
821
0
               nsLinebreakConverter::eLinebreakPlatform,
822
0
               nsLinebreakConverter::eLinebreakContent);
823
0
824
0
      if (NS_FAILED(rv)) {
825
0
        NS_ERROR("Converting linebreaks failed!");
826
0
        return rv;
827
0
      }
828
0
829
0
      state->contentData() = std::move(value);
830
0
    }
831
0
  }
832
0
833
0
  if (mDisabledChanged) {
834
0
    if (!state) {
835
0
      state = GetPrimaryPresState();
836
0
      rv = NS_OK;
837
0
    }
838
0
    if (state) {
839
0
      // We do not want to save the real disabled state but the disabled
840
0
      // attribute.
841
0
      state->disabled() = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
842
0
      state->disabledSet() = true;
843
0
    }
844
0
  }
845
0
  return rv;
846
0
}
847
848
bool
849
HTMLTextAreaElement::RestoreState(PresState* aState)
850
0
{
851
0
  const PresContentData& state = aState->contentData();
852
0
853
0
  if (state.type() == PresContentData::TnsString) {
854
0
    ErrorResult rv;
855
0
    SetValue(state.get_nsString(), rv);
856
0
    ENSURE_SUCCESS(rv, false);
857
0
  }
858
0
859
0
  if (aState->disabledSet() && !aState->disabled()) {
860
0
    SetDisabled(false, IgnoreErrors());
861
0
  }
862
0
863
0
  return false;
864
0
}
865
866
EventStates
867
HTMLTextAreaElement::IntrinsicState() const
868
0
{
869
0
  EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
870
0
871
0
  if (IsCandidateForConstraintValidation()) {
872
0
    if (IsValid()) {
873
0
      state |= NS_EVENT_STATE_VALID;
874
0
    } else {
875
0
      state |= NS_EVENT_STATE_INVALID;
876
0
      // :-moz-ui-invalid always apply if the element suffers from a custom
877
0
      // error and never applies if novalidate is set on the form owner.
878
0
      if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
879
0
          (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
880
0
           (mCanShowInvalidUI && ShouldShowValidityUI()))) {
881
0
        state |= NS_EVENT_STATE_MOZ_UI_INVALID;
882
0
      }
883
0
    }
884
0
885
0
    // :-moz-ui-valid applies if all the following are true:
886
0
    // 1. The element is not focused, or had either :-moz-ui-valid or
887
0
    //    :-moz-ui-invalid applying before it was focused ;
888
0
    // 2. The element is either valid or isn't allowed to have
889
0
    //    :-moz-ui-invalid applying ;
890
0
    // 3. The element has no form owner or its form owner doesn't have the
891
0
    //    novalidate attribute set ;
892
0
    // 4. The element has already been modified or the user tried to submit the
893
0
    //    form owner while invalid.
894
0
    if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
895
0
        (mCanShowValidUI && ShouldShowValidityUI() &&
896
0
         (IsValid() || (state.HasState(NS_EVENT_STATE_MOZ_UI_INVALID) &&
897
0
                        !mCanShowInvalidUI)))) {
898
0
      state |= NS_EVENT_STATE_MOZ_UI_VALID;
899
0
    }
900
0
  }
901
0
902
0
  if (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder) &&
903
0
      IsValueEmpty()) {
904
0
    state |= NS_EVENT_STATE_PLACEHOLDERSHOWN;
905
0
  }
906
0
907
0
  return state;
908
0
}
909
910
nsresult
911
HTMLTextAreaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
912
                                nsIContent* aBindingParent)
913
0
{
914
0
  nsresult rv = nsGenericHTMLFormElementWithState::BindToTree(aDocument, aParent,
915
0
                                                              aBindingParent);
916
0
  NS_ENSURE_SUCCESS(rv, rv);
917
0
918
0
  // If there is a disabled fieldset in the parent chain, the element is now
919
0
  // barred from constraint validation and can't suffer from value missing.
920
0
  UpdateValueMissingValidityState();
921
0
  UpdateBarredFromConstraintValidation();
922
0
923
0
  // And now make sure our state is up to date
924
0
  UpdateState(false);
925
0
926
0
  return rv;
927
0
}
928
929
void
930
HTMLTextAreaElement::UnbindFromTree(bool aDeep, bool aNullParent)
931
0
{
932
0
  nsGenericHTMLFormElementWithState::UnbindFromTree(aDeep, aNullParent);
933
0
934
0
  // We might be no longer disabled because of parent chain changed.
935
0
  UpdateValueMissingValidityState();
936
0
  UpdateBarredFromConstraintValidation();
937
0
938
0
  // And now make sure our state is up to date
939
0
  UpdateState(false);
940
0
}
941
942
nsresult
943
HTMLTextAreaElement::BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
944
                                   const nsAttrValueOrString* aValue,
945
                                   bool aNotify)
946
0
{
947
0
  if (aNotify && aName == nsGkAtoms::disabled &&
948
0
      aNameSpaceID == kNameSpaceID_None) {
949
0
    mDisabledChanged = true;
950
0
  }
951
0
952
0
  return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
953
0
                                                 aValue, aNotify);
954
0
}
955
956
void
957
HTMLTextAreaElement::CharacterDataChanged(nsIContent* aContent,
958
                                          const CharacterDataChangeInfo&)
959
0
{
960
0
  ContentChanged(aContent);
961
0
}
962
963
void
964
HTMLTextAreaElement::ContentAppended(nsIContent* aFirstNewContent)
965
0
{
966
0
  ContentChanged(aFirstNewContent);
967
0
}
968
969
void
970
HTMLTextAreaElement::ContentInserted(nsIContent* aChild)
971
0
{
972
0
  ContentChanged(aChild);
973
0
}
974
975
void
976
HTMLTextAreaElement::ContentRemoved(nsIContent* aChild,
977
                                    nsIContent* aPreviousSibling)
978
0
{
979
0
  ContentChanged(aChild);
980
0
}
981
982
void
983
HTMLTextAreaElement::ContentChanged(nsIContent* aContent)
984
0
{
985
0
  if (!mValueChanged && mDoneAddingChildren &&
986
0
      nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
987
0
    // Hard to say what the reset can trigger, so be safe pending
988
0
    // further auditing.
989
0
    nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
990
0
    Reset();
991
0
  }
992
0
}
993
994
nsresult
995
HTMLTextAreaElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
996
                                  const nsAttrValue* aValue,
997
                                  const nsAttrValue* aOldValue,
998
                                  nsIPrincipal* aSubjectPrincipal,
999
                                  bool aNotify)
1000
0
{
1001
0
  if (aNameSpaceID == kNameSpaceID_None) {
1002
0
    if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
1003
0
        aName == nsGkAtoms::readonly) {
1004
0
      if (aName == nsGkAtoms::disabled) {
1005
0
        // This *has* to be called *before* validity state check because
1006
0
        // UpdateBarredFromConstraintValidation and
1007
0
        // UpdateValueMissingValidityState depend on our disabled state.
1008
0
        UpdateDisabledState(aNotify);
1009
0
      }
1010
0
1011
0
      if (aName == nsGkAtoms::required) {
1012
0
        // This *has* to be called *before* UpdateValueMissingValidityState
1013
0
        // because UpdateValueMissingValidityState depends on our required
1014
0
        // state.
1015
0
        UpdateRequiredState(!!aValue, aNotify);
1016
0
      }
1017
0
1018
0
      UpdateValueMissingValidityState();
1019
0
1020
0
      // This *has* to be called *after* validity has changed.
1021
0
      if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
1022
0
        UpdateBarredFromConstraintValidation();
1023
0
      }
1024
0
    } else if (aName == nsGkAtoms::autocomplete) {
1025
0
      // Clear the cached @autocomplete attribute state.
1026
0
      mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
1027
0
    } else if (aName == nsGkAtoms::maxlength) {
1028
0
      UpdateTooLongValidityState();
1029
0
    } else if (aName == nsGkAtoms::minlength) {
1030
0
      UpdateTooShortValidityState();
1031
0
    }
1032
0
  }
1033
0
1034
0
  return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, aValue,
1035
0
                                                         aOldValue, aSubjectPrincipal, aNotify);
1036
0
  }
1037
1038
nsresult
1039
HTMLTextAreaElement::CopyInnerTo(Element* aDest)
1040
0
{
1041
0
  nsresult rv = nsGenericHTMLFormElementWithState::CopyInnerTo(aDest);
1042
0
  NS_ENSURE_SUCCESS(rv, rv);
1043
0
1044
0
  if (aDest->OwnerDoc()->IsStaticDocument()) {
1045
0
    nsAutoString value;
1046
0
    GetValueInternal(value, true);
1047
0
    ErrorResult ret;
1048
0
    static_cast<HTMLTextAreaElement*>(aDest)->SetValue(value, ret);
1049
0
    return ret.StealNSResult();
1050
0
  }
1051
0
  return NS_OK;
1052
0
}
1053
1054
bool
1055
HTMLTextAreaElement::IsMutable() const
1056
0
{
1057
0
  return (!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) && !IsDisabled());
1058
0
}
1059
1060
bool
1061
HTMLTextAreaElement::IsValueEmpty() const
1062
0
{
1063
0
  nsAutoString value;
1064
0
  GetValueInternal(value, true);
1065
0
1066
0
  return value.IsEmpty();
1067
0
}
1068
1069
void
1070
HTMLTextAreaElement::SetCustomValidity(const nsAString& aError)
1071
0
{
1072
0
  nsIConstraintValidation::SetCustomValidity(aError);
1073
0
1074
0
  UpdateState(true);
1075
0
}
1076
1077
bool
1078
HTMLTextAreaElement::IsTooLong()
1079
0
{
1080
0
  if (!mValueChanged ||
1081
0
      !mLastValueChangeWasInteractive ||
1082
0
      !HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength)) {
1083
0
    return false;
1084
0
  }
1085
0
1086
0
  int32_t maxLength = MaxLength();
1087
0
1088
0
  // Maxlength of -1 means parsing error.
1089
0
  if (maxLength == -1) {
1090
0
    return false;
1091
0
  }
1092
0
1093
0
  int32_t textLength = GetTextLength();
1094
0
1095
0
  return textLength > maxLength;
1096
0
}
1097
1098
bool
1099
HTMLTextAreaElement::IsTooShort()
1100
0
{
1101
0
  if (!mValueChanged ||
1102
0
      !mLastValueChangeWasInteractive ||
1103
0
      !HasAttr(kNameSpaceID_None, nsGkAtoms::minlength)) {
1104
0
    return false;
1105
0
  }
1106
0
1107
0
  int32_t minLength = MinLength();
1108
0
1109
0
  // Minlength of -1 means parsing error.
1110
0
  if (minLength == -1) {
1111
0
    return false;
1112
0
  }
1113
0
1114
0
  int32_t textLength = GetTextLength();
1115
0
1116
0
  return textLength && textLength < minLength;
1117
0
}
1118
1119
bool
1120
HTMLTextAreaElement::IsValueMissing() const
1121
0
{
1122
0
  if (!Required() || !IsMutable()) {
1123
0
    return false;
1124
0
  }
1125
0
1126
0
  return IsValueEmpty();
1127
0
}
1128
1129
void
1130
HTMLTextAreaElement::UpdateTooLongValidityState()
1131
0
{
1132
0
  SetValidityState(VALIDITY_STATE_TOO_LONG, IsTooLong());
1133
0
}
1134
1135
void
1136
HTMLTextAreaElement::UpdateTooShortValidityState()
1137
0
{
1138
0
  SetValidityState(VALIDITY_STATE_TOO_SHORT, IsTooShort());
1139
0
}
1140
1141
void
1142
HTMLTextAreaElement::UpdateValueMissingValidityState()
1143
0
{
1144
0
  SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
1145
0
}
1146
1147
void
1148
HTMLTextAreaElement::UpdateBarredFromConstraintValidation()
1149
0
{
1150
0
  SetBarredFromConstraintValidation(HasAttr(kNameSpaceID_None,
1151
0
                                            nsGkAtoms::readonly) ||
1152
0
                                    IsDisabled());
1153
0
}
1154
1155
nsresult
1156
HTMLTextAreaElement::GetValidationMessage(nsAString& aValidationMessage,
1157
                                          ValidityStateType aType)
1158
0
{
1159
0
  nsresult rv = NS_OK;
1160
0
1161
0
  switch (aType)
1162
0
  {
1163
0
    case VALIDITY_STATE_TOO_LONG:
1164
0
      {
1165
0
        nsAutoString message;
1166
0
        int32_t maxLength = MaxLength();
1167
0
        int32_t textLength = GetTextLength();
1168
0
        nsAutoString strMaxLength;
1169
0
        nsAutoString strTextLength;
1170
0
1171
0
        strMaxLength.AppendInt(maxLength);
1172
0
        strTextLength.AppendInt(textLength);
1173
0
1174
0
        const char16_t* params[] = { strMaxLength.get(), strTextLength.get() };
1175
0
        rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1176
0
                                                   "FormValidationTextTooLong",
1177
0
                                                   params, message);
1178
0
        aValidationMessage = message;
1179
0
      }
1180
0
      break;
1181
0
    case VALIDITY_STATE_TOO_SHORT:
1182
0
      {
1183
0
        nsAutoString message;
1184
0
        int32_t minLength = MinLength();
1185
0
        int32_t textLength = GetTextLength();
1186
0
        nsAutoString strMinLength;
1187
0
        nsAutoString strTextLength;
1188
0
1189
0
        strMinLength.AppendInt(minLength);
1190
0
        strTextLength.AppendInt(textLength);
1191
0
1192
0
        const char16_t* params[] = { strMinLength.get(), strTextLength.get() };
1193
0
        rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1194
0
                                                   "FormValidationTextTooShort",
1195
0
                                                   params, message);
1196
0
        aValidationMessage = message;
1197
0
      }
1198
0
      break;
1199
0
    case VALIDITY_STATE_VALUE_MISSING:
1200
0
      {
1201
0
        nsAutoString message;
1202
0
        rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
1203
0
                                                "FormValidationValueMissing",
1204
0
                                                message);
1205
0
        aValidationMessage = message;
1206
0
      }
1207
0
      break;
1208
0
    default:
1209
0
      rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
1210
0
  }
1211
0
1212
0
  return rv;
1213
0
}
1214
1215
NS_IMETHODIMP_(bool)
1216
HTMLTextAreaElement::IsSingleLineTextControl() const
1217
0
{
1218
0
  return false;
1219
0
}
1220
1221
NS_IMETHODIMP_(bool)
1222
HTMLTextAreaElement::IsTextArea() const
1223
0
{
1224
0
  return true;
1225
0
}
1226
1227
NS_IMETHODIMP_(bool)
1228
HTMLTextAreaElement::IsPasswordTextControl() const
1229
0
{
1230
0
  return false;
1231
0
}
1232
1233
NS_IMETHODIMP_(int32_t)
1234
HTMLTextAreaElement::GetCols()
1235
0
{
1236
0
  return Cols();
1237
0
}
1238
1239
NS_IMETHODIMP_(int32_t)
1240
HTMLTextAreaElement::GetWrapCols()
1241
0
{
1242
0
  // wrap=off means -1 for wrap width no matter what cols is
1243
0
  nsHTMLTextWrap wrapProp;
1244
0
  nsITextControlElement::GetWrapPropertyEnum(this, wrapProp);
1245
0
  if (wrapProp == nsITextControlElement::eHTMLTextWrap_Off) {
1246
0
    // do not wrap when wrap=off
1247
0
    return 0;
1248
0
  }
1249
0
1250
0
  // Otherwise we just wrap at the given number of columns
1251
0
  return GetCols();
1252
0
}
1253
1254
1255
NS_IMETHODIMP_(int32_t)
1256
HTMLTextAreaElement::GetRows()
1257
0
{
1258
0
  const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::rows);
1259
0
  if (attr && attr->Type() == nsAttrValue::eInteger) {
1260
0
    int32_t rows = attr->GetIntegerValue();
1261
0
    return (rows <= 0) ? DEFAULT_ROWS_TEXTAREA : rows;
1262
0
  }
1263
0
1264
0
  return DEFAULT_ROWS_TEXTAREA;
1265
0
}
1266
1267
NS_IMETHODIMP_(void)
1268
HTMLTextAreaElement::GetDefaultValueFromContent(nsAString& aValue)
1269
0
{
1270
0
  GetDefaultValue(aValue, IgnoreErrors());
1271
0
}
1272
1273
NS_IMETHODIMP_(bool)
1274
HTMLTextAreaElement::ValueChanged() const
1275
0
{
1276
0
  return mValueChanged;
1277
0
}
1278
1279
NS_IMETHODIMP_(void)
1280
HTMLTextAreaElement::GetTextEditorValue(nsAString& aValue,
1281
                                        bool aIgnoreWrap) const
1282
0
{
1283
0
  mState.GetValue(aValue, aIgnoreWrap);
1284
0
}
1285
1286
NS_IMETHODIMP_(void)
1287
HTMLTextAreaElement::InitializeKeyboardEventListeners()
1288
0
{
1289
0
  mState.InitializeKeyboardEventListeners();
1290
0
}
1291
1292
NS_IMETHODIMP_(void)
1293
HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
1294
0
{
1295
0
  mLastValueChangeWasInteractive = aWasInteractiveUserChange;
1296
0
1297
0
  // Update the validity state
1298
0
  bool validBefore = IsValid();
1299
0
  UpdateTooLongValidityState();
1300
0
  UpdateTooShortValidityState();
1301
0
  UpdateValueMissingValidityState();
1302
0
1303
0
  if (validBefore != IsValid() ||
1304
0
      HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
1305
0
    UpdateState(aNotify);
1306
0
  }
1307
0
}
1308
1309
NS_IMETHODIMP_(bool)
1310
HTMLTextAreaElement::HasCachedSelection()
1311
0
{
1312
0
  return mState.IsSelectionCached();
1313
0
}
1314
1315
void
1316
HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify)
1317
0
{
1318
0
  // This *has* to be called before UpdateBarredFromConstraintValidation and
1319
0
  // UpdateValueMissingValidityState because these two functions depend on our
1320
0
  // disabled state.
1321
0
  nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
1322
0
1323
0
  UpdateValueMissingValidityState();
1324
0
  UpdateBarredFromConstraintValidation();
1325
0
  UpdateState(aNotify);
1326
0
}
1327
1328
JSObject*
1329
HTMLTextAreaElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
1330
0
{
1331
0
  return HTMLTextAreaElement_Binding::Wrap(aCx, this, aGivenProto);
1332
0
}
1333
1334
void
1335
HTMLTextAreaElement::GetAutocomplete(DOMString& aValue)
1336
0
{
1337
0
  const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
1338
0
1339
0
  mAutocompleteAttrState =
1340
0
    nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
1341
0
                                                   mAutocompleteAttrState);
1342
0
}
1343
1344
} // namespace dom
1345
} // namespace mozilla