diff options
Diffstat (limited to 'dom/html/HTMLOutputElement.cpp')
-rw-r--r-- | dom/html/HTMLOutputElement.cpp | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/dom/html/HTMLOutputElement.cpp b/dom/html/HTMLOutputElement.cpp new file mode 100644 index 0000000000..4d6688a766 --- /dev/null +++ b/dom/html/HTMLOutputElement.cpp @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/HTMLOutputElement.h" + +#include "mozAutoDocUpdate.h" +#include "mozilla/EventStates.h" +#include "mozilla/dom/HTMLFormElement.h" +#include "mozilla/dom/HTMLFormSubmission.h" +#include "mozilla/dom/HTMLOutputElementBinding.h" +#include "nsContentUtils.h" +#include "nsDOMTokenList.h" + +NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Output) + +namespace mozilla::dom { + +HTMLOutputElement::HTMLOutputElement( + already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, + FromParser aFromParser) + : nsGenericHTMLFormElement(std::move(aNodeInfo), NS_FORM_OUTPUT), + mValueModeFlag(eModeDefault), + mIsDoneAddingChildren(!aFromParser) { + AddMutationObserver(this); + + // We start out valid and ui-valid (since we have no form). + AddStatesSilently(NS_EVENT_STATE_VALID | NS_EVENT_STATE_MOZ_UI_VALID); +} + +HTMLOutputElement::~HTMLOutputElement() = default; + +NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLOutputElement, nsGenericHTMLFormElement, + mValidity, mTokenList) + +NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLOutputElement, + nsGenericHTMLFormElement, + nsIMutationObserver, + nsIConstraintValidation) + +NS_IMPL_ELEMENT_CLONE(HTMLOutputElement) + +void HTMLOutputElement::SetCustomValidity(const nsAString& aError) { + nsIConstraintValidation::SetCustomValidity(aError); + + UpdateState(true); +} + +NS_IMETHODIMP +HTMLOutputElement::Reset() { + mValueModeFlag = eModeDefault; + return nsContentUtils::SetNodeTextContent(this, mDefaultValue, true); +} + +NS_IMETHODIMP +HTMLOutputElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission) { + // The output element is not submittable. + return NS_OK; +} + +bool HTMLOutputElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, + const nsAString& aValue, + nsIPrincipal* aMaybeScriptedPrincipal, + nsAttrValue& aResult) { + if (aNamespaceID == kNameSpaceID_None) { + if (aAttribute == nsGkAtoms::_for) { + aResult.ParseAtomArray(aValue); + return true; + } + } + + return nsGenericHTMLFormElement::ParseAttribute( + aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult); +} + +void HTMLOutputElement::DoneAddingChildren(bool aHaveNotified) { + mIsDoneAddingChildren = true; +} + +EventStates HTMLOutputElement::IntrinsicState() const { + EventStates states = nsGenericHTMLFormElement::IntrinsicState(); + + // We don't have to call IsCandidateForConstraintValidation() + // because <output> can't be barred from constraint validation. + if (IsValid()) { + states |= NS_EVENT_STATE_VALID; + if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) { + states |= NS_EVENT_STATE_MOZ_UI_VALID; + } + } else { + states |= NS_EVENT_STATE_INVALID; + if (!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) { + states |= NS_EVENT_STATE_MOZ_UI_INVALID; + } + } + + return states; +} + +nsresult HTMLOutputElement::BindToTree(BindContext& aContext, + nsINode& aParent) { + nsresult rv = nsGenericHTMLFormElement::BindToTree(aContext, aParent); + NS_ENSURE_SUCCESS(rv, rv); + + // Unfortunately, we can actually end up having to change our state + // as a result of being bound to a tree even from the parser: we + // might end up a in a novalidate form, and unlike other form + // controls that on its own is enough to make change ui-valid state. + // So just go ahead and update our state now. + UpdateState(false); + + return rv; +} + +void HTMLOutputElement::GetValue(nsAString& aValue) { + nsContentUtils::GetNodeTextContent(this, true, aValue); +} + +void HTMLOutputElement::SetValue(const nsAString& aValue, ErrorResult& aRv) { + mValueModeFlag = eModeValue; + aRv = nsContentUtils::SetNodeTextContent(this, aValue, true); +} + +void HTMLOutputElement::SetDefaultValue(const nsAString& aDefaultValue, + ErrorResult& aRv) { + mDefaultValue = aDefaultValue; + if (mValueModeFlag == eModeDefault) { + // We can't pass mDefaultValue, because it'll be truncated when + // the element's descendants are changed. + aRv = nsContentUtils::SetNodeTextContent(this, aDefaultValue, true); + } +} + +nsDOMTokenList* HTMLOutputElement::HtmlFor() { + if (!mTokenList) { + mTokenList = new nsDOMTokenList(this, nsGkAtoms::_for); + } + return mTokenList; +} + +void HTMLOutputElement::DescendantsChanged() { + if (mIsDoneAddingChildren && mValueModeFlag == eModeDefault) { + nsContentUtils::GetNodeTextContent(this, true, mDefaultValue); + } +} + +// nsIMutationObserver + +void HTMLOutputElement::CharacterDataChanged(nsIContent* aContent, + const CharacterDataChangeInfo&) { + DescendantsChanged(); +} + +void HTMLOutputElement::ContentAppended(nsIContent* aFirstNewContent) { + DescendantsChanged(); +} + +void HTMLOutputElement::ContentInserted(nsIContent* aChild) { + DescendantsChanged(); +} + +void HTMLOutputElement::ContentRemoved(nsIContent* aChild, + nsIContent* aPreviousSibling) { + DescendantsChanged(); +} + +JSObject* HTMLOutputElement::WrapNode(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return HTMLOutputElement_Binding::Wrap(aCx, this, aGivenProto); +} + +} // namespace mozilla::dom |