123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "mozilla/dom/HTMLTextAreaElement.h"
- #include "mozAutoDocUpdate.h"
- #include "mozilla/AsyncEventDispatcher.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/dom/HTMLFormSubmission.h"
- #include "mozilla/dom/HTMLTextAreaElementBinding.h"
- #include "mozilla/EventDispatcher.h"
- #include "mozilla/EventStates.h"
- #include "mozilla/MouseEvents.h"
- #include "nsAttrValueInlines.h"
- #include "nsContentCID.h"
- #include "nsContentCreatorFunctions.h"
- #include "nsError.h"
- #include "nsFocusManager.h"
- #include "nsIComponentManager.h"
- #include "nsIConstraintValidation.h"
- #include "nsIControllers.h"
- #include "nsIDocument.h"
- #include "nsIDOMHTMLFormElement.h"
- #include "nsIFormControlFrame.h"
- #include "nsIFormControl.h"
- #include "nsIForm.h"
- #include "nsIFrame.h"
- #include "nsISupportsPrimitives.h"
- #include "nsITextControlFrame.h"
- #include "nsLayoutUtils.h"
- #include "nsLinebreakConverter.h"
- #include "nsMappedAttributes.h"
- #include "nsPIDOMWindow.h"
- #include "nsPresContext.h"
- #include "nsPresState.h"
- #include "nsReadableUtils.h"
- #include "nsRuleData.h"
- #include "nsStyleConsts.h"
- #include "nsTextEditorState.h"
- #include "nsIController.h"
- static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
- #define NS_NO_CONTENT_DISPATCH (1 << 0)
- NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(TextArea)
- namespace mozilla {
- namespace dom {
- HTMLTextAreaElement::HTMLTextAreaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
- FromParser aFromParser)
- : nsGenericHTMLFormElementWithState(aNodeInfo),
- mValueChanged(false),
- mLastValueChangeWasInteractive(false),
- mHandlingSelect(false),
- mDoneAddingChildren(!aFromParser),
- mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
- mDisabledChanged(false),
- mCanShowInvalidUI(true),
- mCanShowValidUI(true),
- mState(this)
- {
- AddMutationObserver(this);
- // Set up our default state. By default we're enabled (since we're
- // a control type that can be disabled but not actually disabled
- // right now), optional, and valid. We are NOT readwrite by default
- // until someone calls UpdateEditableState on us, apparently! Also
- // by default we don't have to show validity UI and so forth.
- AddStatesSilently(NS_EVENT_STATE_ENABLED |
- NS_EVENT_STATE_OPTIONAL |
- NS_EVENT_STATE_VALID);
- }
- NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLTextAreaElement,
- nsGenericHTMLFormElementWithState,
- mValidity,
- mControllers,
- mState)
- NS_IMPL_ADDREF_INHERITED(HTMLTextAreaElement, Element)
- NS_IMPL_RELEASE_INHERITED(HTMLTextAreaElement, Element)
- // QueryInterface implementation for HTMLTextAreaElement
- NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLTextAreaElement)
- NS_INTERFACE_TABLE_INHERITED(HTMLTextAreaElement,
- nsIDOMHTMLTextAreaElement,
- nsITextControlElement,
- nsIDOMNSEditableElement,
- nsIMutationObserver,
- nsIConstraintValidation)
- NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
- // nsIDOMHTMLTextAreaElement
- nsresult
- HTMLTextAreaElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
- {
- *aResult = nullptr;
- already_AddRefed<mozilla::dom::NodeInfo> ni =
- RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
- RefPtr<HTMLTextAreaElement> it = new HTMLTextAreaElement(ni);
- nsresult rv = const_cast<HTMLTextAreaElement*>(this)->CopyInnerTo(it);
- NS_ENSURE_SUCCESS(rv, rv);
- if (mValueChanged) {
- // Set our value on the clone.
- nsAutoString value;
- GetValueInternal(value, true);
- // SetValueInternal handles setting mValueChanged for us
- rv = it->SetValueInternal(value, nsTextEditorState::eSetValue_Notify);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- it->mLastValueChangeWasInteractive = mLastValueChangeWasInteractive;
- it.forget(aResult);
- return NS_OK;
- }
- // nsIConstraintValidation
- NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(HTMLTextAreaElement)
- NS_IMETHODIMP
- HTMLTextAreaElement::GetForm(nsIDOMHTMLFormElement** aForm)
- {
- return nsGenericHTMLFormElementWithState::GetForm(aForm);
- }
- // nsIContent
- NS_IMETHODIMP
- HTMLTextAreaElement::Select()
- {
- // XXX Bug? We have to give the input focus before contents can be
- // selected
- FocusTristate state = FocusState();
- if (state == eUnfocusable) {
- return NS_OK;
- }
- nsIFocusManager* fm = nsFocusManager::GetFocusManager();
- RefPtr<nsPresContext> presContext = GetPresContext(eForComposedDoc);
- if (state == eInactiveWindow) {
- if (fm)
- fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
- SelectAll(presContext);
- return NS_OK;
- }
- nsEventStatus status = nsEventStatus_eIgnore;
- WidgetGUIEvent event(true, eFormSelect, nullptr);
- // XXXbz HTMLInputElement guards against this reentering; shouldn't we?
- EventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext,
- &event, nullptr, &status);
- // If the DOM event was not canceled (e.g. by a JS event handler
- // returning false)
- if (status == nsEventStatus_eIgnore) {
- if (fm) {
- fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
- // ensure that the element is actually focused
- nsCOMPtr<nsIDOMElement> focusedElement;
- fm->GetFocusedElement(getter_AddRefs(focusedElement));
- if (SameCOMIdentity(static_cast<nsIDOMNode*>(this), focusedElement)) {
- // Now Select all the text!
- SelectAll(presContext);
- }
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SelectAll(nsPresContext* aPresContext)
- {
- nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
- if (formControlFrame) {
- formControlFrame->SetFormProperty(nsGkAtoms::select, EmptyString());
- }
- return NS_OK;
- }
- bool
- HTMLTextAreaElement::IsHTMLFocusable(bool aWithMouse,
- bool *aIsFocusable, int32_t *aTabIndex)
- {
- if (nsGenericHTMLFormElementWithState::IsHTMLFocusable(aWithMouse, aIsFocusable,
- aTabIndex))
- {
- return true;
- }
- // disabled textareas are not focusable
- *aIsFocusable = !IsDisabled();
- return false;
- }
- NS_IMPL_BOOL_ATTR(HTMLTextAreaElement, Autofocus, autofocus)
- NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(HTMLTextAreaElement, Cols, cols, DEFAULT_COLS)
- NS_IMPL_BOOL_ATTR(HTMLTextAreaElement, Disabled, disabled)
- NS_IMPL_NON_NEGATIVE_INT_ATTR(HTMLTextAreaElement, MaxLength, maxlength)
- NS_IMPL_NON_NEGATIVE_INT_ATTR(HTMLTextAreaElement, MinLength, minlength)
- NS_IMPL_STRING_ATTR(HTMLTextAreaElement, Name, name)
- NS_IMPL_BOOL_ATTR(HTMLTextAreaElement, ReadOnly, readonly)
- NS_IMPL_BOOL_ATTR(HTMLTextAreaElement, Required, required)
- NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(HTMLTextAreaElement, Rows, rows, DEFAULT_ROWS_TEXTAREA)
- NS_IMPL_STRING_ATTR(HTMLTextAreaElement, Wrap, wrap)
- NS_IMPL_STRING_ATTR(HTMLTextAreaElement, Placeholder, placeholder)
-
- int32_t
- HTMLTextAreaElement::TabIndexDefault()
- {
- return 0;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::GetType(nsAString& aType)
- {
- aType.AssignLiteral("textarea");
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::GetValue(nsAString& aValue)
- {
- GetValueInternal(aValue, true);
- return NS_OK;
- }
- void
- HTMLTextAreaElement::GetValueInternal(nsAString& aValue, bool aIgnoreWrap) const
- {
- mState.GetValue(aValue, aIgnoreWrap);
- }
- NS_IMETHODIMP_(nsIEditor*)
- HTMLTextAreaElement::GetTextEditor()
- {
- return GetEditor();
- }
- NS_IMETHODIMP_(nsISelectionController*)
- HTMLTextAreaElement::GetSelectionController()
- {
- return mState.GetSelectionController();
- }
- NS_IMETHODIMP_(nsFrameSelection*)
- HTMLTextAreaElement::GetConstFrameSelection()
- {
- return mState.GetConstFrameSelection();
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::BindToFrame(nsTextControlFrame* aFrame)
- {
- return mState.BindToFrame(aFrame);
- }
- NS_IMETHODIMP_(void)
- HTMLTextAreaElement::UnbindFromFrame(nsTextControlFrame* aFrame)
- {
- if (aFrame) {
- mState.UnbindFromFrame(aFrame);
- }
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::CreateEditor()
- {
- return mState.PrepareEditor();
- }
- NS_IMETHODIMP_(nsIContent*)
- HTMLTextAreaElement::GetRootEditorNode()
- {
- return mState.GetRootNode();
- }
- NS_IMETHODIMP_(Element*)
- HTMLTextAreaElement::CreatePlaceholderNode()
- {
- NS_ENSURE_SUCCESS(mState.CreatePlaceholderNode(), nullptr);
- return mState.GetPlaceholderNode();
- }
- NS_IMETHODIMP_(Element*)
- HTMLTextAreaElement::GetPlaceholderNode()
- {
- return mState.GetPlaceholderNode();
- }
- NS_IMETHODIMP_(void)
- HTMLTextAreaElement::UpdatePlaceholderVisibility(bool aNotify)
- {
- mState.UpdatePlaceholderVisibility(aNotify);
- }
- NS_IMETHODIMP_(bool)
- HTMLTextAreaElement::GetPlaceholderVisibility()
- {
- return mState.GetPlaceholderVisibility();
- }
- nsresult
- HTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
- uint32_t aFlags)
- {
- // Need to set the value changed flag here, so that
- // nsTextControlFrame::UpdateValueDisplay retrieves the correct value
- // if needed.
- SetValueChanged(true);
- aFlags |= nsTextEditorState::eSetValue_Notify;
- if (!mState.SetValue(aValue, aFlags)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SetValue(const nsAString& aValue)
- {
- // If the value has been set by a script, we basically want to keep the
- // current change event state. If the element is ready to fire a change
- // event, we should keep it that way. Otherwise, we should make sure the
- // element will not fire any event because of the script interaction.
- //
- // NOTE: this is currently quite expensive work (too much string
- // manipulation). We should probably optimize that.
- nsAutoString currentValue;
- GetValueInternal(currentValue, true);
- nsresult rv =
- SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent);
- NS_ENSURE_SUCCESS(rv, rv);
- if (mFocusedValue.Equals(currentValue)) {
- GetValueInternal(mFocusedValue, true);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SetUserInput(const nsAString& aValue)
- {
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- return SetValueInternal(aValue, nsTextEditorState::eSetValue_BySetUserInput);
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SetValueChanged(bool aValueChanged)
- {
- bool previousValue = mValueChanged;
- mValueChanged = aValueChanged;
- if (!aValueChanged && !mState.IsEmpty()) {
- mState.EmptyValue();
- }
- if (mValueChanged != previousValue) {
- UpdateState(true);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::GetDefaultValue(nsAString& aDefaultValue)
- {
- if (!nsContentUtils::GetNodeTextContent(this, false, aDefaultValue, fallible)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SetDefaultValue(const nsAString& aDefaultValue)
- {
- ErrorResult error;
- SetDefaultValue(aDefaultValue, error);
- return error.StealNSResult();
- }
- void
- HTMLTextAreaElement::SetDefaultValue(const nsAString& aDefaultValue, ErrorResult& aError)
- {
- nsresult rv = nsContentUtils::SetNodeTextContent(this, aDefaultValue, true);
- if (NS_SUCCEEDED(rv) && !mValueChanged) {
- Reset();
- }
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- }
- }
- bool
- HTMLTextAreaElement::ParseAttribute(int32_t aNamespaceID,
- nsIAtom* aAttribute,
- const nsAString& aValue,
- nsAttrValue& aResult)
- {
- if (aNamespaceID == kNameSpaceID_None) {
- if (aAttribute == nsGkAtoms::maxlength ||
- aAttribute == nsGkAtoms::minlength) {
- return aResult.ParseNonNegativeIntValue(aValue);
- } else if (aAttribute == nsGkAtoms::cols) {
- aResult.ParseIntWithFallback(aValue, DEFAULT_COLS);
- return true;
- } else if (aAttribute == nsGkAtoms::rows) {
- aResult.ParseIntWithFallback(aValue, DEFAULT_ROWS_TEXTAREA);
- return true;
- }
- }
- return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
- aResult);
- }
- void
- HTMLTextAreaElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
- nsRuleData* aData)
- {
- if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
- // wrap=off
- nsCSSValue* whiteSpace = aData->ValueForWhiteSpace();
- if (whiteSpace->GetUnit() == eCSSUnit_Null) {
- const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::wrap);
- if (value && value->Type() == nsAttrValue::eString &&
- value->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
- whiteSpace->SetIntValue(NS_STYLE_WHITESPACE_PRE, eCSSUnit_Enumerated);
- }
- }
- }
- nsGenericHTMLFormElementWithState::MapDivAlignAttributeInto(aAttributes, aData);
- nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
- }
- nsChangeHint
- HTMLTextAreaElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
- int32_t aModType) const
- {
- nsChangeHint retval =
- nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
- if (aAttribute == nsGkAtoms::rows ||
- aAttribute == nsGkAtoms::cols) {
- retval |= NS_STYLE_HINT_REFLOW;
- } else if (aAttribute == nsGkAtoms::wrap) {
- retval |= nsChangeHint_ReconstructFrame;
- } else if (aAttribute == nsGkAtoms::placeholder) {
- retval |= nsChangeHint_ReconstructFrame;
- }
- return retval;
- }
- NS_IMETHODIMP_(bool)
- HTMLTextAreaElement::IsAttributeMapped(const nsIAtom* aAttribute) const
- {
- static const MappedAttributeEntry attributes[] = {
- { &nsGkAtoms::wrap },
- { nullptr }
- };
- static const MappedAttributeEntry* const map[] = {
- attributes,
- sDivAlignAttributeMap,
- sCommonAttributeMap,
- };
- return FindAttributeDependence(aAttribute, map);
- }
- nsMapRuleToAttributesFunc
- HTMLTextAreaElement::GetAttributeMappingFunction() const
- {
- return &MapAttributesIntoRule;
- }
- bool
- HTMLTextAreaElement::IsDisabledForEvents(WidgetEvent* aEvent)
- {
- nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
- nsIFrame* formFrame = do_QueryFrame(formControlFrame);
- return IsElementDisabledForEvents(aEvent, formFrame);
- }
- nsresult
- HTMLTextAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
- {
- aVisitor.mCanHandle = false;
- if (IsDisabledForEvents(aVisitor.mEvent)) {
- return NS_OK;
- }
- // Don't dispatch a second select event if we are already handling
- // one.
- if (aVisitor.mEvent->mMessage == eFormSelect) {
- if (mHandlingSelect) {
- return NS_OK;
- }
- mHandlingSelect = true;
- }
- // If noContentDispatch is true we will not allow content to handle
- // this event. But to allow middle mouse button paste to work we must allow
- // middle clicks to go to text fields anyway.
- if (aVisitor.mEvent->mFlags.mNoContentDispatch) {
- aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH;
- }
- if (aVisitor.mEvent->mMessage == eMouseClick &&
- aVisitor.mEvent->AsMouseEvent()->button ==
- WidgetMouseEvent::eMiddleButton) {
- aVisitor.mEvent->mFlags.mNoContentDispatch = false;
- }
- if (aVisitor.mEvent->mMessage == eBlur) {
- // Set mWantsPreHandleEvent and fire change event in PreHandleEvent to
- // prevent it breaks event target chain creation.
- aVisitor.mWantsPreHandleEvent = true;
- }
- return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
- }
- nsresult
- HTMLTextAreaElement::PreHandleEvent(EventChainVisitor& aVisitor)
- {
- if (aVisitor.mEvent->mMessage == eBlur) {
- // Fire onchange (if necessary), before we do the blur, bug 370521.
- FireChangeEventIfNeeded();
- }
- return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
- }
- void
- HTMLTextAreaElement::FireChangeEventIfNeeded()
- {
- nsString value;
- GetValueInternal(value, true);
- if (mFocusedValue.Equals(value)) {
- return;
- }
- // Dispatch the change event.
- mFocusedValue = value;
- nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
- static_cast<nsIContent*>(this),
- NS_LITERAL_STRING("change"), true,
- false);
- }
- nsresult
- HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
- {
- if (aVisitor.mEvent->mMessage == eFormSelect) {
- mHandlingSelect = false;
- }
- if (aVisitor.mEvent->mMessage == eFocus ||
- aVisitor.mEvent->mMessage == eBlur) {
- if (aVisitor.mEvent->mMessage == eFocus) {
- // If the invalid UI is shown, we should show it while focusing (and
- // update). Otherwise, we should not.
- GetValueInternal(mFocusedValue, true);
- mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
- // If neither invalid UI nor valid UI is shown, we shouldn't show the valid
- // UI while typing.
- mCanShowValidUI = ShouldShowValidityUI();
- } else { // eBlur
- mCanShowInvalidUI = true;
- mCanShowValidUI = true;
- }
- UpdateState(true);
- }
- // Reset the flag for other content besides this text field
- aVisitor.mEvent->mFlags.mNoContentDispatch =
- ((aVisitor.mItemFlags & NS_NO_CONTENT_DISPATCH) != 0);
- return NS_OK;
- }
- void
- HTMLTextAreaElement::DoneAddingChildren(bool aHaveNotified)
- {
- if (!mValueChanged) {
- if (!mDoneAddingChildren) {
- // Reset now that we're done adding children if the content sink tried to
- // sneak some text in without calling AppendChildTo.
- Reset();
- }
- if (!mInhibitStateRestoration) {
- nsresult rv = GenerateStateKey();
- if (NS_SUCCEEDED(rv)) {
- RestoreFormControlState();
- }
- }
- }
- mDoneAddingChildren = true;
- }
- bool
- HTMLTextAreaElement::IsDoneAddingChildren()
- {
- return mDoneAddingChildren;
- }
- // Controllers Methods
- nsIControllers*
- HTMLTextAreaElement::GetControllers(ErrorResult& aError)
- {
- if (!mControllers)
- {
- nsresult rv;
- mControllers = do_CreateInstance(kXULControllersCID, &rv);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- return nullptr;
- }
- nsCOMPtr<nsIController> controller = do_CreateInstance("@mozilla.org/editor/editorcontroller;1", &rv);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- return nullptr;
- }
- mControllers->AppendController(controller);
- controller = do_CreateInstance("@mozilla.org/editor/editingcontroller;1", &rv);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- return nullptr;
- }
- mControllers->AppendController(controller);
- }
- return mControllers;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::GetControllers(nsIControllers** aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- ErrorResult error;
- *aResult = GetControllers(error);
- NS_IF_ADDREF(*aResult);
- return error.StealNSResult();
- }
- uint32_t
- HTMLTextAreaElement::GetTextLength()
- {
- nsAutoString val;
- GetValue(val);
- return val.Length();
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::GetTextLength(int32_t *aTextLength)
- {
- NS_ENSURE_ARG_POINTER(aTextLength);
- *aTextLength = GetTextLength();
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::GetSelectionStart(int32_t *aSelectionStart)
- {
- NS_ENSURE_ARG_POINTER(aSelectionStart);
- ErrorResult error;
- Nullable<uint32_t> selStart(GetSelectionStart(error));
- if (error.Failed()) {
- return error.StealNSResult();
- }
- *aSelectionStart = int32_t(selStart.Value());
- return error.StealNSResult();
- }
- Nullable<uint32_t>
- HTMLTextAreaElement::GetSelectionStart(ErrorResult& aError)
- {
- int32_t selStart, selEnd;
- nsresult rv = GetSelectionRange(&selStart, &selEnd);
- if (NS_FAILED(rv) && mState.IsSelectionCached()) {
- return Nullable<uint32_t>(mState.GetSelectionProperties().GetStart());
- }
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- }
- return Nullable<uint32_t>(selStart);
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SetSelectionStart(int32_t aSelectionStart)
- {
- ErrorResult error;
- Nullable<uint32_t> selStart(aSelectionStart);
- SetSelectionStart(selStart, error);
- return error.StealNSResult();
- }
- void
- HTMLTextAreaElement::SetSelectionStart(const Nullable<uint32_t>& aSelectionStart,
- ErrorResult& aError)
- {
- int32_t selStart = 0;
- if (!aSelectionStart.IsNull()) {
- selStart = aSelectionStart.Value();
- }
- if (mState.IsSelectionCached()) {
- mState.GetSelectionProperties().SetStart(selStart);
- return;
- }
- nsAutoString direction;
- nsresult rv = GetSelectionDirection(direction);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- return;
- }
- int32_t start, end;
- rv = GetSelectionRange(&start, &end);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- return;
- }
- start = selStart;
- if (end < start) {
- end = start;
- }
- rv = SetSelectionRange(start, end, direction);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- }
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::GetSelectionEnd(int32_t *aSelectionEnd)
- {
- NS_ENSURE_ARG_POINTER(aSelectionEnd);
- ErrorResult error;
- Nullable<uint32_t> selEnd(GetSelectionEnd(error));
- if (error.Failed()) {
- return error.StealNSResult();
- }
- *aSelectionEnd = int32_t(selEnd.Value());
- return NS_OK;
- }
- Nullable<uint32_t>
- HTMLTextAreaElement::GetSelectionEnd(ErrorResult& aError)
- {
- int32_t selStart, selEnd;
- nsresult rv = GetSelectionRange(&selStart, &selEnd);
- if (NS_FAILED(rv) && mState.IsSelectionCached()) {
- return Nullable<uint32_t>(mState.GetSelectionProperties().GetEnd());
- }
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- }
- return Nullable<uint32_t>(selEnd);
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SetSelectionEnd(int32_t aSelectionEnd)
- {
- ErrorResult error;
- Nullable<uint32_t> selEnd(aSelectionEnd);
- SetSelectionEnd(selEnd, error);
- return error.StealNSResult();
- }
- void
- HTMLTextAreaElement::SetSelectionEnd(const Nullable<uint32_t>& aSelectionEnd,
- ErrorResult& aError)
- {
- int32_t selEnd = 0;
- if (!aSelectionEnd.IsNull()) {
- selEnd = aSelectionEnd.Value();
- }
- if (mState.IsSelectionCached()) {
- mState.GetSelectionProperties().SetEnd(selEnd);
- return;
- }
- nsAutoString direction;
- nsresult rv = GetSelectionDirection(direction);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- return;
- }
- int32_t start, end;
- rv = GetSelectionRange(&start, &end);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- return;
- }
- end = selEnd;
- if (start > end) {
- start = end;
- }
- rv = SetSelectionRange(start, end, direction);
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- }
- }
- nsresult
- HTMLTextAreaElement::GetSelectionRange(int32_t* aSelectionStart,
- int32_t* aSelectionEnd)
- {
- nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
- nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
- if (textControlFrame) {
- return textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
- }
- return NS_ERROR_FAILURE;
- }
- static void
- DirectionToName(nsITextControlFrame::SelectionDirection dir, nsAString& aDirection)
- {
- if (dir == nsITextControlFrame::eNone) {
- aDirection.AssignLiteral("none");
- } else if (dir == nsITextControlFrame::eForward) {
- aDirection.AssignLiteral("forward");
- } else if (dir == nsITextControlFrame::eBackward) {
- aDirection.AssignLiteral("backward");
- } else {
- NS_NOTREACHED("Invalid SelectionDirection value");
- }
- }
- nsresult
- HTMLTextAreaElement::GetSelectionDirection(nsAString& aDirection)
- {
- ErrorResult error;
- GetSelectionDirection(aDirection, error);
- return error.StealNSResult();
- }
- void
- HTMLTextAreaElement::GetSelectionDirection(nsAString& aDirection, ErrorResult& aError)
- {
- nsresult rv = NS_ERROR_FAILURE;
- nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
- nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
- if (textControlFrame) {
- nsITextControlFrame::SelectionDirection dir;
- rv = textControlFrame->GetSelectionRange(nullptr, nullptr, &dir);
- if (NS_SUCCEEDED(rv)) {
- DirectionToName(dir, aDirection);
- }
- }
- if (NS_FAILED(rv)) {
- if (mState.IsSelectionCached()) {
- DirectionToName(mState.GetSelectionProperties().GetDirection(), aDirection);
- return;
- }
- aError.Throw(rv);
- }
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SetSelectionDirection(const nsAString& aDirection)
- {
- ErrorResult error;
- SetSelectionDirection(aDirection, error);
- return error.StealNSResult();
- }
- void
- HTMLTextAreaElement::SetSelectionDirection(const nsAString& aDirection,
- ErrorResult& aError)
- {
- if (mState.IsSelectionCached()) {
- nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eNone;
- if (aDirection.EqualsLiteral("forward")) {
- dir = nsITextControlFrame::eForward;
- } else if (aDirection.EqualsLiteral("backward")) {
- dir = nsITextControlFrame::eBackward;
- }
- mState.GetSelectionProperties().SetDirection(dir);
- return;
- }
- int32_t start, end;
- nsresult rv = GetSelectionRange(&start, &end);
- if (NS_SUCCEEDED(rv)) {
- rv = SetSelectionRange(start, end, aDirection);
- }
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- }
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SetSelectionRange(int32_t aSelectionStart,
- int32_t aSelectionEnd,
- const nsAString& aDirection)
- {
- ErrorResult error;
- Optional<nsAString> dir;
- dir = &aDirection;
- SetSelectionRange(aSelectionStart, aSelectionEnd, dir, error);
- return error.StealNSResult();
- }
- void
- HTMLTextAreaElement::SetSelectionRange(uint32_t aSelectionStart,
- uint32_t aSelectionEnd,
- const Optional<nsAString>& aDirection,
- ErrorResult& aError)
- {
- nsresult rv = NS_ERROR_FAILURE;
- nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
- nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
- if (textControlFrame) {
- // Default to forward, even if not specified.
- // Note that we don't currently support directionless selections, so
- // "none" is treated like "forward".
- nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eForward;
- if (aDirection.WasPassed() && aDirection.Value().EqualsLiteral("backward")) {
- dir = nsITextControlFrame::eBackward;
- }
- rv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd, dir);
- if (NS_SUCCEEDED(rv)) {
- rv = textControlFrame->ScrollSelectionIntoView();
- RefPtr<AsyncEventDispatcher> asyncDispatcher =
- new AsyncEventDispatcher(this, NS_LITERAL_STRING("select"),
- true, false);
- asyncDispatcher->PostDOMEvent();
- }
- }
- if (NS_FAILED(rv)) {
- aError.Throw(rv);
- }
- }
- void
- HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
- ErrorResult& aRv)
- {
- int32_t start, end;
- aRv = GetSelectionRange(&start, &end);
- if (aRv.Failed()) {
- if (mState.IsSelectionCached()) {
- start = mState.GetSelectionProperties().GetStart();
- end = mState.GetSelectionProperties().GetEnd();
- aRv = NS_OK;
- }
- }
- SetRangeText(aReplacement, start, end, mozilla::dom::SelectionMode::Preserve,
- aRv, start, end);
- }
- void
- HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
- uint32_t aStart, uint32_t aEnd,
- const SelectionMode& aSelectMode,
- ErrorResult& aRv, int32_t aSelectionStart,
- int32_t aSelectionEnd)
- {
- if (aStart > aEnd) {
- aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
- return;
- }
- nsAutoString value;
- GetValueInternal(value, false);
- uint32_t inputValueLength = value.Length();
- if (aStart > inputValueLength) {
- aStart = inputValueLength;
- }
- if (aEnd > inputValueLength) {
- aEnd = inputValueLength;
- }
- if (aSelectionStart == -1 && aSelectionEnd == -1) {
- aRv = GetSelectionRange(&aSelectionStart, &aSelectionEnd);
- if (aRv.Failed()) {
- if (mState.IsSelectionCached()) {
- aSelectionStart = mState.GetSelectionProperties().GetStart();
- aSelectionEnd = mState.GetSelectionProperties().GetEnd();
- aRv = NS_OK;
- }
- }
- }
- if (aStart <= aEnd) {
- value.Replace(aStart, aEnd - aStart, aReplacement);
- nsresult rv =
- SetValueInternal(value, nsTextEditorState::eSetValue_ByContent);
- if (NS_FAILED(rv)) {
- aRv.Throw(rv);
- return;
- }
- }
- uint32_t newEnd = aStart + aReplacement.Length();
- int32_t delta = aReplacement.Length() - (aEnd - aStart);
- switch (aSelectMode) {
- case mozilla::dom::SelectionMode::Select:
- {
- aSelectionStart = aStart;
- aSelectionEnd = newEnd;
- }
- break;
- case mozilla::dom::SelectionMode::Start:
- {
- aSelectionStart = aSelectionEnd = aStart;
- }
- break;
- case mozilla::dom::SelectionMode::End:
- {
- aSelectionStart = aSelectionEnd = newEnd;
- }
- break;
- case mozilla::dom::SelectionMode::Preserve:
- {
- if ((uint32_t)aSelectionStart > aEnd) {
- aSelectionStart += delta;
- } else if ((uint32_t)aSelectionStart > aStart) {
- aSelectionStart = aStart;
- }
- if ((uint32_t)aSelectionEnd > aEnd) {
- aSelectionEnd += delta;
- } else if ((uint32_t)aSelectionEnd > aStart) {
- aSelectionEnd = newEnd;
- }
- }
- break;
- default:
- MOZ_CRASH("Unknown mode!");
- }
- Optional<nsAString> direction;
- SetSelectionRange(aSelectionStart, aSelectionEnd, direction, aRv);
- }
- nsresult
- HTMLTextAreaElement::Reset()
- {
- nsresult rv;
- // To get the initial spellchecking, reset value to
- // empty string before setting the default value.
- rv = SetValue(EmptyString());
- NS_ENSURE_SUCCESS(rv, rv);
- nsAutoString resetVal;
- GetDefaultValue(resetVal);
- rv = SetValue(resetVal);
- NS_ENSURE_SUCCESS(rv, rv);
- SetValueChanged(false);
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
- {
- // Disabled elements don't submit
- if (IsDisabled()) {
- return NS_OK;
- }
- //
- // Get the name (if no name, no submit)
- //
- nsAutoString name;
- GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
- if (name.IsEmpty()) {
- return NS_OK;
- }
- //
- // Get the value
- //
- nsAutoString value;
- GetValueInternal(value, false);
- //
- // Submit
- //
- return aFormSubmission->AddNameValuePair(name, value);
- }
- NS_IMETHODIMP
- HTMLTextAreaElement::SaveState()
- {
- nsresult rv = NS_OK;
- // Only save if value != defaultValue (bug 62713)
- nsPresState *state = nullptr;
- if (mValueChanged) {
- state = GetPrimaryPresState();
- if (state) {
- nsAutoString value;
- GetValueInternal(value, true);
- rv = nsLinebreakConverter::ConvertStringLineBreaks(
- value,
- nsLinebreakConverter::eLinebreakPlatform,
- nsLinebreakConverter::eLinebreakContent);
- if (NS_FAILED(rv)) {
- NS_ERROR("Converting linebreaks failed!");
- return rv;
- }
- nsCOMPtr<nsISupportsString> pState =
- do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
- if (!pState) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- pState->SetData(value);
- state->SetStateProperty(pState);
- }
- }
- if (mDisabledChanged) {
- if (!state) {
- state = GetPrimaryPresState();
- rv = NS_OK;
- }
- if (state) {
- // We do not want to save the real disabled state but the disabled
- // attribute.
- state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
- }
- }
- return rv;
- }
- bool
- HTMLTextAreaElement::RestoreState(nsPresState* aState)
- {
- nsCOMPtr<nsISupportsString> state
- (do_QueryInterface(aState->GetStateProperty()));
-
- if (state) {
- nsAutoString data;
- state->GetData(data);
- nsresult rv = SetValue(data);
- NS_ENSURE_SUCCESS(rv, false);
- }
- if (aState->IsDisabledSet()) {
- SetDisabled(aState->GetDisabled());
- }
- return false;
- }
- EventStates
- HTMLTextAreaElement::IntrinsicState() const
- {
- EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
- if (HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
- state |= NS_EVENT_STATE_REQUIRED;
- } else {
- state |= NS_EVENT_STATE_OPTIONAL;
- }
- if (IsCandidateForConstraintValidation()) {
- if (IsValid()) {
- state |= NS_EVENT_STATE_VALID;
- } else {
- state |= NS_EVENT_STATE_INVALID;
- // :-moz-ui-invalid always apply if the element suffers from a custom
- // error and never applies if novalidate is set on the form owner.
- if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
- (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
- (mCanShowInvalidUI && ShouldShowValidityUI()))) {
- state |= NS_EVENT_STATE_MOZ_UI_INVALID;
- }
- }
- // :-moz-ui-valid applies if all the following are true:
- // 1. The element is not focused, or had either :-moz-ui-valid or
- // :-moz-ui-invalid applying before it was focused ;
- // 2. The element is either valid or isn't allowed to have
- // :-moz-ui-invalid applying ;
- // 3. The element has no form owner or its form owner doesn't have the
- // novalidate attribute set ;
- // 4. The element has already been modified or the user tried to submit the
- // form owner while invalid.
- if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
- (mCanShowValidUI && ShouldShowValidityUI() &&
- (IsValid() || (state.HasState(NS_EVENT_STATE_MOZ_UI_INVALID) &&
- !mCanShowInvalidUI)))) {
- state |= NS_EVENT_STATE_MOZ_UI_VALID;
- }
- }
- if (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder) &&
- IsValueEmpty()) {
- state |= NS_EVENT_STATE_PLACEHOLDERSHOWN;
- }
- return state;
- }
- nsresult
- HTMLTextAreaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
- nsIContent* aBindingParent,
- bool aCompileEventHandlers)
- {
- nsresult rv = nsGenericHTMLFormElementWithState::BindToTree(aDocument, aParent,
- aBindingParent,
- aCompileEventHandlers);
- NS_ENSURE_SUCCESS(rv, rv);
- // If there is a disabled fieldset in the parent chain, the element is now
- // barred from constraint validation and can't suffer from value missing.
- UpdateValueMissingValidityState();
- UpdateBarredFromConstraintValidation();
- // And now make sure our state is up to date
- UpdateState(false);
- return rv;
- }
- void
- HTMLTextAreaElement::UnbindFromTree(bool aDeep, bool aNullParent)
- {
- nsGenericHTMLFormElementWithState::UnbindFromTree(aDeep, aNullParent);
- // We might be no longer disabled because of parent chain changed.
- UpdateValueMissingValidityState();
- UpdateBarredFromConstraintValidation();
- // And now make sure our state is up to date
- UpdateState(false);
- }
- nsresult
- HTMLTextAreaElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValueOrString* aValue,
- bool aNotify)
- {
- if (aNotify && aName == nsGkAtoms::disabled &&
- aNameSpaceID == kNameSpaceID_None) {
- mDisabledChanged = true;
- }
- return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
- }
- void
- HTMLTextAreaElement::CharacterDataChanged(nsIDocument* aDocument,
- nsIContent* aContent,
- CharacterDataChangeInfo* aInfo)
- {
- ContentChanged(aContent);
- }
- void
- HTMLTextAreaElement::ContentAppended(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aFirstNewContent,
- int32_t /* unused */)
- {
- ContentChanged(aFirstNewContent);
- }
- void
- HTMLTextAreaElement::ContentInserted(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aChild,
- int32_t /* unused */)
- {
- ContentChanged(aChild);
- }
- void
- HTMLTextAreaElement::ContentRemoved(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aChild,
- int32_t aIndexInContainer,
- nsIContent* aPreviousSibling)
- {
- ContentChanged(aChild);
- }
- void
- HTMLTextAreaElement::ContentChanged(nsIContent* aContent)
- {
- if (!mValueChanged && mDoneAddingChildren &&
- nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
- // Hard to say what the reset can trigger, so be safe pending
- // further auditing.
- nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
- Reset();
- }
- }
- nsresult
- HTMLTextAreaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue,
- const nsAttrValue* aOldValue, bool aNotify)
- {
- if (aNameSpaceID == kNameSpaceID_None) {
- if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
- aName == nsGkAtoms::readonly) {
- UpdateValueMissingValidityState();
- // This *has* to be called *after* validity has changed.
- if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
- UpdateBarredFromConstraintValidation();
- }
- } else if (aName == nsGkAtoms::maxlength) {
- UpdateTooLongValidityState();
- } else if (aName == nsGkAtoms::minlength) {
- UpdateTooShortValidityState();
- }
- }
- return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, aValue,
- aOldValue, aNotify);
- }
- nsresult
- HTMLTextAreaElement::CopyInnerTo(Element* aDest)
- {
- nsresult rv = nsGenericHTMLFormElementWithState::CopyInnerTo(aDest);
- NS_ENSURE_SUCCESS(rv, rv);
- if (aDest->OwnerDoc()->IsStaticDocument()) {
- nsAutoString value;
- GetValueInternal(value, true);
- return static_cast<HTMLTextAreaElement*>(aDest)->SetValue(value);
- }
- return NS_OK;
- }
- bool
- HTMLTextAreaElement::IsMutable() const
- {
- return (!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) && !IsDisabled());
- }
- bool
- HTMLTextAreaElement::IsValueEmpty() const
- {
- nsAutoString value;
- GetValueInternal(value, true);
- return value.IsEmpty();
- }
- // nsIConstraintValidation
- NS_IMETHODIMP
- HTMLTextAreaElement::SetCustomValidity(const nsAString& aError)
- {
- nsIConstraintValidation::SetCustomValidity(aError);
- UpdateState(true);
- return NS_OK;
- }
- bool
- HTMLTextAreaElement::IsTooLong()
- {
- if (!mValueChanged ||
- !mLastValueChangeWasInteractive ||
- !HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength)) {
- return false;
- }
- int32_t maxLength = -1;
- GetMaxLength(&maxLength);
- // Maxlength of -1 means parsing error.
- if (maxLength == -1) {
- return false;
- }
- int32_t textLength = -1;
- GetTextLength(&textLength);
- return textLength > maxLength;
- }
- bool
- HTMLTextAreaElement::IsTooShort()
- {
- if (!mValueChanged ||
- !mLastValueChangeWasInteractive ||
- !HasAttr(kNameSpaceID_None, nsGkAtoms::minlength)) {
- return false;
- }
- int32_t minLength = -1;
- GetMinLength(&minLength);
- // Minlength of -1 means parsing error.
- if (minLength == -1) {
- return false;
- }
- int32_t textLength = -1;
- GetTextLength(&textLength);
- return textLength && textLength < minLength;
- }
- bool
- HTMLTextAreaElement::IsValueMissing() const
- {
- if (!HasAttr(kNameSpaceID_None, nsGkAtoms::required) || !IsMutable()) {
- return false;
- }
- return IsValueEmpty();
- }
- void
- HTMLTextAreaElement::UpdateTooLongValidityState()
- {
- SetValidityState(VALIDITY_STATE_TOO_LONG, IsTooLong());
- }
- void
- HTMLTextAreaElement::UpdateTooShortValidityState()
- {
- SetValidityState(VALIDITY_STATE_TOO_SHORT, IsTooShort());
- }
- void
- HTMLTextAreaElement::UpdateValueMissingValidityState()
- {
- SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
- }
- void
- HTMLTextAreaElement::UpdateBarredFromConstraintValidation()
- {
- SetBarredFromConstraintValidation(HasAttr(kNameSpaceID_None,
- nsGkAtoms::readonly) ||
- IsDisabled());
- }
- nsresult
- HTMLTextAreaElement::GetValidationMessage(nsAString& aValidationMessage,
- ValidityStateType aType)
- {
- nsresult rv = NS_OK;
- switch (aType)
- {
- case VALIDITY_STATE_TOO_LONG:
- {
- nsXPIDLString message;
- int32_t maxLength = -1;
- int32_t textLength = -1;
- nsAutoString strMaxLength;
- nsAutoString strTextLength;
- GetMaxLength(&maxLength);
- GetTextLength(&textLength);
- strMaxLength.AppendInt(maxLength);
- strTextLength.AppendInt(textLength);
- const char16_t* params[] = { strMaxLength.get(), strTextLength.get() };
- rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
- "FormValidationTextTooLong",
- params, message);
- aValidationMessage = message;
- }
- break;
- case VALIDITY_STATE_TOO_SHORT:
- {
- nsXPIDLString message;
- int32_t minLength = -1;
- int32_t textLength = -1;
- nsAutoString strMinLength;
- nsAutoString strTextLength;
- GetMinLength(&minLength);
- GetTextLength(&textLength);
- strMinLength.AppendInt(minLength);
- strTextLength.AppendInt(textLength);
- const char16_t* params[] = { strMinLength.get(), strTextLength.get() };
- rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
- "FormValidationTextTooShort",
- params, message);
- aValidationMessage = message;
- }
- break;
- case VALIDITY_STATE_VALUE_MISSING:
- {
- nsXPIDLString message;
- rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
- "FormValidationValueMissing",
- message);
- aValidationMessage = message;
- }
- break;
- default:
- rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
- }
- return rv;
- }
- NS_IMETHODIMP_(bool)
- HTMLTextAreaElement::IsSingleLineTextControl() const
- {
- return false;
- }
- NS_IMETHODIMP_(bool)
- HTMLTextAreaElement::IsTextArea() const
- {
- return true;
- }
- NS_IMETHODIMP_(bool)
- HTMLTextAreaElement::IsPlainTextControl() const
- {
- // need to check our HTML attribute and/or CSS.
- return true;
- }
- NS_IMETHODIMP_(bool)
- HTMLTextAreaElement::IsPasswordTextControl() const
- {
- return false;
- }
- NS_IMETHODIMP_(int32_t)
- HTMLTextAreaElement::GetCols()
- {
- return Cols();
- }
- NS_IMETHODIMP_(int32_t)
- HTMLTextAreaElement::GetWrapCols()
- {
- // wrap=off means -1 for wrap width no matter what cols is
- nsHTMLTextWrap wrapProp;
- nsITextControlElement::GetWrapPropertyEnum(this, wrapProp);
- if (wrapProp == nsITextControlElement::eHTMLTextWrap_Off) {
- // do not wrap when wrap=off
- return 0;
- }
- // Otherwise we just wrap at the given number of columns
- return GetCols();
- }
- NS_IMETHODIMP_(int32_t)
- HTMLTextAreaElement::GetRows()
- {
- const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::rows);
- if (attr && attr->Type() == nsAttrValue::eInteger) {
- int32_t rows = attr->GetIntegerValue();
- return (rows <= 0) ? DEFAULT_ROWS_TEXTAREA : rows;
- }
- return DEFAULT_ROWS_TEXTAREA;
- }
- NS_IMETHODIMP_(void)
- HTMLTextAreaElement::GetDefaultValueFromContent(nsAString& aValue)
- {
- GetDefaultValue(aValue);
- }
- NS_IMETHODIMP_(bool)
- HTMLTextAreaElement::ValueChanged() const
- {
- return mValueChanged;
- }
- NS_IMETHODIMP_(void)
- HTMLTextAreaElement::GetTextEditorValue(nsAString& aValue,
- bool aIgnoreWrap) const
- {
- mState.GetValue(aValue, aIgnoreWrap);
- }
- NS_IMETHODIMP_(void)
- HTMLTextAreaElement::InitializeKeyboardEventListeners()
- {
- mState.InitializeKeyboardEventListeners();
- }
- NS_IMETHODIMP_(void)
- HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
- {
- mLastValueChangeWasInteractive = aWasInteractiveUserChange;
- // Update the validity state
- bool validBefore = IsValid();
- UpdateTooLongValidityState();
- UpdateTooShortValidityState();
- UpdateValueMissingValidityState();
- if (validBefore != IsValid() ||
- HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
- UpdateState(aNotify);
- }
- }
- NS_IMETHODIMP_(bool)
- HTMLTextAreaElement::HasCachedSelection()
- {
- return mState.IsSelectionCached();
- }
- void
- HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify)
- {
- UpdateValueMissingValidityState();
- UpdateBarredFromConstraintValidation();
- nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
- }
- JSObject*
- HTMLTextAreaElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return HTMLTextAreaElementBinding::Wrap(aCx, this, aGivenProto);
- }
- } // namespace dom
- } // namespace mozilla
|