Bug 1850295 - Update :user-{valid,invalid} to follow the spec. r=smaug

(Modulo open spec issues linked in comments)

Differential Revision: https://phabricator.services.mozilla.com/D196986
This commit is contained in:
Emilio Cobos Álvarez
2024-01-16 11:09:01 +00:00
parent 97909653e7
commit b9aedffc24
69 changed files with 203 additions and 1109 deletions

View File

@@ -48,15 +48,8 @@ HTMLTextAreaElement::HTMLTextAreaElement(
FromParser aFromParser)
: TextControlElement(std::move(aNodeInfo), aFromParser,
FormControlType::Textarea),
mValueChanged(false),
mLastValueChangeWasInteractive(false),
mHandlingSelect(false),
mDoneAddingChildren(!aFromParser),
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
mDisabledChanged(false),
mCanShowInvalidUI(true),
mCanShowValidUI(true),
mIsPreviewEnabled(false),
mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
mState(TextControlState::Construct(this)) {
AddMutationObserver(this);
@@ -465,6 +458,13 @@ void HTMLTextAreaElement::FireChangeEventIfNeeded() {
nsString value;
GetValueInternal(value, true);
// NOTE(emilio): This is not quite on the spec, but matches <input>, see
// https://github.com/whatwg/html/issues/10011 and
// https://github.com/whatwg/html/issues/10013
if (mValueChanged) {
SetUserInteracted(true);
}
if (mFocusedValue.Equals(value)) {
return;
}
@@ -480,24 +480,6 @@ nsresult HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
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;
}
UpdateValidityElementStates(true);
}
return NS_OK;
}
@@ -654,6 +636,7 @@ nsresult HTMLTextAreaElement::Reset() {
nsAutoString resetVal;
GetDefaultValue(resetVal, IgnoreErrors());
SetValueChanged(false);
SetUserInteracted(false);
nsresult rv = SetValueInternal(resetVal, ValueSetterOption::ByInternalAPI);
NS_ENSURE_SUCCESS(rv, rv);
@@ -751,28 +734,15 @@ void HTMLTextAreaElement::UpdateValidityElementStates(bool aNotify) {
ElementState state;
if (IsValid()) {
state |= ElementState::VALID;
if (mUserInteracted) {
state |= ElementState::USER_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())) {
if (mUserInteracted) {
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;
}
AddStatesSilently(state);
}
@@ -1156,6 +1126,14 @@ bool HTMLTextAreaElement::HasCachedSelection() {
return mState->IsSelectionCached();
}
void HTMLTextAreaElement::SetUserInteracted(bool aInteracted) {
if (mUserInteracted == aInteracted) {
return;
}
mUserInteracted = aInteracted;
UpdateValidityElementStates(true);
}
void HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify) {
// This *has* to be called before UpdateBarredFromConstraintValidation and
// UpdateValueMissingValidityState because these two functions depend on our