mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 1850293 - Make validity states non-intrinsic. r=smaug
Add a RAII helper to notify of multiple state changes together for these. The UpdateState CustomElementInternals calls that are getting removed are unnecessary (the state should be up-to-date by then, there's nothing changing there particularly). Same for the call in nsGenericHTMLFormElement::UnbindFromTree. ClearForm already does an state update. Differential Revision: https://phabricator.services.mozilla.com/D187033
This commit is contained in:
parent
7855659a73
commit
c27a2129fd
@ -651,9 +651,7 @@ class Element : public FragmentOrElement {
|
||||
|
||||
const AttrArray& GetAttrs() const { return mAttrs; }
|
||||
|
||||
void SetDefined(bool aSet) {
|
||||
SetStates(ElementState::DEFINED, aSet);
|
||||
}
|
||||
void SetDefined(bool aSet) { SetStates(ElementState::DEFINED, aSet); }
|
||||
|
||||
// AccessibilityRole
|
||||
REFLECT_DOMSTRING_ATTR(Role, role)
|
||||
@ -728,6 +726,25 @@ class Element : public FragmentOrElement {
|
||||
already_AddRefed<ShadowRoot> AttachShadowInternal(ShadowRootMode,
|
||||
ErrorResult& aError);
|
||||
|
||||
struct AutoStateChangeNotifier {
|
||||
AutoStateChangeNotifier(Element& aElement, bool aNotify)
|
||||
: mElement(aElement), mOldState(aElement.State()), mNotify(aNotify) {}
|
||||
~AutoStateChangeNotifier() {
|
||||
if (!mNotify) {
|
||||
return;
|
||||
}
|
||||
ElementState newState = mElement.State();
|
||||
if (mOldState != newState) {
|
||||
mElement.NotifyStateChange(mOldState ^ newState);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Element& mElement;
|
||||
const ElementState mOldState;
|
||||
const bool mNotify;
|
||||
};
|
||||
|
||||
public:
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsIScrollableFrame* GetScrollFrame(nsIFrame** aStyledFrame = nullptr,
|
||||
|
@ -66,7 +66,7 @@ bool Link::ElementHasHref() const {
|
||||
}
|
||||
|
||||
void Link::SetLinkState(State aState, bool aNotify) {
|
||||
auto old = mElement->State();
|
||||
Element::AutoStateChangeNotifier notifier(*mElement, aNotify);
|
||||
switch (aState) {
|
||||
case State::Visited:
|
||||
mElement->AddStatesSilently(ElementState::VISITED);
|
||||
@ -80,9 +80,6 @@ void Link::SetLinkState(State aState, bool aNotify) {
|
||||
mElement->RemoveStatesSilently(ElementState::VISITED_OR_UNVISITED);
|
||||
break;
|
||||
}
|
||||
if (aNotify) {
|
||||
mElement->NotifyStateChange(old ^ mElement->State());
|
||||
}
|
||||
}
|
||||
|
||||
void Link::TriggerLinkUpdate(bool aNotify) {
|
||||
|
@ -46,6 +46,8 @@ bitflags! {
|
||||
const USER_VALID = 1 << 12;
|
||||
/// <https://drafts.csswg.org/selectors-4/#user-invalid-pseudo>
|
||||
const USER_INVALID = 1 << 13;
|
||||
/// All the validity bits at once.
|
||||
const VALIDITY_STATES = Self::VALID.bits | Self::INVALID.bits | Self::USER_VALID.bits | Self::USER_INVALID.bits;
|
||||
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken
|
||||
const BROKEN = 1 << 14;
|
||||
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-loading
|
||||
@ -188,7 +190,8 @@ bitflags! {
|
||||
Self::INRANGE.bits |
|
||||
Self::OUTOFRANGE.bits |
|
||||
Self::VISITED.bits |
|
||||
Self::UNVISITED.bits;
|
||||
Self::UNVISITED.bits |
|
||||
Self::VALIDITY_STATES.bits;
|
||||
|
||||
const INTRINSIC_STATES = !Self::EXTERNALLY_MANAGED_STATES.bits;
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ void ElementInternals::SetValidity(
|
||||
SetValidityState(VALIDITY_STATE_STEP_MISMATCH, aFlags.mStepMismatch);
|
||||
SetValidityState(VALIDITY_STATE_BAD_INPUT, aFlags.mBadInput);
|
||||
SetValidityState(VALIDITY_STATE_CUSTOM_ERROR, aFlags.mCustomError);
|
||||
mTarget->UpdateState(true);
|
||||
mTarget->UpdateValidityElementStates(true);
|
||||
|
||||
/**
|
||||
* 5. Set element's validation message to the empty string if message is not
|
||||
@ -305,8 +305,6 @@ bool ElementInternals::ReportValidity(ErrorResult& aRv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mTarget->UpdateState(true);
|
||||
|
||||
RefPtr<CustomEvent> event =
|
||||
NS_NewDOMCustomEvent(mTarget->OwnerDoc(), nullptr, nullptr);
|
||||
event->InitCustomEvent(jsapi.cx(), u"MozInvalidForm"_ns,
|
||||
@ -448,8 +446,6 @@ nsresult ElementInternals::SetAttr(nsAtom* aName, const nsAString& aValue) {
|
||||
|
||||
MutationObservers::NotifyARIAAttributeDefaultChanged(mTarget, aName, modType);
|
||||
|
||||
mTarget->UpdateState(true);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,7 @@ NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
|
||||
|
||||
void HTMLButtonElement::SetCustomValidity(const nsAString& aError) {
|
||||
ConstraintValidation::SetCustomValidity(aError);
|
||||
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
void HTMLButtonElement::UpdateBarredFromConstraintValidation() {
|
||||
@ -94,7 +93,7 @@ void HTMLButtonElement::FieldSetDisabledChanged(bool aNotify) {
|
||||
nsGenericHTMLFormControlElementWithState::FieldSetDisabledChanged(aNotify);
|
||||
|
||||
UpdateBarredFromConstraintValidation();
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLButtonElement)
|
||||
@ -269,9 +268,7 @@ nsresult HTMLButtonElement::BindToTree(BindContext& aContext,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
// Update our state; we may now be the default submit element
|
||||
UpdateState(false);
|
||||
UpdateValidityElementStates(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -280,9 +277,7 @@ void HTMLButtonElement::UnbindFromTree(bool aNullParent) {
|
||||
nsGenericHTMLFormControlElementWithState::UnbindFromTree(aNullParent);
|
||||
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
// Update our state; we may no longer be the default submit element
|
||||
UpdateState(false);
|
||||
UpdateValidityElementStates(false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -358,6 +353,7 @@ void HTMLButtonElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
}
|
||||
|
||||
UpdateBarredFromConstraintValidation();
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,23 +379,20 @@ bool HTMLButtonElement::RestoreState(PresState* aState) {
|
||||
if (aState && aState->disabledSet() && !aState->disabled()) {
|
||||
SetDisabled(false, IgnoreErrors());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ElementState HTMLButtonElement::IntrinsicState() const {
|
||||
ElementState state =
|
||||
nsGenericHTMLFormControlElementWithState::IntrinsicState();
|
||||
|
||||
if (IsCandidateForConstraintValidation()) {
|
||||
if (IsValid()) {
|
||||
state |= ElementState::VALID | ElementState::USER_VALID;
|
||||
} else {
|
||||
state |= ElementState::INVALID | ElementState::USER_INVALID;
|
||||
}
|
||||
void HTMLButtonElement::UpdateValidityElementStates(bool aNotify) {
|
||||
AutoStateChangeNotifier notifier(*this, aNotify);
|
||||
RemoveStatesSilently(ElementState::VALIDITY_STATES);
|
||||
if (!IsCandidateForConstraintValidation()) {
|
||||
return;
|
||||
}
|
||||
if (IsValid()) {
|
||||
AddStatesSilently(ElementState::VALID | ElementState::USER_VALID);
|
||||
} else {
|
||||
AddStatesSilently(ElementState::INVALID | ElementState::USER_INVALID);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
JSObject* HTMLButtonElement::WrapNode(JSContext* aCx,
|
||||
|
@ -64,8 +64,7 @@ class HTMLButtonElement final : public nsGenericHTMLFormControlElementWithState,
|
||||
void DoneCreatingElement() override;
|
||||
|
||||
void UpdateBarredFromConstraintValidation();
|
||||
// Element
|
||||
ElementState IntrinsicState() const override;
|
||||
void UpdateValidityElementStates(bool aNotify) final;
|
||||
/**
|
||||
* Called when an attribute is about to be changed
|
||||
*/
|
||||
|
@ -331,24 +331,25 @@ void HTMLElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
UpdateReadOnlyState(aNotify);
|
||||
}
|
||||
UpdateBarredFromConstraintValidation();
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormElement::AfterSetAttr(
|
||||
aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
|
||||
}
|
||||
|
||||
ElementState HTMLElement::IntrinsicState() const {
|
||||
ElementState state = nsGenericHTMLFormElement::IntrinsicState();
|
||||
if (ElementInternals* internals = GetElementInternals()) {
|
||||
if (internals->IsCandidateForConstraintValidation()) {
|
||||
if (internals->IsValid()) {
|
||||
state |= ElementState::VALID | ElementState::USER_VALID;
|
||||
} else {
|
||||
state |= ElementState::INVALID | ElementState::USER_INVALID;
|
||||
}
|
||||
}
|
||||
void HTMLElement::UpdateValidityElementStates(bool aNotify) {
|
||||
AutoStateChangeNotifier notifier(*this, aNotify);
|
||||
RemoveStatesSilently(ElementState::VALIDITY_STATES);
|
||||
ElementInternals* internals = GetElementInternals();
|
||||
if (!internals || !internals->IsCandidateForConstraintValidation()) {
|
||||
return;
|
||||
}
|
||||
if (internals->IsValid()) {
|
||||
AddStatesSilently(ElementState::VALID | ElementState::USER_VALID);
|
||||
} else {
|
||||
AddStatesSilently(ElementState::INVALID | ElementState::USER_INVALID);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void HTMLElement::SetFormInternal(HTMLFormElement* aForm, bool aBindToTree) {
|
||||
|
@ -49,6 +49,7 @@ class HTMLElement final : public nsGenericHTMLFormElement {
|
||||
void AfterClearForm(bool aUnbindOrDelete) override;
|
||||
void FieldSetDisabledChanged(bool aNotify) override;
|
||||
void SaveState() override;
|
||||
void UpdateValidityElementStates(bool aNotify) final;
|
||||
|
||||
void UpdateFormOwner();
|
||||
|
||||
@ -67,7 +68,6 @@ class HTMLElement final : public nsGenericHTMLFormElement {
|
||||
const nsAttrValue* aValue, const nsAttrValue* aOldValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
bool aNotify) override;
|
||||
ElementState IntrinsicState() const override;
|
||||
|
||||
// nsGenericHTMLFormElement
|
||||
void SetFormInternal(HTMLFormElement* aForm, bool aBindToTree) override;
|
||||
|
@ -294,7 +294,10 @@ void HTMLFieldSetElement::UpdateValidity(bool aElementValidity) {
|
||||
// - or there is one invalid elmement and an element just became invalid.
|
||||
if (!mInvalidElementsCount ||
|
||||
(mInvalidElementsCount == 1 && !aElementValidity)) {
|
||||
UpdateState(true);
|
||||
AutoStateChangeNotifier notifier(*this, true);
|
||||
RemoveStatesSilently(ElementState::VALID | ElementState::INVALID);
|
||||
AddStatesSilently(mInvalidElementsCount ? ElementState::INVALID
|
||||
: ElementState::VALID);
|
||||
}
|
||||
|
||||
// We should propagate the change to the fieldset parent chain.
|
||||
@ -303,18 +306,6 @@ void HTMLFieldSetElement::UpdateValidity(bool aElementValidity) {
|
||||
}
|
||||
}
|
||||
|
||||
ElementState HTMLFieldSetElement::IntrinsicState() const {
|
||||
ElementState state = nsGenericHTMLFormControlElement::IntrinsicState();
|
||||
|
||||
if (mInvalidElementsCount) {
|
||||
state |= ElementState::INVALID;
|
||||
} else {
|
||||
state |= ElementState::VALID;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
JSObject* HTMLFieldSetElement::WrapNode(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return HTMLFieldSetElement_Binding::Wrap(aCx, this, aGivenProto);
|
||||
|
@ -90,8 +90,6 @@ class HTMLFieldSetElement final : public nsGenericHTMLFormControlElement,
|
||||
|
||||
// XPCOM SetCustomValidity is OK for us
|
||||
|
||||
ElementState IntrinsicState() const override;
|
||||
|
||||
/*
|
||||
* This method will update the fieldset's validity. This method has to be
|
||||
* called by fieldset elements whenever their validity state or status
|
||||
@ -133,7 +131,7 @@ class HTMLFieldSetElement final : public nsGenericHTMLFormControlElement,
|
||||
* Number of invalid and candidate for constraint validation
|
||||
* elements in the fieldSet the last time UpdateValidity has been called.
|
||||
*
|
||||
* @note Should only be used by UpdateValidity() and IntrinsicState()!
|
||||
* @note Should only be used by UpdateValidity()
|
||||
*/
|
||||
int32_t mInvalidElementsCount;
|
||||
};
|
||||
|
@ -65,6 +65,8 @@
|
||||
|
||||
// radio buttons
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
#include "mozilla/dom/HTMLButtonElement.h"
|
||||
#include "mozilla/dom/HTMLSelectElement.h"
|
||||
#include "nsIRadioVisitor.h"
|
||||
#include "RadioNodeList.h"
|
||||
|
||||
@ -388,9 +390,6 @@ static void CollectOrphans(nsINode* aRemovalRoot,
|
||||
nsCOMPtr<nsIFormControl> fc = do_QueryInterface(node);
|
||||
MOZ_ASSERT(fc);
|
||||
fc->ClearForm(true, false);
|
||||
|
||||
// When a form control loses its form owner, its state can change.
|
||||
node->UpdateState(true);
|
||||
#ifdef DEBUG
|
||||
removed = true;
|
||||
#endif
|
||||
@ -1215,7 +1214,6 @@ nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
|
||||
// unless it replaces what's in the slot. If it _does_ replace what's in
|
||||
// the slot, it becomes the default submit if either the default submit is
|
||||
// what's in the slot or the child is earlier than the default submit.
|
||||
nsGenericHTMLFormElement* oldDefaultSubmit = mDefaultSubmitElement;
|
||||
if (!*firstSubmitSlot ||
|
||||
(!lastElement && nsContentUtils::CompareTreePosition(
|
||||
aChild, *firstSubmitSlot, this) < 0)) {
|
||||
@ -1236,13 +1234,6 @@ nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
|
||||
mDefaultSubmitElement == mFirstSubmitNotInElements ||
|
||||
!mDefaultSubmitElement,
|
||||
"What happened here?");
|
||||
|
||||
// Notify that the state of the previous default submit element has changed
|
||||
// if the element which is the default submit element has changed. The new
|
||||
// default submit element is responsible for its own state update.
|
||||
if (oldDefaultSubmit && oldDefaultSubmit != mDefaultSubmitElement) {
|
||||
oldDefaultSubmit->UpdateState(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
// If the element is subject to constraint validaton and is invalid, we need
|
||||
@ -1342,7 +1333,7 @@ nsresult HTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
|
||||
// own notifications.
|
||||
}
|
||||
|
||||
// If the element was subject to constraint validaton and is invalid, we need
|
||||
// If the element was subject to constraint validation and is invalid, we need
|
||||
// to update our internal counter.
|
||||
if (aUpdateValidity) {
|
||||
nsCOMPtr<nsIConstraintValidation> cvElmt = do_QueryObject(aChild);
|
||||
@ -1794,30 +1785,27 @@ bool HTMLFormElement::CheckValidFormSubmission() {
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
for (uint32_t i = 0, length = mControls->mElements.Length(); i < length;
|
||||
++i) {
|
||||
for (nsGenericHTMLFormElement* element : mControls->mElements) {
|
||||
// Input elements can trigger a form submission and we want to
|
||||
// update the style in that case.
|
||||
if (mControls->mElements[i]->IsHTMLElement(nsGkAtoms::input) &&
|
||||
// We don't use nsContentUtils::IsFocusedContent here, because it
|
||||
// doesn't really do what we want for number controls: it's true
|
||||
// for the anonymous textnode inside, but not the number control
|
||||
// itself. We can use the focus state, though, because that gets
|
||||
// synced to the number control by the anonymous text control.
|
||||
mControls->mElements[i]->State().HasState(ElementState::FOCUS)) {
|
||||
static_cast<HTMLInputElement*>(mControls->mElements[i])
|
||||
->UpdateValidityUIBits(true);
|
||||
if (auto* input = HTMLInputElement::FromNode(*element)) {
|
||||
// We don't use nsContentUtils::IsFocusedContent here, because it
|
||||
// doesn't really do what we want for number controls: it's true
|
||||
// for the anonymous textnode inside, but not the number control
|
||||
// itself. We can use the focus state, though, because that gets
|
||||
// synced to the number control by the anonymous text control.
|
||||
if (input->State().HasState(ElementState::FOCUS)) {
|
||||
input->UpdateValidityUIBits(true);
|
||||
}
|
||||
}
|
||||
|
||||
mControls->mElements[i]->UpdateState(true);
|
||||
element->UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
// Because of backward compatibility, <input type='image'> is not in
|
||||
// elements but can be invalid.
|
||||
// TODO: should probably be removed when bug 606491 will be fixed.
|
||||
for (uint32_t i = 0, length = mControls->mNotInElements.Length();
|
||||
i < length; ++i) {
|
||||
mControls->mNotInElements[i]->UpdateState(true);
|
||||
for (nsGenericHTMLFormElement* element : mControls->mNotInElements) {
|
||||
element->UpdateValidityElementStates(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1861,7 +1849,10 @@ void HTMLFormElement::UpdateValidity(bool aElementValidity) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateState(true);
|
||||
AutoStateChangeNotifier notifier(*this, true);
|
||||
RemoveStatesSilently(ElementState::VALID | ElementState::INVALID);
|
||||
AddStatesSilently(mInvalidElementsCount ? ElementState::INVALID
|
||||
: ElementState::VALID);
|
||||
}
|
||||
|
||||
int32_t HTMLFormElement::IndexOfContent(nsIContent* aContent) {
|
||||
@ -1922,18 +1913,6 @@ void HTMLFormElement::SetValueMissingState(const nsAString& aName,
|
||||
RadioGroupManager::SetValueMissingState(aName, aValue);
|
||||
}
|
||||
|
||||
ElementState HTMLFormElement::IntrinsicState() const {
|
||||
ElementState state = nsGenericHTMLElement::IntrinsicState();
|
||||
|
||||
if (mInvalidElementsCount) {
|
||||
state |= ElementState::INVALID;
|
||||
} else {
|
||||
state |= ElementState::VALID;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void HTMLFormElement::Clear() {
|
||||
for (int32_t i = mImageElements.Length() - 1; i >= 0; i--) {
|
||||
mImageElements[i]->ClearForm(false);
|
||||
|
@ -80,8 +80,6 @@ class HTMLFormElement final : public nsGenericHTMLElement,
|
||||
bool GetValueMissingState(const nsAString& aName) const override;
|
||||
void SetValueMissingState(const nsAString& aName, bool aValue) override;
|
||||
|
||||
ElementState IntrinsicState() const override;
|
||||
|
||||
// EventTarget
|
||||
void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
|
||||
|
||||
|
@ -1214,6 +1214,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
bool aNotify) {
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
bool needValidityUpdate = false;
|
||||
if (aName == nsGkAtoms::src) {
|
||||
mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
|
||||
this, aValue ? aValue->GetStringValue() : EmptyString(),
|
||||
@ -1244,6 +1245,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
// GetStepBase() depends on the `value` attribute if `min` is not present,
|
||||
// even if the value doesn't change.
|
||||
UpdateStepMismatchValidityState();
|
||||
needValidityUpdate = true;
|
||||
}
|
||||
|
||||
// Checked must be set no matter what type of control it is, since
|
||||
@ -1261,6 +1263,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
DoSetChecked(!!aValue, aNotify, false);
|
||||
}
|
||||
}
|
||||
needValidityUpdate = true;
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::type) {
|
||||
@ -1273,6 +1276,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
}
|
||||
if (newType != mType) {
|
||||
HandleTypeChange(newType, aNotify);
|
||||
needValidityUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1282,6 +1286,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
mType == FormControlType::InputRadio && (mForm || mDoneCreating)) {
|
||||
AddedToRadioGroup();
|
||||
UpdateValueMissingValidityStateForRadio(false);
|
||||
needValidityUpdate = true;
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
|
||||
@ -1310,10 +1315,13 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
|
||||
UpdateBarredFromConstraintValidation();
|
||||
}
|
||||
needValidityUpdate = true;
|
||||
} else if (aName == nsGkAtoms::maxlength) {
|
||||
UpdateTooLongValidityState();
|
||||
needValidityUpdate = true;
|
||||
} else if (aName == nsGkAtoms::minlength) {
|
||||
UpdateTooShortValidityState();
|
||||
needValidityUpdate = true;
|
||||
} else if (aName == nsGkAtoms::pattern) {
|
||||
// Although pattern attribute only applies to single line text controls,
|
||||
// we set this flag for all input types to save having to check the type
|
||||
@ -1323,8 +1331,10 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
if (mDoneCreating) {
|
||||
UpdatePatternMismatchValidityState();
|
||||
}
|
||||
needValidityUpdate = true;
|
||||
} else if (aName == nsGkAtoms::multiple) {
|
||||
UpdateTypeMismatchValidityState();
|
||||
needValidityUpdate = true;
|
||||
} else if (aName == nsGkAtoms::max) {
|
||||
UpdateHasRange(aNotify);
|
||||
mInputType->MinMaxStepAttrChanged();
|
||||
@ -1333,6 +1343,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
// We don't assert the state of underflow during creation since
|
||||
// DoneCreatingElement sanitizes.
|
||||
UpdateRangeOverflowValidityState();
|
||||
needValidityUpdate = true;
|
||||
MOZ_ASSERT(!mDoneCreating || mType != FormControlType::InputRange ||
|
||||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow underflow for type=range");
|
||||
@ -1342,6 +1353,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
// See corresponding @max comment
|
||||
UpdateRangeUnderflowValidityState();
|
||||
UpdateStepMismatchValidityState();
|
||||
needValidityUpdate = true;
|
||||
MOZ_ASSERT(!mDoneCreating || mType != FormControlType::InputRange ||
|
||||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow underflow for type=range");
|
||||
@ -1349,6 +1361,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
mInputType->MinMaxStepAttrChanged();
|
||||
// See corresponding @max comment
|
||||
UpdateStepMismatchValidityState();
|
||||
needValidityUpdate = true;
|
||||
MOZ_ASSERT(!mDoneCreating || mType != FormControlType::InputRange ||
|
||||
!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
||||
"HTML5 spec does not allow underflow for type=range");
|
||||
@ -1361,6 +1374,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
if (mType == FormControlType::InputNumber) {
|
||||
// The validity of our value may have changed based on the locale.
|
||||
UpdateValidityState();
|
||||
needValidityUpdate = true;
|
||||
}
|
||||
} else if (aName == nsGkAtoms::autocomplete) {
|
||||
// Clear the cached @autocomplete attribute and autocompleteInfo state.
|
||||
@ -1372,6 +1386,7 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
f->PlaceholderChanged(aOldValue, aValue);
|
||||
}
|
||||
UpdatePlaceholderShownState();
|
||||
needValidityUpdate = true;
|
||||
}
|
||||
|
||||
if (CreatesDateTimeWidget()) {
|
||||
@ -1389,6 +1404,9 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needValidityUpdate) {
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormControlElementWithState::AfterSetAttr(
|
||||
@ -2250,7 +2268,7 @@ void HTMLInputElement::UpdateValidityState() {
|
||||
// become valid/invalid. For other validity states, they will be updated when
|
||||
// .value is actually changed.
|
||||
UpdateBadInputValidityState();
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
bool HTMLInputElement::MozIsTextField(bool aExcludePassword) {
|
||||
@ -2771,9 +2789,7 @@ void HTMLInputElement::SetValueChanged(bool aValueChanged) {
|
||||
mValueChanged = aValueChanged;
|
||||
UpdateTooLongValidityState();
|
||||
UpdateTooShortValidityState();
|
||||
// We need to do this unconditionally because the validity ui bits depend on
|
||||
// this.
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
void HTMLInputElement::SetLastValueChangeWasInteractive(bool aWasInteractive) {
|
||||
@ -2785,7 +2801,7 @@ void HTMLInputElement::SetLastValueChangeWasInteractive(bool aWasInteractive) {
|
||||
UpdateTooLongValidityState();
|
||||
UpdateTooShortValidityState();
|
||||
if (wasValid != IsValid()) {
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2806,15 +2822,11 @@ void HTMLInputElement::DoSetCheckedChanged(bool aCheckedChanged, bool aNotify) {
|
||||
}
|
||||
|
||||
void HTMLInputElement::SetCheckedChangedInternal(bool aCheckedChanged) {
|
||||
bool checkedChangedBefore = mCheckedChanged;
|
||||
|
||||
mCheckedChanged = aCheckedChanged;
|
||||
|
||||
// This method can't be called when we are not authorized to notify
|
||||
// so we do not need a aNotify parameter.
|
||||
if (checkedChangedBefore != aCheckedChanged) {
|
||||
UpdateState(true);
|
||||
if (mCheckedChanged == aCheckedChanged) {
|
||||
return;
|
||||
}
|
||||
mCheckedChanged = aCheckedChanged;
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
void HTMLInputElement::SetChecked(bool aChecked) {
|
||||
@ -2986,8 +2998,7 @@ void HTMLInputElement::SetCheckedInternal(bool aChecked, bool aNotify) {
|
||||
// UpdateState anyway.
|
||||
UpdateAllValidityStatesButNotElementState();
|
||||
UpdateIndeterminateState(aNotify);
|
||||
// validity state still require UpdateState to be called.
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
|
||||
// Notify all radios in the group that value has changed, this is to let
|
||||
// radios to have the chance to update its states, e.g., :indeterminate.
|
||||
@ -3461,7 +3472,7 @@ void HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection) {
|
||||
// regardless because we need the UI to update _now_ or the user will
|
||||
// wonder why the step behavior isn't functioning.
|
||||
UpdateValidityUIBits(true);
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -3627,8 +3638,7 @@ nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
||||
}
|
||||
|
||||
UpdateValidityUIBits(aVisitor.mEvent->mMessage == eFocus);
|
||||
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
@ -4276,7 +4286,7 @@ nsresult HTMLInputElement::BindToTree(BindContext& aContext, nsINode& aParent) {
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
// And now make sure our state is up to date
|
||||
UpdateState(false);
|
||||
UpdateValidityElementStates(true);
|
||||
|
||||
if (CreatesDateTimeWidget() && IsInComposedDoc()) {
|
||||
// Construct Shadow Root so web content can be hidden in the DOM.
|
||||
@ -4325,9 +4335,8 @@ void HTMLInputElement::UnbindFromTree(bool aNullParent) {
|
||||
UpdateValueMissingValidityState();
|
||||
// We might be no longer disabled because of parent chain changed.
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
// And now make sure our state is up to date
|
||||
UpdateState(false);
|
||||
UpdateValidityElementStates(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6062,34 +6071,38 @@ ElementState HTMLInputElement::IntrinsicState() const {
|
||||
if (mType == FormControlType::InputImage) {
|
||||
state |= nsImageLoadingContent::ImageState();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
if (IsCandidateForConstraintValidation()) {
|
||||
if (IsValid()) {
|
||||
state |= ElementState::VALID;
|
||||
} else {
|
||||
state |= ElementState::INVALID;
|
||||
|
||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
||||
state |= ElementState::USER_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// :-moz-ui-valid applies if all of the following conditions 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 already been modified or the user tried to submit the
|
||||
// form owner while invalid.
|
||||
if (mCanShowValidUI && ShouldShowValidityUI() &&
|
||||
(IsValid() ||
|
||||
(!state.HasState(ElementState::USER_INVALID) && !mCanShowInvalidUI))) {
|
||||
state |= ElementState::USER_VALID;
|
||||
void HTMLInputElement::UpdateValidityElementStates(bool aNotify) {
|
||||
AutoStateChangeNotifier notifier(*this, aNotify);
|
||||
RemoveStatesSilently(ElementState::VALIDITY_STATES);
|
||||
if (!IsCandidateForConstraintValidation()) {
|
||||
return;
|
||||
}
|
||||
ElementState state;
|
||||
if (IsValid()) {
|
||||
state |= ElementState::VALID;
|
||||
} else {
|
||||
state |= ElementState::INVALID;
|
||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
||||
state |= ElementState::USER_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
// :-moz-ui-valid applies if all of the following conditions 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 already been modified or the user tried to submit the
|
||||
// form owner while invalid.
|
||||
if (mCanShowValidUI && ShouldShowValidityUI() &&
|
||||
(IsValid() ||
|
||||
(!state.HasState(ElementState::USER_INVALID) && !mCanShowInvalidUI))) {
|
||||
state |= ElementState::USER_VALID;
|
||||
}
|
||||
AddStatesSilently(state);
|
||||
}
|
||||
|
||||
static nsTArray<OwningFileOrDirectory> RestoreFileContentData(
|
||||
@ -6540,8 +6553,7 @@ Decimal HTMLInputElement::GetStep() const {
|
||||
|
||||
void HTMLInputElement::SetCustomValidity(const nsAString& aError) {
|
||||
ConstraintValidation::SetCustomValidity(aError);
|
||||
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
bool HTMLInputElement::IsTooLong() {
|
||||
@ -6705,7 +6717,7 @@ void HTMLInputElement::UpdateAllValidityStates(bool aNotify) {
|
||||
bool validBefore = IsValid();
|
||||
UpdateAllValidityStatesButNotElementState();
|
||||
if (validBefore != IsValid()) {
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6873,7 +6885,7 @@ void HTMLInputElement::FieldSetDisabledChanged(bool aNotify) {
|
||||
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateBarredFromConstraintValidation();
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
|
||||
void HTMLInputElement::SetFilePickerFiltersFromAccept(
|
||||
@ -7115,23 +7127,15 @@ void HTMLInputElement::UpdateValidityUIBits(bool aIsFocused) {
|
||||
}
|
||||
|
||||
void HTMLInputElement::UpdateInRange(bool aNotify) {
|
||||
AutoStateChangeNotifier notifier(*this, aNotify);
|
||||
RemoveStatesSilently(ElementState::INRANGE | ElementState::OUTOFRANGE);
|
||||
if (!mHasRange || !IsCandidateForConstraintValidation()) {
|
||||
RemoveStates(ElementState::INRANGE | ElementState::OUTOFRANGE, aNotify);
|
||||
return;
|
||||
}
|
||||
bool outOfRange = GetValidityState(VALIDITY_STATE_RANGE_OVERFLOW) ||
|
||||
GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW);
|
||||
auto oldState = State();
|
||||
RemoveStatesSilently(ElementState::INRANGE | ElementState::OUTOFRANGE);
|
||||
AddStatesSilently(outOfRange ? ElementState::OUTOFRANGE
|
||||
: ElementState::INRANGE);
|
||||
if (!aNotify) {
|
||||
return;
|
||||
}
|
||||
auto newState = State();
|
||||
if (oldState != newState) {
|
||||
NotifyStateChange(oldState ^ newState);
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLInputElement::UpdateHasRange(bool aNotify) {
|
||||
|
@ -331,6 +331,7 @@ class HTMLInputElement final : public TextControlElement,
|
||||
// as needed. aNotify controls whether the element state update
|
||||
// needs to notify.
|
||||
void UpdateAllValidityStates(bool aNotify);
|
||||
void UpdateValidityElementStates(bool aNotify) final;
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
void MaybeUpdateAllValidityStates(bool aNotify) {
|
||||
// If you need to add new type which supports validationMessage, you should
|
||||
|
@ -56,13 +56,9 @@ void HTMLMeterElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
}
|
||||
|
||||
void HTMLMeterElement::UpdateOptimumState(bool aNotify) {
|
||||
const auto oldState = State();
|
||||
AutoStateChangeNotifier notifier(*this, aNotify);
|
||||
RemoveStatesSilently(ElementState::METER_OPTIMUM_STATES);
|
||||
AddStatesSilently(GetOptimumState());
|
||||
const auto newState = State();
|
||||
if (aNotify && oldState != newState) {
|
||||
NotifyStateChange(oldState ^ newState);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -45,8 +45,6 @@ NS_IMPL_ELEMENT_CLONE(HTMLOutputElement)
|
||||
|
||||
void HTMLOutputElement::SetCustomValidity(const nsAString& aError) {
|
||||
ConstraintValidation::SetCustomValidity(aError);
|
||||
|
||||
UpdateState(true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -79,21 +77,6 @@ void HTMLOutputElement::DoneAddingChildren(bool aHaveNotified) {
|
||||
DescendantsChanged();
|
||||
}
|
||||
|
||||
nsresult HTMLOutputElement::BindToTree(BindContext& aContext,
|
||||
nsINode& aParent) {
|
||||
nsresult rv = nsGenericHTMLFormControlElement::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) const {
|
||||
nsContentUtils::GetNodeTextContent(this, true, aValue);
|
||||
}
|
||||
|
@ -36,14 +36,12 @@ class HTMLOutputElement final : public nsGenericHTMLFormControlElement,
|
||||
|
||||
nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
||||
|
||||
virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult) override;
|
||||
bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult) override;
|
||||
|
||||
virtual void DoneAddingChildren(bool aHaveNotified) override;
|
||||
|
||||
virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
|
||||
void DoneAddingChildren(bool aHaveNotified) override;
|
||||
|
||||
// This function is called when a callback function from nsIMutationObserver
|
||||
// has to be used to update the defaultValue attribute.
|
||||
@ -58,8 +56,7 @@ class HTMLOutputElement final : public nsGenericHTMLFormControlElement,
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLOutputElement,
|
||||
nsGenericHTMLFormControlElement)
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// WebIDL
|
||||
nsDOMTokenList* HtmlFor();
|
||||
|
@ -90,7 +90,7 @@ SafeOptionListMutation::~SafeOptionListMutation() {
|
||||
// update validity here as needed, because by now we know our <option>s
|
||||
// are where they should be.
|
||||
mSelect->UpdateValueMissingValidityState();
|
||||
mSelect->UpdateState(mNotify);
|
||||
mSelect->UpdateValidityElementStates(mNotify);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
mSelect->VerifyOptionsArray();
|
||||
@ -161,8 +161,7 @@ NS_IMPL_ELEMENT_CLONE(HTMLSelectElement)
|
||||
|
||||
void HTMLSelectElement::SetCustomValidity(const nsAString& aError) {
|
||||
ConstraintValidation::SetCustomValidity(aError);
|
||||
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
void HTMLSelectElement::GetAutocomplete(DOMString& aValue) {
|
||||
@ -344,8 +343,7 @@ nsresult HTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
|
||||
// Update the validity state in case of we've just removed the last
|
||||
// option.
|
||||
UpdateValueMissingValidityState();
|
||||
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
@ -681,7 +679,7 @@ void HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
|
||||
|
||||
UpdateSelectedOptions();
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
|
||||
void HTMLSelectElement::FindSelectedIndex(int32_t aStartIndex, bool aNotify) {
|
||||
@ -1010,7 +1008,7 @@ bool HTMLSelectElement::SelectSomething(bool aNotify) {
|
||||
SetSelectedIndexInternal(i, aNotify);
|
||||
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1032,7 +1030,7 @@ nsresult HTMLSelectElement::BindToTree(BindContext& aContext,
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
// And now make sure our state is up to date
|
||||
UpdateState(false);
|
||||
UpdateValidityElementStates(false);
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -1046,7 +1044,7 @@ void HTMLSelectElement::UnbindFromTree(bool aNullParent) {
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
// And now make sure our state is up to date
|
||||
UpdateState(false);
|
||||
UpdateValidityElementStates(false);
|
||||
}
|
||||
|
||||
void HTMLSelectElement::BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
@ -1087,13 +1085,14 @@ void HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateBarredFromConstraintValidation();
|
||||
UpdateValidityElementStates(aNotify);
|
||||
} else if (aName == nsGkAtoms::required) {
|
||||
// This *has* to be called *before* UpdateValueMissingValidityState
|
||||
// because UpdateValueMissingValidityState depends on our required
|
||||
// state.
|
||||
UpdateRequiredState(!!aValue, aNotify);
|
||||
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateValidityElementStates(aNotify);
|
||||
} else if (aName == nsGkAtoms::autocomplete) {
|
||||
// Clear the cached @autocomplete attribute and autocompleteInfo state.
|
||||
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
|
||||
@ -1142,7 +1141,7 @@ void HTMLSelectElement::DoneAddingChildren(bool aHaveNotified) {
|
||||
UpdateValueMissingValidityState();
|
||||
|
||||
// And now make sure we update our content state too
|
||||
UpdateState(aHaveNotified);
|
||||
UpdateValidityElementStates(aHaveNotified);
|
||||
}
|
||||
|
||||
mDefaultSelectionSet = true;
|
||||
@ -1229,44 +1228,45 @@ nsresult HTMLSelectElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
||||
} else if (aVisitor.mEvent->mMessage == eBlur) {
|
||||
mCanShowInvalidUI = true;
|
||||
mCanShowValidUI = true;
|
||||
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
return nsGenericHTMLFormControlElementWithState::PostHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
ElementState HTMLSelectElement::IntrinsicState() const {
|
||||
ElementState state =
|
||||
nsGenericHTMLFormControlElementWithState::IntrinsicState();
|
||||
void HTMLSelectElement::UpdateValidityElementStates(bool aNotify) {
|
||||
AutoStateChangeNotifier notifier(*this, aNotify);
|
||||
RemoveStatesSilently(ElementState::VALIDITY_STATES);
|
||||
if (!IsCandidateForConstraintValidation()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsCandidateForConstraintValidation()) {
|
||||
if (IsValid()) {
|
||||
state |= ElementState::VALID;
|
||||
} else {
|
||||
state |= ElementState::INVALID;
|
||||
ElementState state;
|
||||
if (IsValid()) {
|
||||
state |= ElementState::VALID;
|
||||
} else {
|
||||
state |= ElementState::INVALID;
|
||||
|
||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
||||
state |= ElementState::USER_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 already been modified or the user tried to submit the
|
||||
// form owner while invalid.
|
||||
if (mCanShowValidUI && ShouldShowValidityUI() &&
|
||||
(IsValid() ||
|
||||
(state.HasState(ElementState::USER_INVALID) && !mCanShowInvalidUI))) {
|
||||
state |= ElementState::USER_VALID;
|
||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
||||
state |= ElementState::USER_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
// :-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 already been modified or the user tried to submit the
|
||||
// form owner while invalid.
|
||||
if (mCanShowValidUI && ShouldShowValidityUI() &&
|
||||
(IsValid() ||
|
||||
(state.HasState(ElementState::USER_INVALID) && !mCanShowInvalidUI))) {
|
||||
state |= ElementState::USER_VALID;
|
||||
}
|
||||
|
||||
AddStatesSilently(state);
|
||||
}
|
||||
|
||||
void HTMLSelectElement::SaveState() {
|
||||
@ -1566,7 +1566,7 @@ void HTMLSelectElement::FieldSetDisabledChanged(bool aNotify) {
|
||||
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateBarredFromConstraintValidation();
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
|
||||
void HTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify) {
|
||||
@ -1578,9 +1578,8 @@ void HTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify) {
|
||||
|
||||
bool previousSelectionChangedValue = mSelectionHasChanged;
|
||||
mSelectionHasChanged = aValue;
|
||||
|
||||
if (mSelectionHasChanged != previousSelectionChangedValue) {
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,8 +214,6 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState,
|
||||
|
||||
void FieldSetDisabledChanged(bool aNotify) override;
|
||||
|
||||
ElementState IntrinsicState() const override;
|
||||
|
||||
/**
|
||||
* To be called when stuff is added under a child of the select--but *before*
|
||||
* they are actually added.
|
||||
@ -300,6 +298,7 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState,
|
||||
ValidityStateType aType) override;
|
||||
|
||||
void UpdateValueMissingValidityState();
|
||||
void UpdateValidityElementStates(bool aNotify) final;
|
||||
/**
|
||||
* Insert aElement before the node given by aBefore
|
||||
*/
|
||||
|
@ -302,9 +302,7 @@ void HTMLTextAreaElement::SetValueChanged(bool aValueChanged) {
|
||||
}
|
||||
UpdateTooLongValidityState();
|
||||
UpdateTooShortValidityState();
|
||||
// We need to do this unconditionally because the validity ui bits depend on
|
||||
// this.
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::SetLastValueChangeWasInteractive(
|
||||
@ -317,7 +315,7 @@ void HTMLTextAreaElement::SetLastValueChangeWasInteractive(
|
||||
UpdateTooLongValidityState();
|
||||
UpdateTooShortValidityState();
|
||||
if (wasValid != IsValid()) {
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -497,8 +495,7 @@ nsresult HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
||||
mCanShowInvalidUI = true;
|
||||
mCanShowValidUI = true;
|
||||
}
|
||||
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -745,37 +742,38 @@ bool HTMLTextAreaElement::RestoreState(PresState* aState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ElementState HTMLTextAreaElement::IntrinsicState() const {
|
||||
ElementState state =
|
||||
nsGenericHTMLFormControlElementWithState::IntrinsicState();
|
||||
|
||||
if (IsCandidateForConstraintValidation()) {
|
||||
if (IsValid()) {
|
||||
state |= ElementState::VALID;
|
||||
} else {
|
||||
state |= ElementState::INVALID;
|
||||
// :-moz-ui-invalid always apply if the element suffers from a custom
|
||||
// error.
|
||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
||||
state |= ElementState::USER_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 already been modified or the user tried to submit the
|
||||
// form owner while invalid.
|
||||
if (mCanShowValidUI && ShouldShowValidityUI() &&
|
||||
(IsValid() ||
|
||||
(state.HasState(ElementState::USER_INVALID) && !mCanShowInvalidUI))) {
|
||||
state |= ElementState::USER_VALID;
|
||||
void HTMLTextAreaElement::UpdateValidityElementStates(bool aNotify) {
|
||||
AutoStateChangeNotifier notifier(*this, aNotify);
|
||||
RemoveStatesSilently(ElementState::VALIDITY_STATES);
|
||||
if (!IsCandidateForConstraintValidation()) {
|
||||
return;
|
||||
}
|
||||
ElementState state;
|
||||
if (IsValid()) {
|
||||
state |= ElementState::VALID;
|
||||
} else {
|
||||
state |= ElementState::INVALID;
|
||||
// :-moz-ui-invalid always apply if the element suffers from a custom
|
||||
// error.
|
||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
||||
state |= ElementState::USER_INVALID;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
|
||||
// :-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 already been modified or the user tried to submit the
|
||||
// form owner while invalid.
|
||||
if (mCanShowValidUI && ShouldShowValidityUI() &&
|
||||
(IsValid() ||
|
||||
(state.HasState(ElementState::USER_INVALID) && !mCanShowInvalidUI))) {
|
||||
state |= ElementState::USER_VALID;
|
||||
}
|
||||
AddStatesSilently(state);
|
||||
}
|
||||
|
||||
nsresult HTMLTextAreaElement::BindToTree(BindContext& aContext,
|
||||
@ -795,7 +793,7 @@ nsresult HTMLTextAreaElement::BindToTree(BindContext& aContext,
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
// And now make sure our state is up to date
|
||||
UpdateState(false);
|
||||
UpdateValidityElementStates(false);
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -808,7 +806,7 @@ void HTMLTextAreaElement::UnbindFromTree(bool aNullParent) {
|
||||
UpdateBarredFromConstraintValidation();
|
||||
|
||||
// And now make sure our state is up to date
|
||||
UpdateState(false);
|
||||
UpdateValidityElementStates(false);
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
@ -908,13 +906,16 @@ void HTMLTextAreaElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
|
||||
UpdateBarredFromConstraintValidation();
|
||||
}
|
||||
UpdateValidityElementStates(aNotify);
|
||||
} else if (aName == nsGkAtoms::autocomplete) {
|
||||
// Clear the cached @autocomplete attribute state.
|
||||
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
|
||||
} else if (aName == nsGkAtoms::maxlength) {
|
||||
UpdateTooLongValidityState();
|
||||
UpdateValidityElementStates(aNotify);
|
||||
} else if (aName == nsGkAtoms::minlength) {
|
||||
UpdateTooShortValidityState();
|
||||
UpdateValidityElementStates(aNotify);
|
||||
} else if (aName == nsGkAtoms::placeholder) {
|
||||
if (nsTextControlFrame* f = do_QueryFrame(GetPrimaryFrame())) {
|
||||
f->PlaceholderChanged(aOldValue, aValue);
|
||||
@ -957,8 +958,7 @@ bool HTMLTextAreaElement::IsMutable() const { return !IsDisabledOrReadOnly(); }
|
||||
|
||||
void HTMLTextAreaElement::SetCustomValidity(const nsAString& aError) {
|
||||
ConstraintValidation::SetCustomValidity(aError);
|
||||
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
bool HTMLTextAreaElement::IsTooLong() {
|
||||
@ -1147,7 +1147,7 @@ void HTMLTextAreaElement::OnValueChanged(ValueChangeKind aKind,
|
||||
}
|
||||
|
||||
if (validBefore != IsValid()) {
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1164,7 +1164,7 @@ void HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify) {
|
||||
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateBarredFromConstraintValidation();
|
||||
UpdateState(aNotify);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
JSObject* HTMLTextAreaElement::WrapNode(JSContext* aCx,
|
||||
|
@ -71,8 +71,6 @@ class HTMLTextAreaElement final : public TextControlElement,
|
||||
|
||||
void FieldSetDisabledChanged(bool aNotify) override;
|
||||
|
||||
ElementState IntrinsicState() const override;
|
||||
|
||||
void SetLastValueChangeWasInteractive(bool);
|
||||
|
||||
// TextControlElement
|
||||
@ -393,6 +391,8 @@ class HTMLTextAreaElement final : public TextControlElement,
|
||||
void GetSelectionRange(uint32_t* aSelectionStart, uint32_t* aSelectionEnd,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void UpdateValidityElementStates(bool aNotify) final;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(MappedDeclarationsBuilder&);
|
||||
};
|
||||
|
@ -1739,7 +1739,7 @@ void nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm,
|
||||
UnsetFlags(ADDED_TO_FORM);
|
||||
SetFormInternal(nullptr, false);
|
||||
AfterClearForm(aUnbindOrDelete);
|
||||
UpdateState(true);
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
nsresult nsGenericHTMLFormElement::BindToTree(BindContext& aContext,
|
||||
@ -1760,7 +1760,6 @@ nsresult nsGenericHTMLFormElement::BindToTree(BindContext& aContext,
|
||||
|
||||
// Set parent fieldset which should be used for the disabled state.
|
||||
UpdateFieldSet(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1782,11 +1781,6 @@ void nsGenericHTMLFormElement::UnbindFromTree(bool aNullParent) {
|
||||
UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetFormInternal()) {
|
||||
// Our novalidate state might have changed
|
||||
UpdateState(false);
|
||||
}
|
||||
}
|
||||
|
||||
// We have to remove the form id observer if there was one.
|
||||
@ -2100,7 +2094,8 @@ void nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
|
||||
}
|
||||
|
||||
if (form != oldForm) {
|
||||
UpdateState(true);
|
||||
// ui-valid / invalid depends on the form for some elements
|
||||
UpdateValidityElementStates(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1015,6 +1015,11 @@ class nsGenericHTMLFormElement : public nsGenericHTMLElement {
|
||||
*/
|
||||
already_AddRefed<nsILayoutHistoryState> GetLayoutHistory(bool aRead);
|
||||
|
||||
// Form changes (in particular whether our current form has been submitted
|
||||
// invalidly) affect the user-valid/user-invalid pseudo-classes. Sub-classes
|
||||
// can override this to react to it.
|
||||
virtual void UpdateValidityElementStates(bool aNotify) {}
|
||||
|
||||
protected:
|
||||
virtual ~nsGenericHTMLFormElement() = default;
|
||||
|
||||
|
@ -87,9 +87,9 @@ bool nsIConstraintValidation::ReportValidity() {
|
||||
auto* inputElement = HTMLInputElement::FromNode(element);
|
||||
if (inputElement && inputElement->State().HasState(ElementState::FOCUS)) {
|
||||
inputElement->UpdateValidityUIBits(true);
|
||||
inputElement->UpdateValidityElementStates(true);
|
||||
}
|
||||
|
||||
element->UpdateState(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -111,8 +111,7 @@ void nsIConstraintValidation::SetValidityState(ValidityStateType aState,
|
||||
if (HTMLFormElement* form = formCtrl->GetForm()) {
|
||||
form->UpdateValidity(IsValid());
|
||||
}
|
||||
HTMLFieldSetElement* fieldSet = formCtrl->GetFieldSet();
|
||||
if (fieldSet) {
|
||||
if (HTMLFieldSetElement* fieldSet = formCtrl->GetFieldSet()) {
|
||||
fieldSet->UpdateValidity(IsValid());
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ bool nsRadioSetValueMissingState::Visit(HTMLInputElement* aRadio) {
|
||||
|
||||
aRadio->SetValidityState(
|
||||
nsIConstraintValidation::VALIDITY_STATE_VALUE_MISSING, mValidity);
|
||||
aRadio->UpdateState(true);
|
||||
aRadio->UpdateValidityElementStates(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -44,6 +44,6 @@ bool nsRadioUpdateStateVisitor::Visit(HTMLInputElement* aRadio) {
|
||||
return true;
|
||||
}
|
||||
aRadio->UpdateIndeterminateState(true);
|
||||
aRadio->UpdateState(true);
|
||||
aRadio->UpdateValidityElementStates(true);
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user