HTMLTextAreaElement.cpp 45 KB

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