зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1850293 - Make CHECKED/DEFAULT states not intrinsic. r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D186933
This commit is contained in:
Родитель
33968f7c4e
Коммит
b1ad2fb6f3
|
@ -126,6 +126,7 @@ struct ScrollOptions;
|
|||
class Attr;
|
||||
class BooleanOrScrollIntoViewOptions;
|
||||
class Document;
|
||||
class HTMLFormElement;
|
||||
class DOMIntersectionObserver;
|
||||
class DOMMatrixReadOnly;
|
||||
class Element;
|
||||
|
@ -656,11 +657,7 @@ class Element : public FragmentOrElement {
|
|||
const AttrArray& GetAttrs() const { return mAttrs; }
|
||||
|
||||
void SetDefined(bool aSet) {
|
||||
if (aSet) {
|
||||
AddStates(ElementState::DEFINED);
|
||||
} else {
|
||||
RemoveStates(ElementState::DEFINED);
|
||||
}
|
||||
SetStates(ElementState::DEFINED, aSet);
|
||||
}
|
||||
|
||||
// AccessibilityRole
|
||||
|
@ -749,6 +746,7 @@ class Element : public FragmentOrElement {
|
|||
friend class ::nsGlobalWindowInner;
|
||||
friend class ::nsGlobalWindowOuter;
|
||||
friend class ::nsFocusManager;
|
||||
friend class mozilla::dom::HTMLFormElement;
|
||||
|
||||
// Allow CusomtElementRegistry to call AddStates.
|
||||
friend class CustomElementRegistry;
|
||||
|
@ -768,19 +766,30 @@ class Element : public FragmentOrElement {
|
|||
// These will handle setting up script blockers when they notify, so no need
|
||||
// to do it in the callers unless desired. States passed here must only be
|
||||
// those in EXTERNALLY_MANAGED_STATES.
|
||||
void AddStates(ElementState aStates) {
|
||||
void AddStates(ElementState aStates, bool aNotify = true) {
|
||||
MOZ_ASSERT(!aStates.HasAtLeastOneOfStates(ElementState::INTRINSIC_STATES),
|
||||
"Should only be adding externally-managed states here");
|
||||
ElementState old = mState;
|
||||
AddStatesSilently(aStates);
|
||||
NotifyStateChange(old ^ mState);
|
||||
if (aNotify) {
|
||||
NotifyStateChange(old ^ mState);
|
||||
}
|
||||
}
|
||||
void RemoveStates(ElementState aStates) {
|
||||
void RemoveStates(ElementState aStates, bool aNotify = true) {
|
||||
MOZ_ASSERT(!aStates.HasAtLeastOneOfStates(ElementState::INTRINSIC_STATES),
|
||||
"Should only be removing externally-managed states here");
|
||||
ElementState old = mState;
|
||||
RemoveStatesSilently(aStates);
|
||||
NotifyStateChange(old ^ mState);
|
||||
if (aNotify) {
|
||||
NotifyStateChange(old ^ mState);
|
||||
}
|
||||
}
|
||||
void SetStates(ElementState aStates, bool aSet, bool aNotify = true) {
|
||||
if (aSet) {
|
||||
AddStates(aStates, aNotify);
|
||||
} else {
|
||||
RemoveStates(aStates, aNotify);
|
||||
}
|
||||
}
|
||||
void ToggleStates(ElementState aStates, bool aNotify) {
|
||||
MOZ_ASSERT(!aStates.HasAtLeastOneOfStates(ElementState::INTRINSIC_STATES),
|
||||
|
|
|
@ -181,7 +181,9 @@ bitflags! {
|
|||
Self::INCREMENT_SCRIPT_LEVEL.bits |
|
||||
Self::PLACEHOLDER_SHOWN.bits |
|
||||
Self::READONLY.bits |
|
||||
Self::READWRITE.bits;
|
||||
Self::READWRITE.bits |
|
||||
Self::CHECKED.bits |
|
||||
Self::DEFAULT.bits;
|
||||
|
||||
const INTRINSIC_STATES = !Self::EXTERNALLY_MANAGED_STATES.bits;
|
||||
}
|
||||
|
|
|
@ -1227,7 +1227,7 @@ nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
|
|||
(*firstSubmitSlot == mDefaultSubmitElement ||
|
||||
nsContentUtils::CompareTreePosition(aChild, mDefaultSubmitElement,
|
||||
this) < 0)) {
|
||||
mDefaultSubmitElement = aChild;
|
||||
SetDefaultSubmitElement(aChild);
|
||||
}
|
||||
*firstSubmitSlot = aChild;
|
||||
}
|
||||
|
@ -1271,6 +1271,19 @@ nsresult HTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild,
|
|||
return mControls->AddElementToTable(aChild, aName);
|
||||
}
|
||||
|
||||
void HTMLFormElement::SetDefaultSubmitElement(
|
||||
nsGenericHTMLFormElement* aElement) {
|
||||
if (mDefaultSubmitElement) {
|
||||
// It just so happens that a radio button or an <option> can't be our
|
||||
// default submit element, so we can just blindly remove the bit.
|
||||
mDefaultSubmitElement->RemoveStates(ElementState::DEFAULT);
|
||||
}
|
||||
mDefaultSubmitElement = aElement;
|
||||
if (mDefaultSubmitElement) {
|
||||
mDefaultSubmitElement->AddStates(ElementState::DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult HTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
|
||||
bool aUpdateValidity) {
|
||||
RemoveElementFromPastNamesMap(aChild);
|
||||
|
@ -1320,7 +1333,7 @@ nsresult HTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
|
|||
if (aChild == mDefaultSubmitElement) {
|
||||
// Need to reset mDefaultSubmitElement. Do this asynchronously so
|
||||
// that we're not doing it while the DOM is in flux.
|
||||
mDefaultSubmitElement = nullptr;
|
||||
SetDefaultSubmitElement(nullptr);
|
||||
nsContentUtils::AddScriptRunner(new RemoveElementRunnable(this));
|
||||
|
||||
// Note that we don't need to notify on the old default submit (which is
|
||||
|
@ -1348,29 +1361,26 @@ void HTMLFormElement::HandleDefaultSubmitRemoval() {
|
|||
return;
|
||||
}
|
||||
|
||||
nsGenericHTMLFormElement* newDefaultSubmit;
|
||||
if (!mFirstSubmitNotInElements) {
|
||||
mDefaultSubmitElement = mFirstSubmitInElements;
|
||||
newDefaultSubmit = mFirstSubmitInElements;
|
||||
} else if (!mFirstSubmitInElements) {
|
||||
mDefaultSubmitElement = mFirstSubmitNotInElements;
|
||||
newDefaultSubmit = mFirstSubmitNotInElements;
|
||||
} else {
|
||||
NS_ASSERTION(mFirstSubmitInElements != mFirstSubmitNotInElements,
|
||||
"How did that happen?");
|
||||
// Have both; use the earlier one
|
||||
mDefaultSubmitElement =
|
||||
newDefaultSubmit =
|
||||
nsContentUtils::CompareTreePosition(mFirstSubmitInElements,
|
||||
mFirstSubmitNotInElements, this) < 0
|
||||
? mFirstSubmitInElements
|
||||
: mFirstSubmitNotInElements;
|
||||
}
|
||||
SetDefaultSubmitElement(newDefaultSubmit);
|
||||
|
||||
MOZ_ASSERT(mDefaultSubmitElement == mFirstSubmitInElements ||
|
||||
mDefaultSubmitElement == mFirstSubmitNotInElements,
|
||||
"What happened here?");
|
||||
|
||||
// Notify about change if needed.
|
||||
if (mDefaultSubmitElement) {
|
||||
mDefaultSubmitElement->UpdateState(true);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult HTMLFormElement::RemoveElementFromTableInternal(
|
||||
|
@ -1679,40 +1689,6 @@ nsGenericHTMLFormElement* HTMLFormElement::GetDefaultSubmitElement() const {
|
|||
return mDefaultSubmitElement;
|
||||
}
|
||||
|
||||
bool HTMLFormElement::IsDefaultSubmitElement(
|
||||
const nsGenericHTMLFormElement* aElement) const {
|
||||
MOZ_ASSERT(aElement, "Unexpected call");
|
||||
|
||||
if (aElement == mDefaultSubmitElement) {
|
||||
// Yes, it is
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mDefaultSubmitElement || (aElement != mFirstSubmitInElements &&
|
||||
aElement != mFirstSubmitNotInElements)) {
|
||||
// It isn't
|
||||
return false;
|
||||
}
|
||||
|
||||
// mDefaultSubmitElement is null, but we have a non-null submit around
|
||||
// (aElement, in fact). figure out whether it's in fact the default submit
|
||||
// and just hasn't been set that way yet. Note that we can't just call
|
||||
// HandleDefaultSubmitRemoval because we might need to notify to handle that
|
||||
// correctly and we don't know whether that's safe right here.
|
||||
if (!mFirstSubmitInElements || !mFirstSubmitNotInElements) {
|
||||
// We only have one first submit; aElement has to be it
|
||||
return true;
|
||||
}
|
||||
|
||||
// We have both kinds of submits. Check which comes first.
|
||||
nsGenericHTMLFormElement* defaultSubmit =
|
||||
nsContentUtils::CompareTreePosition(mFirstSubmitInElements,
|
||||
mFirstSubmitNotInElements, this) < 0
|
||||
? mFirstSubmitInElements
|
||||
: mFirstSubmitNotInElements;
|
||||
return aElement == defaultSubmit;
|
||||
}
|
||||
|
||||
bool HTMLFormElement::ImplicitSubmissionIsDisabled() const {
|
||||
// Input text controls are always in the elements list.
|
||||
uint32_t numDisablingControlsFound = 0;
|
||||
|
|
|
@ -57,6 +57,9 @@ class HTMLFormElement final : public nsGenericHTMLElement,
|
|||
|
||||
int32_t IndexOfContent(nsIContent* aContent);
|
||||
nsGenericHTMLFormElement* GetDefaultSubmitElement() const;
|
||||
bool IsDefaultSubmitElement(nsGenericHTMLFormElement* aElement) const {
|
||||
return aElement == mDefaultSubmitElement;
|
||||
}
|
||||
|
||||
// nsIRadioGroupContainer
|
||||
void SetCurrentRadioButton(const nsAString& aName,
|
||||
|
@ -206,15 +209,6 @@ class HTMLFormElement final : public nsGenericHTMLElement,
|
|||
*/
|
||||
bool IsLastActiveElement(const nsGenericHTMLFormElement* aElement) const;
|
||||
|
||||
/**
|
||||
* Check whether a given nsGenericHTMLFormElement is the default submit
|
||||
* element. This is different from just comparing to
|
||||
* GetDefaultSubmitElement() in certain situations inside an update
|
||||
* when GetDefaultSubmitElement() might not be up to date. aElement
|
||||
* is expected to not be null.
|
||||
*/
|
||||
bool IsDefaultSubmitElement(const nsGenericHTMLFormElement* aElement) const;
|
||||
|
||||
/**
|
||||
* Flag the form to know that a button or image triggered scripted form
|
||||
* submission. In that case the form will defer the submission until the
|
||||
|
@ -618,6 +612,8 @@ class HTMLFormElement final : public nsGenericHTMLElement,
|
|||
private:
|
||||
bool IsSubmitting() const;
|
||||
|
||||
void SetDefaultSubmitElement(nsGenericHTMLFormElement*);
|
||||
|
||||
NotNull<const Encoding*> GetSubmitEncoding();
|
||||
|
||||
/**
|
||||
|
|
|
@ -1246,16 +1246,20 @@ void HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
|||
UpdateStepMismatchValidityState();
|
||||
}
|
||||
|
||||
//
|
||||
// Checked must be set no matter what type of control it is, since
|
||||
// mChecked must reflect the new value
|
||||
if (aName == nsGkAtoms::checked && !mCheckedChanged) {
|
||||
// Delay setting checked if we are creating this element (wait
|
||||
// until everything is set)
|
||||
if (!mDoneCreating) {
|
||||
mShouldInitChecked = true;
|
||||
} else {
|
||||
DoSetChecked(DefaultChecked(), true, false);
|
||||
if (aName == nsGkAtoms::checked) {
|
||||
if (IsRadioOrCheckbox()) {
|
||||
SetStates(ElementState::DEFAULT, !!aValue, aNotify);
|
||||
}
|
||||
if (!mCheckedChanged) {
|
||||
// Delay setting checked if we are creating this element (wait
|
||||
// until everything is set)
|
||||
if (!mDoneCreating) {
|
||||
mShouldInitChecked = true;
|
||||
} else {
|
||||
DoSetChecked(!!aValue, aNotify, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2231,13 +2235,7 @@ void HTMLInputElement::SetFocusState(bool aIsFocused) {
|
|||
if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
|
||||
return;
|
||||
}
|
||||
|
||||
ElementState focusStates = ElementState::FOCUS | ElementState::FOCUSRING;
|
||||
if (aIsFocused) {
|
||||
AddStates(focusStates);
|
||||
} else {
|
||||
RemoveStates(focusStates);
|
||||
}
|
||||
SetStates(ElementState::FOCUS | ElementState::FOCUSRING, aIsFocused);
|
||||
}
|
||||
|
||||
void HTMLInputElement::UpdateValidityState() {
|
||||
|
@ -2952,25 +2950,26 @@ void HTMLInputElement::MaybeSubmitForm(nsPresContext* aPresContext) {
|
|||
}
|
||||
}
|
||||
|
||||
void HTMLInputElement::UpdateCheckedState(bool aNotify) {
|
||||
SetStates(ElementState::CHECKED, IsRadioOrCheckbox() && mChecked, aNotify);
|
||||
}
|
||||
|
||||
void HTMLInputElement::SetCheckedInternal(bool aChecked, bool aNotify) {
|
||||
// Set the value
|
||||
mChecked = aChecked;
|
||||
|
||||
// Notify the frame
|
||||
if (mType == FormControlType::InputCheckbox ||
|
||||
mType == FormControlType::InputRadio) {
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
if (frame) {
|
||||
if (IsRadioOrCheckbox()) {
|
||||
if (nsIFrame* frame = GetPrimaryFrame()) {
|
||||
frame->InvalidateFrameSubtree();
|
||||
}
|
||||
SetStates(ElementState::CHECKED, aChecked, aNotify);
|
||||
}
|
||||
|
||||
// No need to update element state, since we're about to call
|
||||
// UpdateState anyway.
|
||||
UpdateAllValidityStatesButNotElementState();
|
||||
|
||||
// Notify the document that the CSS :checked pseudoclass for this element
|
||||
// has changed state.
|
||||
// :indeterminate and validity state still require UpdateState to be called.
|
||||
UpdateState(aNotify);
|
||||
|
||||
// Notify all radios in the group that value has changed, this is to let
|
||||
|
@ -3350,8 +3349,7 @@ void HTMLInputElement::CancelRangeThumbDrag(bool aIsForUserEvent) {
|
|||
// is small, so we should be fine here.)
|
||||
SetValueInternal(val, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::SetValueChanged});
|
||||
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||
if (frame) {
|
||||
if (nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame())) {
|
||||
frame->UpdateForValueChange();
|
||||
}
|
||||
DebugOnly<nsresult> rvIgnored = nsContentUtils::DispatchInputEvent(this);
|
||||
|
@ -3375,8 +3373,7 @@ void HTMLInputElement::SetValueOfRangeForUserEvent(
|
|||
// is small, so we should be fine here.)
|
||||
SetValueInternal(val, {ValueSetterOption::BySetUserInputAPI,
|
||||
ValueSetterOption::SetValueChanged});
|
||||
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||
if (frame) {
|
||||
if (nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame())) {
|
||||
frame->UpdateForValueChange();
|
||||
}
|
||||
|
||||
|
@ -4396,6 +4393,11 @@ void HTMLInputElement::HandleTypeChange(FormControlType aNewType,
|
|||
UpdatePlaceholderShownState();
|
||||
// Whether readonly applies might have changed.
|
||||
UpdateReadOnlyState(aNotify);
|
||||
UpdateCheckedState(aNotify);
|
||||
const bool isDefault = IsRadioOrCheckbox()
|
||||
? DefaultChecked()
|
||||
: (mForm && mForm->IsDefaultSubmitElement(this));
|
||||
SetStates(ElementState::DEFAULT, isDefault, aNotify);
|
||||
|
||||
// https://html.spec.whatwg.org/#input-type-change
|
||||
switch (GetValueMode()) {
|
||||
|
@ -4473,12 +4475,10 @@ void HTMLInputElement::HandleTypeChange(FormControlType aNewType,
|
|||
// Update or clear our required states since we may have changed from a
|
||||
// required input type to a non-required input type or viceversa.
|
||||
if (DoesRequiredApply()) {
|
||||
bool isRequired = HasAttr(nsGkAtoms::required);
|
||||
const bool isRequired = HasAttr(nsGkAtoms::required);
|
||||
UpdateRequiredState(isRequired, aNotify);
|
||||
} else if (aNotify) {
|
||||
RemoveStates(ElementState::REQUIRED_STATES);
|
||||
} else {
|
||||
RemoveStatesSilently(ElementState::REQUIRED_STATES);
|
||||
RemoveStates(ElementState::REQUIRED_STATES, aNotify);
|
||||
}
|
||||
|
||||
UpdateHasRange();
|
||||
|
@ -6037,36 +6037,19 @@ void HTMLInputElement::DestroyContent() {
|
|||
}
|
||||
|
||||
ElementState HTMLInputElement::IntrinsicState() const {
|
||||
// If you add states here, and they're type-dependent, you need to add them
|
||||
// to the type case in AfterSetAttr.
|
||||
|
||||
// If you add states here, and they're type-dependent, you need to add them to
|
||||
// HandleTypeChange.
|
||||
ElementState state =
|
||||
nsGenericHTMLFormControlElementWithState::IntrinsicState();
|
||||
if (mType == FormControlType::InputCheckbox ||
|
||||
mType == FormControlType::InputRadio) {
|
||||
// Check current checked state (:checked)
|
||||
if (mChecked) {
|
||||
state |= ElementState::CHECKED;
|
||||
}
|
||||
|
||||
// Check current indeterminate state (:indeterminate)
|
||||
if (mType == FormControlType::InputCheckbox && mIndeterminate) {
|
||||
// Check current indeterminate state (:indeterminate)
|
||||
if (mType == FormControlType::InputCheckbox && mIndeterminate) {
|
||||
state |= ElementState::INDETERMINATE;
|
||||
} else if (mType == FormControlType::InputRadio) {
|
||||
HTMLInputElement* selected = GetSelectedRadioButton();
|
||||
const bool indeterminate = !selected && !mChecked;
|
||||
if (indeterminate) {
|
||||
state |= ElementState::INDETERMINATE;
|
||||
}
|
||||
|
||||
if (mType == FormControlType::InputRadio) {
|
||||
HTMLInputElement* selected = GetSelectedRadioButton();
|
||||
bool indeterminate = !selected && !mChecked;
|
||||
|
||||
if (indeterminate) {
|
||||
state |= ElementState::INDETERMINATE;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether we are the default checked element (:default)
|
||||
if (DefaultChecked()) {
|
||||
state |= ElementState::DEFAULT;
|
||||
}
|
||||
} else if (mType == FormControlType::InputImage) {
|
||||
state |= nsImageLoadingContent::ImageState();
|
||||
}
|
||||
|
@ -6267,7 +6250,6 @@ void HTMLInputElement::WillRemoveFromRadioGroup() {
|
|||
// longer a selected radio button
|
||||
if (mChecked) {
|
||||
container->SetCurrentRadioButton(name, nullptr);
|
||||
|
||||
nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this);
|
||||
VisitGroup(visitor);
|
||||
}
|
||||
|
@ -6815,13 +6797,9 @@ void HTMLInputElement::InitializeKeyboardEventListeners() {
|
|||
}
|
||||
|
||||
void HTMLInputElement::UpdatePlaceholderShownState() {
|
||||
const bool shown =
|
||||
IsValueEmpty() && PlaceholderApplies() && HasAttr(nsGkAtoms::placeholder);
|
||||
if (shown) {
|
||||
AddStates(ElementState::PLACEHOLDER_SHOWN);
|
||||
} else {
|
||||
RemoveStates(ElementState::PLACEHOLDER_SHOWN);
|
||||
}
|
||||
SetStates(ElementState::PLACEHOLDER_SHOWN,
|
||||
IsValueEmpty() && PlaceholderApplies() &&
|
||||
HasAttr(nsGkAtoms::placeholder));
|
||||
}
|
||||
|
||||
void HTMLInputElement::OnValueChanged(ValueChangeKind aKind,
|
||||
|
@ -6833,11 +6811,7 @@ void HTMLInputElement::OnValueChanged(ValueChangeKind aKind,
|
|||
}
|
||||
|
||||
if (aNewValueEmpty != IsValueEmpty()) {
|
||||
if (aNewValueEmpty) {
|
||||
AddStates(ElementState::VALUE_EMPTY);
|
||||
} else {
|
||||
RemoveStates(ElementState::VALUE_EMPTY);
|
||||
}
|
||||
SetStates(ElementState::VALUE_EMPTY, aNewValueEmpty);
|
||||
UpdatePlaceholderShownState();
|
||||
}
|
||||
|
||||
|
@ -6876,11 +6850,7 @@ void HTMLInputElement::SetRevealPassword(bool aValue) {
|
|||
if (NS_WARN_IF(!defaultAction)) {
|
||||
return;
|
||||
}
|
||||
if (aValue) {
|
||||
AddStates(ElementState::REVEALED);
|
||||
} else {
|
||||
RemoveStates(ElementState::REVEALED);
|
||||
}
|
||||
SetStates(ElementState::REVEALED, aValue);
|
||||
}
|
||||
|
||||
bool HTMLInputElement::RevealPassword() const {
|
||||
|
|
|
@ -325,6 +325,7 @@ class HTMLInputElement final : public TextControlElement,
|
|||
void UpdateStepMismatchValidityState();
|
||||
void UpdateBadInputValidityState();
|
||||
void UpdatePlaceholderShownState();
|
||||
void UpdateCheckedState(bool aNotify);
|
||||
// Update all our validity states and then update our element state
|
||||
// as needed. aNotify controls whether the element state update
|
||||
// needs to notify.
|
||||
|
@ -464,6 +465,11 @@ class HTMLInputElement final : public TextControlElement,
|
|||
bool Checked() const { return mChecked; }
|
||||
void SetChecked(bool aChecked);
|
||||
|
||||
bool IsRadioOrCheckbox() const {
|
||||
return mType == FormControlType::InputCheckbox ||
|
||||
mType == FormControlType::InputRadio;
|
||||
}
|
||||
|
||||
bool Disabled() const { return GetBoolAttr(nsGkAtoms::disabled); }
|
||||
|
||||
void SetDisabled(bool aValue, ErrorResult& aRv) {
|
||||
|
|
|
@ -33,10 +33,7 @@ namespace mozilla::dom {
|
|||
|
||||
HTMLOptionElement::HTMLOptionElement(
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
|
||||
: nsGenericHTMLElement(std::move(aNodeInfo)),
|
||||
mSelectedChanged(false),
|
||||
mIsSelected(false),
|
||||
mIsInSetDefaultSelected(false) {
|
||||
: nsGenericHTMLElement(std::move(aNodeInfo)) {
|
||||
// We start off enabled
|
||||
AddStatesSilently(ElementState::ENABLED);
|
||||
}
|
||||
|
@ -52,13 +49,7 @@ mozilla::dom::HTMLFormElement* HTMLOptionElement::GetForm() {
|
|||
|
||||
void HTMLOptionElement::SetSelectedInternal(bool aValue, bool aNotify) {
|
||||
mSelectedChanged = true;
|
||||
mIsSelected = aValue;
|
||||
|
||||
// When mIsInSetDefaultSelected is true, the state change will be handled by
|
||||
// SetAttr/UnsetAttr.
|
||||
if (!mIsInSetDefaultSelected) {
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
SetStates(ElementState::CHECKED, aValue, aNotify);
|
||||
}
|
||||
|
||||
void HTMLOptionElement::OptGroupDisabledChanged(bool aNotify) {
|
||||
|
@ -156,9 +147,9 @@ void HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
|||
// it.
|
||||
HTMLSelectElement* selectInt = GetSelect();
|
||||
if (!selectInt) {
|
||||
// If option is a child of select, SetOptionsSelectedByIndex will set
|
||||
// mIsSelected if needed.
|
||||
mIsSelected = aValue;
|
||||
// If option is a child of select, SetOptionsSelectedByIndex will set the
|
||||
// selected state if needed.
|
||||
SetStates(ElementState::CHECKED, !!aValue, aNotify);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -187,8 +178,9 @@ void HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
|||
// Now reset our members; when we finish the attr set we'll end up with the
|
||||
// rigt selected state.
|
||||
mIsInSetDefaultSelected = inSetDefaultSelected;
|
||||
// mIsSelected might have been changed by SetOptionsSelectedByIndex. Possibly
|
||||
// more than once; make sure our mSelectedChanged state is set back correctly.
|
||||
// the selected state might have been changed by SetOptionsSelectedByIndex,
|
||||
// possibly more than once; make sure our mSelectedChanged state is set back
|
||||
// correctly.
|
||||
mSelectedChanged = false;
|
||||
}
|
||||
|
||||
|
@ -203,14 +195,16 @@ void HTMLOptionElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
|||
}
|
||||
|
||||
if (aName == nsGkAtoms::value && Selected()) {
|
||||
// Since this option is selected, changing value
|
||||
// may have changed missing validity state of the
|
||||
// Select element
|
||||
HTMLSelectElement* select = GetSelect();
|
||||
if (select) {
|
||||
// Since this option is selected, changing value may have changed missing
|
||||
// validity state of the select element
|
||||
if (HTMLSelectElement* select = GetSelect()) {
|
||||
select->UpdateValueMissingValidityState();
|
||||
}
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::selected) {
|
||||
SetStates(ElementState::DEFAULT, !!aValue, aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(
|
||||
|
@ -260,18 +254,6 @@ void HTMLOptionElement::UnbindFromTree(bool aNullParent) {
|
|||
UpdateDisabledState(false);
|
||||
}
|
||||
|
||||
ElementState HTMLOptionElement::IntrinsicState() const {
|
||||
ElementState state = nsGenericHTMLElement::IntrinsicState();
|
||||
if (Selected()) {
|
||||
state |= ElementState::CHECKED;
|
||||
}
|
||||
if (DefaultSelected()) {
|
||||
state |= ElementState::DEFAULT;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// Get the select content element that contains this option
|
||||
HTMLSelectElement* HTMLOptionElement::GetSelect() {
|
||||
nsIContent* parent = GetParent();
|
||||
|
|
|
@ -32,7 +32,7 @@ class HTMLOptionElement final : public nsGenericHTMLElement {
|
|||
|
||||
using mozilla::dom::Element::GetText;
|
||||
|
||||
bool Selected() const { return mIsSelected; }
|
||||
bool Selected() const { return State().HasState(ElementState::CHECKED); }
|
||||
void SetSelected(bool aValue);
|
||||
|
||||
void SetSelectedChanged(bool aValue) { mSelectedChanged = aValue; }
|
||||
|
@ -64,9 +64,6 @@ class HTMLOptionElement final : public nsGenericHTMLElement {
|
|||
nsresult BindToTree(BindContext&, nsINode& aParent) override;
|
||||
void UnbindFromTree(bool aNullParent = true) override;
|
||||
|
||||
// nsIContent
|
||||
ElementState IntrinsicState() const override;
|
||||
|
||||
nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
||||
|
||||
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
|
||||
|
@ -125,12 +122,11 @@ class HTMLOptionElement final : public nsGenericHTMLElement {
|
|||
*/
|
||||
HTMLSelectElement* GetSelect();
|
||||
|
||||
bool mSelectedChanged;
|
||||
bool mIsSelected;
|
||||
bool mSelectedChanged = false;
|
||||
|
||||
// True only while we're under the SetOptionsSelectedByIndex call when our
|
||||
// "selected" attribute is changing and mSelectedChanged is false.
|
||||
bool mIsInSetDefaultSelected;
|
||||
bool mIsInSetDefaultSelected = false;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
|
|
@ -1120,12 +1120,8 @@ void HTMLTextAreaElement::InitializeKeyboardEventListeners() {
|
|||
}
|
||||
|
||||
void HTMLTextAreaElement::UpdatePlaceholderShownState() {
|
||||
const bool shown = IsValueEmpty() && HasAttr(nsGkAtoms::placeholder);
|
||||
if (shown) {
|
||||
AddStates(ElementState::PLACEHOLDER_SHOWN);
|
||||
} else {
|
||||
RemoveStates(ElementState::PLACEHOLDER_SHOWN);
|
||||
}
|
||||
SetStates(ElementState::PLACEHOLDER_SHOWN,
|
||||
IsValueEmpty() && HasAttr(nsGkAtoms::placeholder));
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::OnValueChanged(ValueChangeKind aKind,
|
||||
|
@ -1136,11 +1132,7 @@ void HTMLTextAreaElement::OnValueChanged(ValueChangeKind aKind,
|
|||
}
|
||||
|
||||
if (aNewValueEmpty != IsValueEmpty()) {
|
||||
if (aNewValueEmpty) {
|
||||
AddStates(ElementState::VALUE_EMPTY);
|
||||
} else {
|
||||
RemoveStates(ElementState::VALUE_EMPTY);
|
||||
}
|
||||
SetStates(ElementState::VALUE_EMPTY, aNewValueEmpty);
|
||||
UpdatePlaceholderShownState();
|
||||
}
|
||||
|
||||
|
|
|
@ -2035,10 +2035,8 @@ void nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
|
|||
MOZ_ASSERT(!aBindToTree || !aFormIdElement,
|
||||
"aFormIdElement shouldn't be set if aBindToTree is true!");
|
||||
|
||||
bool needStateUpdate = false;
|
||||
HTMLFormElement* form = GetFormInternal();
|
||||
if (!aBindToTree) {
|
||||
needStateUpdate = form && form->IsDefaultSubmitElement(this);
|
||||
ClearForm(true, false);
|
||||
form = nullptr;
|
||||
}
|
||||
|
@ -2101,7 +2099,7 @@ void nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
|
|||
}
|
||||
}
|
||||
|
||||
if (form != oldForm || needStateUpdate) {
|
||||
if (form != oldForm) {
|
||||
UpdateState(true);
|
||||
}
|
||||
}
|
||||
|
@ -2625,22 +2623,6 @@ void nsGenericHTMLFormControlElement::ClearForm(bool aRemoveFromForm,
|
|||
nsGenericHTMLFormElement::ClearForm(aRemoveFromForm, aUnbindOrDelete);
|
||||
}
|
||||
|
||||
ElementState nsGenericHTMLFormControlElement::IntrinsicState() const {
|
||||
// If you add attribute-dependent states here, you need to add them to
|
||||
// AfterSetAttr too. And add them to AfterSetAttr for all subclasses that
|
||||
// implement IntrinsicState() and are affected by that attribute.
|
||||
ElementState state = nsGenericHTMLFormElement::IntrinsicState();
|
||||
|
||||
if (mForm && mForm->IsDefaultSubmitElement(this)) {
|
||||
NS_ASSERTION(IsSubmitControl(),
|
||||
"Default submit element that isn't a submit control.");
|
||||
// We are the default submit element (:default)
|
||||
state |= ElementState::DEFAULT;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool nsGenericHTMLFormControlElement::IsLabelable() const {
|
||||
auto type = ControlType();
|
||||
return (IsInputElement(type) && type != FormControlType::InputHidden) ||
|
||||
|
|
|
@ -1156,7 +1156,6 @@ class nsGenericHTMLFormControlElement : public nsGenericHTMLFormElement,
|
|||
virtual ~nsGenericHTMLFormControlElement();
|
||||
|
||||
// Element
|
||||
mozilla::dom::ElementState IntrinsicState() const override;
|
||||
bool IsLabelable() const override;
|
||||
|
||||
// nsGenericHTMLFormElement
|
||||
|
|
|
@ -43,7 +43,6 @@ bool nsRadioUpdateStateVisitor::Visit(HTMLInputElement* aRadio) {
|
|||
if (aRadio == mExcludeElement) {
|
||||
return true;
|
||||
}
|
||||
|
||||
aRadio->UpdateState(true);
|
||||
return true;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче