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 #ifndef mozilla_dom_HTMLTextAreaElement_h
8 #define mozilla_dom_HTMLTextAreaElement_h
9 
10 #include "mozilla/Attributes.h"
11 #include "mozilla/TextControlElement.h"
12 #include "mozilla/TextControlState.h"
13 #include "mozilla/TextEditor.h"
14 #include "mozilla/dom/ConstraintValidation.h"
15 #include "mozilla/dom/HTMLFormElement.h"
16 #include "mozilla/dom/HTMLInputElementBinding.h"
17 #include "nsIControllers.h"
18 #include "nsCOMPtr.h"
19 #include "nsGenericHTMLElement.h"
20 #include "nsStubMutationObserver.h"
21 #include "nsGkAtoms.h"
22 
23 class nsIControllers;
24 class nsPresContext;
25 
26 namespace mozilla {
27 
28 class EventChainPostVisitor;
29 class EventChainPreVisitor;
30 class EventStates;
31 class PresState;
32 
33 namespace dom {
34 
35 class FormData;
36 
37 class HTMLTextAreaElement final : public TextControlElement,
38                                   public nsStubMutationObserver,
39                                   public ConstraintValidation {
40  public:
41   using ConstraintValidation::GetValidationMessage;
42   using ValueSetterOption = TextControlState::ValueSetterOption;
43   using ValueSetterOptions = TextControlState::ValueSetterOptions;
44 
45   explicit HTMLTextAreaElement(
46       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
47       FromParser aFromParser = NOT_FROM_PARSER);
48 
49   // nsISupports
50   NS_DECL_ISUPPORTS_INHERITED
51 
52   NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLTextAreaElement, textarea)
53 
54   virtual int32_t TabIndexDefault() override;
55 
56   // Element
IsInteractiveHTMLContent()57   virtual bool IsInteractiveHTMLContent() const override { return true; }
58 
59   // nsGenericHTMLElement
60   virtual bool IsDisabledForEvents(WidgetEvent* aEvent) override;
61 
62   // nsGenericHTMLFormElement
63   void SaveState() override;
64   bool RestoreState(PresState* aState) override;
65 
66   // nsIFormControl
67   MOZ_CAN_RUN_SCRIPT_BOUNDARY
68   NS_IMETHOD Reset() override;
69   NS_IMETHOD SubmitNamesValues(FormData* aFormData) override;
70 
71   virtual void FieldSetDisabledChanged(bool aNotify) override;
72 
73   virtual EventStates IntrinsicState() const override;
74 
75   void SetLastValueChangeWasInteractive(bool);
76 
77   // TextControlElement
78   virtual nsresult SetValueChanged(bool aValueChanged) override;
79   virtual bool IsSingleLineTextControl() const override;
80   virtual bool IsTextArea() const override;
81   virtual bool IsPasswordTextControl() const override;
82   virtual int32_t GetCols() override;
83   virtual int32_t GetWrapCols() override;
84   virtual int32_t GetRows() override;
85   virtual void GetDefaultValueFromContent(nsAString& aValue) override;
86   virtual bool ValueChanged() const override;
87   virtual void GetTextEditorValue(nsAString& aValue,
88                                   bool aIgnoreWrap) const override;
89   MOZ_CAN_RUN_SCRIPT virtual TextEditor* GetTextEditor() override;
90   virtual TextEditor* GetTextEditorWithoutCreation() override;
91   virtual nsISelectionController* GetSelectionController() override;
92   virtual nsFrameSelection* GetConstFrameSelection() override;
GetTextControlState()93   virtual TextControlState* GetTextControlState() const override {
94     return mState;
95   }
96   virtual nsresult BindToFrame(nsTextControlFrame* aFrame) override;
97   MOZ_CAN_RUN_SCRIPT virtual void UnbindFromFrame(
98       nsTextControlFrame* aFrame) override;
99   MOZ_CAN_RUN_SCRIPT virtual nsresult CreateEditor() override;
100   virtual void SetPreviewValue(const nsAString& aValue) override;
101   virtual void GetPreviewValue(nsAString& aValue) override;
102   virtual void EnablePreview() override;
103   virtual bool IsPreviewEnabled() override;
104   virtual void InitializeKeyboardEventListeners() override;
105   virtual void OnValueChanged(ValueChangeKind) override;
106   virtual void GetValueFromSetRangeText(nsAString& aValue) override;
107   MOZ_CAN_RUN_SCRIPT virtual nsresult SetValueFromSetRangeText(
108       const nsAString& aValue) override;
109   virtual bool HasCachedSelection() override;
110 
111   // nsIContent
112   virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
113   virtual void UnbindFromTree(bool aNullParent = true) override;
114   virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
115                               const nsAString& aValue,
116                               nsIPrincipal* aMaybeScriptedPrincipal,
117                               nsAttrValue& aResult) override;
118   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction()
119       const override;
120   virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
121                                               int32_t aModType) const override;
122   NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
123 
124   void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
125   virtual nsresult PreHandleEvent(EventChainVisitor& aVisitor) override;
126   virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
127 
128   virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
129                                int32_t* aTabIndex) override;
130 
131   virtual void DoneAddingChildren(bool aHaveNotified) override;
132   virtual bool IsDoneAddingChildren() override;
133 
134   MOZ_CAN_RUN_SCRIPT_BOUNDARY
135   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
136 
137   nsresult CopyInnerTo(Element* aDest);
138 
139   /**
140    * Called when an attribute is about to be changed
141    */
142   virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
143                                  const nsAttrValueOrString* aValue,
144                                  bool aNotify) override;
145 
146   // nsIMutationObserver
147   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
148   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
149   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
150   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
151 
152   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTextAreaElement,
153                                            TextControlElement)
154 
155   // nsIConstraintValidation
156   bool IsTooLong();
157   bool IsTooShort();
158   bool IsValueMissing() const;
159   void UpdateTooLongValidityState();
160   void UpdateTooShortValidityState();
161   void UpdateValueMissingValidityState();
162   void UpdateBarredFromConstraintValidation();
163 
164   // ConstraintValidation
165   nsresult GetValidationMessage(nsAString& aValidationMessage,
166                                 ValidityStateType aType) override;
167 
168   // Web IDL binding methods
169   void GetAutocomplete(DOMString& aValue);
SetAutocomplete(const nsAString & aValue,ErrorResult & aRv)170   void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv) {
171     SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
172   }
Autofocus()173   bool Autofocus() { return GetBoolAttr(nsGkAtoms::autofocus); }
SetAutofocus(bool aAutoFocus,ErrorResult & aError)174   void SetAutofocus(bool aAutoFocus, ErrorResult& aError) {
175     SetHTMLBoolAttr(nsGkAtoms::autofocus, aAutoFocus, aError);
176   }
Cols()177   uint32_t Cols() { return GetUnsignedIntAttr(nsGkAtoms::cols, DEFAULT_COLS); }
SetCols(uint32_t aCols,ErrorResult & aError)178   void SetCols(uint32_t aCols, ErrorResult& aError) {
179     uint32_t cols = aCols ? aCols : DEFAULT_COLS;
180     SetUnsignedIntAttr(nsGkAtoms::cols, cols, DEFAULT_COLS, aError);
181   }
Disabled()182   bool Disabled() { return GetBoolAttr(nsGkAtoms::disabled); }
SetDisabled(bool aDisabled,ErrorResult & aError)183   void SetDisabled(bool aDisabled, ErrorResult& aError) {
184     SetHTMLBoolAttr(nsGkAtoms::disabled, aDisabled, aError);
185   }
186   // nsGenericHTMLFormControlElementWithState::GetForm is fine
187   using nsGenericHTMLFormControlElementWithState::GetForm;
MaxLength()188   int32_t MaxLength() const { return GetIntAttr(nsGkAtoms::maxlength, -1); }
UsedMaxLength()189   int32_t UsedMaxLength() const final { return MaxLength(); }
SetMaxLength(int32_t aMaxLength,ErrorResult & aError)190   void SetMaxLength(int32_t aMaxLength, ErrorResult& aError) {
191     int32_t minLength = MinLength();
192     if (aMaxLength < 0 || (minLength >= 0 && aMaxLength < minLength)) {
193       aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
194     } else {
195       SetHTMLIntAttr(nsGkAtoms::maxlength, aMaxLength, aError);
196     }
197   }
MinLength()198   int32_t MinLength() const { return GetIntAttr(nsGkAtoms::minlength, -1); }
SetMinLength(int32_t aMinLength,ErrorResult & aError)199   void SetMinLength(int32_t aMinLength, ErrorResult& aError) {
200     int32_t maxLength = MaxLength();
201     if (aMinLength < 0 || (maxLength >= 0 && aMinLength > maxLength)) {
202       aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
203     } else {
204       SetHTMLIntAttr(nsGkAtoms::minlength, aMinLength, aError);
205     }
206   }
GetName(nsAString & aName)207   void GetName(nsAString& aName) { GetHTMLAttr(nsGkAtoms::name, aName); }
SetName(const nsAString & aName,ErrorResult & aError)208   void SetName(const nsAString& aName, ErrorResult& aError) {
209     SetHTMLAttr(nsGkAtoms::name, aName, aError);
210   }
GetPlaceholder(nsAString & aPlaceholder)211   void GetPlaceholder(nsAString& aPlaceholder) {
212     GetHTMLAttr(nsGkAtoms::placeholder, aPlaceholder);
213   }
SetPlaceholder(const nsAString & aPlaceholder,ErrorResult & aError)214   void SetPlaceholder(const nsAString& aPlaceholder, ErrorResult& aError) {
215     SetHTMLAttr(nsGkAtoms::placeholder, aPlaceholder, aError);
216   }
ReadOnly()217   bool ReadOnly() { return GetBoolAttr(nsGkAtoms::readonly); }
SetReadOnly(bool aReadOnly,ErrorResult & aError)218   void SetReadOnly(bool aReadOnly, ErrorResult& aError) {
219     SetHTMLBoolAttr(nsGkAtoms::readonly, aReadOnly, aError);
220   }
Required()221   bool Required() const { return State().HasState(NS_EVENT_STATE_REQUIRED); }
222 
223   MOZ_CAN_RUN_SCRIPT void SetRangeText(const nsAString& aReplacement,
224                                        ErrorResult& aRv);
225 
226   MOZ_CAN_RUN_SCRIPT void SetRangeText(const nsAString& aReplacement,
227                                        uint32_t aStart, uint32_t aEnd,
228                                        SelectionMode aSelectMode,
229                                        ErrorResult& aRv);
230 
SetRequired(bool aRequired,ErrorResult & aError)231   void SetRequired(bool aRequired, ErrorResult& aError) {
232     SetHTMLBoolAttr(nsGkAtoms::required, aRequired, aError);
233   }
Rows()234   uint32_t Rows() {
235     return GetUnsignedIntAttr(nsGkAtoms::rows, DEFAULT_ROWS_TEXTAREA);
236   }
SetRows(uint32_t aRows,ErrorResult & aError)237   void SetRows(uint32_t aRows, ErrorResult& aError) {
238     uint32_t rows = aRows ? aRows : DEFAULT_ROWS_TEXTAREA;
239     SetUnsignedIntAttr(nsGkAtoms::rows, rows, DEFAULT_ROWS_TEXTAREA, aError);
240   }
GetWrap(nsAString & aWrap)241   void GetWrap(nsAString& aWrap) { GetHTMLAttr(nsGkAtoms::wrap, aWrap); }
SetWrap(const nsAString & aWrap,ErrorResult & aError)242   void SetWrap(const nsAString& aWrap, ErrorResult& aError) {
243     SetHTMLAttr(nsGkAtoms::wrap, aWrap, aError);
244   }
245   void GetType(nsAString& aType);
246   void GetDefaultValue(nsAString& aDefaultValue, ErrorResult& aError);
247   void SetDefaultValue(const nsAString& aDefaultValue, ErrorResult& aError);
248   void GetValue(nsAString& aValue);
249   /**
250    * ValueEquals() is designed for internal use so that aValue shouldn't
251    * include \r character.  It should be handled before calling this with
252    * nsContentUtils::PlatformToDOMLineBreaks().
253    */
254   bool ValueEquals(const nsAString& aValue) const;
255   MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetValue(const nsAString& aValue,
256                                             ErrorResult& aError);
257 
258   uint32_t GetTextLength();
259 
260   // Override SetCustomValidity so we update our state properly when it's called
261   // via bindings.
262   void SetCustomValidity(const nsAString& aError);
263 
264   MOZ_CAN_RUN_SCRIPT void Select();
265   Nullable<uint32_t> GetSelectionStart(ErrorResult& aError);
266   MOZ_CAN_RUN_SCRIPT void SetSelectionStart(
267       const Nullable<uint32_t>& aSelectionStart, ErrorResult& aError);
268   Nullable<uint32_t> GetSelectionEnd(ErrorResult& aError);
269   MOZ_CAN_RUN_SCRIPT void SetSelectionEnd(
270       const Nullable<uint32_t>& aSelectionEnd, ErrorResult& aError);
271   void GetSelectionDirection(nsAString& aDirection, ErrorResult& aError);
272   MOZ_CAN_RUN_SCRIPT void SetSelectionDirection(const nsAString& aDirection,
273                                                 ErrorResult& aError);
274   MOZ_CAN_RUN_SCRIPT void SetSelectionRange(
275       uint32_t aSelectionStart, uint32_t aSelectionEnd,
276       const Optional<nsAString>& aDirecton, ErrorResult& aError);
277   nsIControllers* GetControllers(ErrorResult& aError);
278   // XPCOM adapter function widely used throughout code, leaving it as is.
279   nsresult GetControllers(nsIControllers** aResult);
280 
281   MOZ_CAN_RUN_SCRIPT nsIEditor* GetEditorForBindings();
HasEditor()282   bool HasEditor() {
283     MOZ_ASSERT(mState);
284     return !!mState->GetTextEditorWithoutCreation();
285   }
286 
IsInputEventTarget()287   bool IsInputEventTarget() const { return true; }
288 
289   MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetUserInput(
290       const nsAString& aValue, nsIPrincipal& aSubjectPrincipal);
291 
292  protected:
293   MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual ~HTMLTextAreaElement();
294 
295   // get rid of the compiler warning
296   using nsGenericHTMLFormControlElementWithState::IsSingleLineTextControl;
297 
298   virtual JSObject* WrapNode(JSContext* aCx,
299                              JS::Handle<JSObject*> aGivenProto) override;
300 
301   nsCOMPtr<nsIControllers> mControllers;
302   /** Whether or not the value has changed since its default value was given. */
303   bool mValueChanged;
304   /** Whether or not the last change to the value was made interactively by the
305    * user. */
306   bool mLastValueChangeWasInteractive;
307   /** Whether or not we are already handling select event. */
308   bool mHandlingSelect;
309   /** Whether or not we are done adding children (always true if not
310       created by a parser */
311   bool mDoneAddingChildren;
312   /** Whether state restoration should be inhibited in DoneAddingChildren. */
313   bool mInhibitStateRestoration;
314   /** Whether our disabled state has changed from the default **/
315   bool mDisabledChanged;
316   /** Whether we should make :-moz-ui-invalid apply on the element. **/
317   bool mCanShowInvalidUI;
318   /** Whether we should make :-moz-ui-valid apply on the element. **/
319   bool mCanShowValidUI;
320   bool mIsPreviewEnabled;
321 
322   nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
323 
324   void FireChangeEventIfNeeded();
325 
326   nsString mFocusedValue;
327 
328   /** The state of the text editor (selection controller and the editor) **/
329   TextControlState* mState;
330 
331   NS_IMETHOD SelectAll(nsPresContext* aPresContext);
332   /**
333    * Get the value, whether it is from the content or the frame.
334    * @param aValue the value [out]
335    * @param aIgnoreWrap whether to ignore the wrap attribute when getting the
336    *        value.  If this is true, linebreaks will not be inserted even if
337    *        wrap=hard.
338    */
339   void GetValueInternal(nsAString& aValue, bool aIgnoreWrap) const;
340 
341   /**
342    * Setting the value.
343    *
344    * @param aValue      String to set.
345    * @param aOptions    See TextControlState::ValueSetterOption.
346    */
347   MOZ_CAN_RUN_SCRIPT nsresult
348   SetValueInternal(const nsAString& aValue, const ValueSetterOptions& aOptions);
349 
350   /**
351    * Common method to call from the various mutation observer methods.
352    * aContent is a content node that's either the one that changed or its
353    * parent; we should only respond to the change if aContent is non-anonymous.
354    */
355   void ContentChanged(nsIContent* aContent);
356 
357   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
358                                 const nsAttrValue* aValue,
359                                 const nsAttrValue* aOldValue,
360                                 nsIPrincipal* aSubjectPrincipal,
361                                 bool aNotify) override;
362 
363   /**
364    * Return if an element should have a specific validity UI
365    * (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes).
366    *
367    * @return Whether the element should have a validity UI.
368    */
ShouldShowValidityUI()369   bool ShouldShowValidityUI() const {
370     /**
371      * Always show the validity UI if the form has already tried to be submitted
372      * but was invalid.
373      *
374      * Otherwise, show the validity UI if the element's value has been changed.
375      */
376 
377     if (mForm && mForm->HasEverTriedInvalidSubmit()) {
378       return true;
379     }
380 
381     return mValueChanged;
382   }
383 
384   /**
385    * Get the mutable state of the element.
386    */
387   bool IsMutable() const;
388 
389   /**
390    * Returns whether the current value is the empty string.
391    *
392    * @return whether the current value is the empty string.
393    */
394   bool IsValueEmpty() const;
395 
396   /**
397    * A helper to get the current selection range.  Will throw on the ErrorResult
398    * if we have no editor state.
399    */
400   void GetSelectionRange(uint32_t* aSelectionStart, uint32_t* aSelectionEnd,
401                          ErrorResult& aRv);
402 
403  private:
404   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
405                                     MappedDeclarations&);
406 };
407 
408 }  // namespace dom
409 }  // namespace mozilla
410 
411 #endif
412