From 71838e2f11b35d415f0ffc0db2f709a906748b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Tue, 16 Jan 2024 11:09:01 +0000 Subject: [PATCH] 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 --- dom/html/HTMLButtonElement.h | 2 +- dom/html/HTMLElement.h | 2 +- dom/html/HTMLFormElement.cpp | 68 ++++--------- dom/html/HTMLFormElement.h | 11 +-- dom/html/HTMLInputElement.cpp | 92 ++++++++---------- dom/html/HTMLInputElement.h | 50 +--------- dom/html/HTMLSelectElement.cpp | 95 ++++++++----------- dom/html/HTMLSelectElement.h | 48 ++-------- dom/html/HTMLTextAreaElement.cpp | 62 ++++-------- dom/html/HTMLTextAreaElement.h | 40 ++------ dom/html/nsGenericHTMLElement.cpp | 6 -- dom/html/nsGenericHTMLElement.h | 7 +- dom/html/nsIConstraintValidation.cpp | 7 -- dom/html/test/test_bug605124-1.html | 17 ++-- dom/html/test/test_bug605125-2.html | 25 ++--- dom/html/test/test_bug610687.html | 68 ++++++------- dom/webidl/HTMLSelectElement.webidl | 7 +- layout/forms/HTMLSelectEventListener.cpp | 10 +- ...put-checkbox-required-invalid-changed.html | 16 ---- .../input/input-customerror.html | 18 ---- .../input/input-dyn-not-disabled.html | 19 ---- .../input/input-dyn-not-readonly-changed.html | 11 --- .../input/input-email-invalid-changed.html | 11 --- .../input-file-required-invalid-changed.html | 11 --- .../input/input-pattern-invalid-changed.html | 12 --- .../input/input-radio-customerror.html | 18 ---- .../input-radio-nogroup-required-valid.html | 13 --- .../input-radio-required-invalid-changed.html | 16 ---- .../input/input-radio-required.html | 18 ---- .../input/input-required-invalid-changed.html | 11 --- .../input/input-type-invalid.html | 20 ---- .../input/input-url-invalid-changed.html | 12 --- .../css-ui-invalid/input/reftest.list | 14 --- .../css-ui-invalid/select/reftest.list | 5 - .../select/select-dyn-not-disabled.html | 19 ---- .../select/select-fieldset-legend-ref.html | 10 -- .../select/select-fieldset-legend.html | 22 ----- .../css-ui-invalid/select/select-invalid.html | 10 -- .../select-required-invalid-changed-1.html | 13 --- .../select-required-invalid-changed-2.html | 13 --- .../css-ui-invalid/textarea/reftest.list | 4 - .../textarea/textarea-customerror.html | 18 ---- .../textarea/textarea-dyn-not-disabled.html | 20 ---- .../textarea-dyn-not-readonly-changed.html | 19 ---- .../textarea-required-invalid-changed.html | 19 ---- .../input/input-checkbox-valid-changed.html | 15 --- .../input/input-dyn-not-disabled-changed.html | 11 --- .../input/input-dyn-not-readonly-changed.html | 11 --- .../input/input-email-valid-changed.html | 11 --- .../input/input-file-valid-changed.html | 10 -- .../input/input-pattern-valid-changed.html | 11 --- .../input/input-radio-customerror.html | 16 ---- .../input/input-radio-dyn-valid-1.html | 15 --- .../input/input-radio-dyn-valid-2.html | 16 ---- .../input-radio-nogroup-required-invalid.html | 13 --- .../input/input-required-valid-changed.html | 11 --- .../input/input-url-valid-changed.html | 11 --- .../reftests/css-ui-valid/input/reftest.list | 12 --- .../reftests/css-ui-valid/select/reftest.list | 3 - ...elect-required-multiple-valid-changed.html | 24 ----- .../select-required-valid-changed-1.html | 12 --- .../select-required-valid-changed-2.html | 12 --- .../css-ui-valid/textarea/reftest.list | 3 - .../textarea-dyn-not-disabled-changed.html | 19 ---- .../textarea-dyn-not-readonly-changed.html | 19 ---- .../textarea-required-valid-changed.html | 11 --- .../meta/css/selectors/user-invalid.html.ini | 13 --- .../meta/css/selectors/user-valid.html.ini | 8 -- toolkit/actors/SelectChild.sys.mjs | 16 +--- 69 files changed, 203 insertions(+), 1109 deletions(-) delete mode 100644 layout/reftests/css-ui-invalid/input/input-checkbox-required-invalid-changed.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-customerror.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-dyn-not-disabled.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-dyn-not-readonly-changed.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-email-invalid-changed.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-file-required-invalid-changed.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-pattern-invalid-changed.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-radio-customerror.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-radio-nogroup-required-valid.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-radio-required-invalid-changed.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-radio-required.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-required-invalid-changed.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-type-invalid.html delete mode 100644 layout/reftests/css-ui-invalid/input/input-url-invalid-changed.html delete mode 100644 layout/reftests/css-ui-invalid/select/select-dyn-not-disabled.html delete mode 100644 layout/reftests/css-ui-invalid/select/select-fieldset-legend-ref.html delete mode 100644 layout/reftests/css-ui-invalid/select/select-fieldset-legend.html delete mode 100644 layout/reftests/css-ui-invalid/select/select-invalid.html delete mode 100644 layout/reftests/css-ui-invalid/select/select-required-invalid-changed-1.html delete mode 100644 layout/reftests/css-ui-invalid/select/select-required-invalid-changed-2.html delete mode 100644 layout/reftests/css-ui-invalid/textarea/textarea-customerror.html delete mode 100644 layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-disabled.html delete mode 100644 layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-changed.html delete mode 100644 layout/reftests/css-ui-invalid/textarea/textarea-required-invalid-changed.html delete mode 100644 layout/reftests/css-ui-valid/input/input-checkbox-valid-changed.html delete mode 100644 layout/reftests/css-ui-valid/input/input-dyn-not-disabled-changed.html delete mode 100644 layout/reftests/css-ui-valid/input/input-dyn-not-readonly-changed.html delete mode 100644 layout/reftests/css-ui-valid/input/input-email-valid-changed.html delete mode 100644 layout/reftests/css-ui-valid/input/input-file-valid-changed.html delete mode 100644 layout/reftests/css-ui-valid/input/input-pattern-valid-changed.html delete mode 100644 layout/reftests/css-ui-valid/input/input-radio-customerror.html delete mode 100644 layout/reftests/css-ui-valid/input/input-radio-dyn-valid-1.html delete mode 100644 layout/reftests/css-ui-valid/input/input-radio-dyn-valid-2.html delete mode 100644 layout/reftests/css-ui-valid/input/input-radio-nogroup-required-invalid.html delete mode 100644 layout/reftests/css-ui-valid/input/input-required-valid-changed.html delete mode 100644 layout/reftests/css-ui-valid/input/input-url-valid-changed.html delete mode 100644 layout/reftests/css-ui-valid/select/select-required-multiple-valid-changed.html delete mode 100644 layout/reftests/css-ui-valid/select/select-required-valid-changed-1.html delete mode 100644 layout/reftests/css-ui-valid/select/select-required-valid-changed-2.html delete mode 100644 layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled-changed.html delete mode 100644 layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly-changed.html delete mode 100644 layout/reftests/css-ui-valid/textarea/textarea-required-valid-changed.html delete mode 100644 testing/web-platform/meta/css/selectors/user-invalid.html.ini delete mode 100644 testing/web-platform/meta/css/selectors/user-valid.html.ini diff --git a/dom/html/HTMLButtonElement.h b/dom/html/HTMLButtonElement.h index 75839df7227d..57bc51c05ce8 100644 --- a/dom/html/HTMLButtonElement.h +++ b/dom/html/HTMLButtonElement.h @@ -69,7 +69,7 @@ class HTMLButtonElement final : public nsGenericHTMLFormControlElementWithState, void DoneCreatingElement() override; void UpdateBarredFromConstraintValidation(); - void UpdateValidityElementStates(bool aNotify) final; + void UpdateValidityElementStates(bool aNotify); /** * Called when an attribute is about to be changed */ diff --git a/dom/html/HTMLElement.h b/dom/html/HTMLElement.h index 455eb992f114..8fbbc6f2b9f4 100644 --- a/dom/html/HTMLElement.h +++ b/dom/html/HTMLElement.h @@ -49,7 +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 UpdateValidityElementStates(bool aNotify); void UpdateFormOwner(); diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 6868da337bca..85472708057e 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -121,7 +121,6 @@ HTMLFormElement::HTMLFormElement( mDeferSubmission(false), mNotifiedObservers(false), mNotifiedObserversResult(false), - mEverTriedInvalidSubmit(false), mIsConstructingEntryList(false), mIsFiringSubmissionEvents(false) { // We start out valid. @@ -261,16 +260,28 @@ void HTMLFormElement::MaybeSubmit(Element* aSubmitter) { return; } - // 6.1. If form's firing submission events is true, then return. + // 5.1. If form's firing submission events is true, then return. if (mIsFiringSubmissionEvents) { return; } - // 6.2. Set form's firing submission events to true. + // 5.2. Set form's firing submission events to true. AutoRestore resetFiringSubmissionEventsFlag(mIsFiringSubmissionEvents); mIsFiringSubmissionEvents = true; - // 6.3. If the submitter element's no-validate state is false, then + // Flag elements as user-interacted. + // FIXME: Should be specified, see: + // https://github.com/whatwg/html/issues/10066 + { + for (nsGenericHTMLFormElement* el : mControls->mElements) { + el->SetUserInteracted(true); + } + for (nsGenericHTMLFormElement* el : mControls->mNotInElements) { + el->SetUserInteracted(true); + } + } + + // 5.3. If the submitter element's no-validate state is false, then // interactively validate the constraints of form and examine the result. // If the result is negative (i.e., the constraint validation concluded // that there were invalid fields and probably informed the user of this) @@ -635,7 +646,6 @@ nsresult HTMLFormElement::DoReset() { doc->FlushPendingNotifications(FlushType::ContentAndNotify); } - mEverTriedInvalidSubmit = false; // JBK walk the elements[] array instead of form frame controls - bug 34297 uint32_t numElements = mControls->Length(); for (uint32_t elementX = 0; elementX < numElements; ++elementX) { @@ -1051,15 +1061,11 @@ nsresult HTMLFormElement::ConstructEntryList(FormData* aFormData) { nsresult rv = mControls->GetSortedControls(sortedControls); NS_ENSURE_SUCCESS(rv, rv); - uint32_t len = sortedControls.Length(); - - // // Walk the list of nodes and call SubmitNamesValues() on the controls - // - for (uint32_t i = 0; i < len; ++i) { + for (nsGenericHTMLFormElement* control : sortedControls) { // Disabled elements don't submit - if (!sortedControls[i]->IsDisabled()) { - nsCOMPtr fc = do_QueryInterface(sortedControls[i]); + if (!control->IsDisabled()) { + nsCOMPtr fc = do_QueryInterface(control); MOZ_ASSERT(fc); // Tell the control to submit its name/value pairs to the submission fc->SubmitNamesValues(aFormData); @@ -1768,44 +1774,6 @@ bool HTMLFormElement::CheckValidFormSubmission() { return true; } - // For the first invalid submission, we should update element states. - // We have to do that _before_ calling the observers so we are sure they - // will not interfere (like focusing the element). - if (!mEverTriedInvalidSubmit) { - mEverTriedInvalidSubmit = true; - - /* - * We are going to call update states assuming elements want to - * be notified because we can't know. - * Submissions shouldn't happen during parsing so it _should_ be safe. - */ - - nsAutoScriptBlocker scriptBlocker; - - for (nsGenericHTMLFormElement* element : mControls->mElements) { - // Input elements can trigger a form submission and we want to - // update the style in that case. - 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); - } - } - element->UpdateValidityElementStates(true); - } - - // Because of backward compatibility, is not in - // elements but can be invalid. - // TODO: should probably be removed when bug 606491 will be fixed. - for (nsGenericHTMLFormElement* element : mControls->mNotInElements) { - element->UpdateValidityElementStates(true); - } - } - AutoJSAPI jsapi; if (!jsapi.Init(GetOwnerGlobal())) { return false; diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index 42593b4e9185..1820ebbfa4fa 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -233,16 +233,7 @@ class HTMLFormElement final : public nsGenericHTMLElement, * @param aFormData the form data object */ // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) - MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult ConstructEntryList(FormData* aFormData); - - /** - * Whether the submission of this form has been ever prevented because of - * being invalid. - * - * @return Whether the submission of this form has been prevented because of - * being invalid. - */ - bool HasEverTriedInvalidSubmit() const { return mEverTriedInvalidSubmit; } + MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult ConstructEntryList(FormData*); /** * Implements form[name]. Returns form controls in this form with the correct diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index e225748daa84..ae2c4af82c38 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -248,7 +248,7 @@ class DispatchChangeEventCallback final : public GetFilesCallback { RefPtr inputElement(mInputElement); nsresult rv = nsContentUtils::DispatchInputEvent(inputElement); NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch input event"); - + mInputElement->SetUserInteracted(true); rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(), mInputElement, u"change"_ns, CanBubble::eYes, Cancelable::eNo); @@ -667,6 +667,7 @@ nsColorPickerShownCallback::Done(const nsAString& aColor) { } if (mValueChanged) { + mInput->SetUserInteracted(true); rv = nsContentUtils::DispatchTrustedEvent( mInput->OwnerDoc(), static_cast(mInput.get()), u"change"_ns, CanBubble::eYes, Cancelable::eNo); @@ -995,6 +996,7 @@ HTMLInputElement::HTMLInputElement(already_AddRefed&& aNodeInfo, mAutocompleteInfoState(nsContentUtils::eAutocompleteAttrState_Unknown), mDisabledChanged(false), mValueChanged(false), + mUserInteracted(false), mLastValueChangeWasInteractive(false), mCheckedChanged(false), mChecked(false), @@ -1006,8 +1008,6 @@ HTMLInputElement::HTMLInputElement(already_AddRefed&& aNodeInfo, mCheckedIsToggled(false), mIndeterminate(false), mInhibitRestoration(aFromParser & FROM_PARSER_FRAGMENT), - mCanShowValidUI(true), - mCanShowInvalidUI(true), mHasRange(false), mIsDraggingRange(false), mNumberControlSpinnerIsSpinning(false), @@ -2613,15 +2613,25 @@ void HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged) { } void HTMLInputElement::FireChangeEventIfNeeded() { + if (!MayFireChangeOnBlur()) { + return; + } + // We're not exposing the GetValue return value anywhere here, so it's safe to // claim to be a system caller. nsAutoString value; GetValue(value, CallerType::System); - if (!MayFireChangeOnBlur() || mFocusedValue.Equals(value)) { + // NOTE(emilio): Per spec we should not set this if we don't fire the change + // event, but that seems like a bug. Using mValueChanged seems reasonable to + // keep the expected behavior while + // https://github.com/whatwg/html/issues/10013 is resolved. + if (mValueChanged) { + SetUserInteracted(true); + } + if (mFocusedValue.Equals(value)) { return; } - // Dispatch the change event. mFocusedValue = value; nsContentUtils::DispatchTrustedEvent( @@ -3146,9 +3156,9 @@ bool HTMLInputElement::CheckActivationBehaviorPreconditions( // we're a DOMActivate dispatched from click handling, it will not be set. WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); bool outerActivateEvent = - ((mouseEvent && mouseEvent->IsLeftClickEvent()) || - (aVisitor.mEvent->mMessage == eLegacyDOMActivate && - !mInInternalActivate)); + (mouseEvent && mouseEvent->IsLeftClickEvent()) || + (aVisitor.mEvent->mMessage == eLegacyDOMActivate && + !mInInternalActivate); if (outerActivateEvent) { aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT; } @@ -3505,11 +3515,9 @@ void HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection) { // the user. (IsValid() can return false if the 'required' attribute is // set and the value is the empty string.) if (!IsValueEmpty()) { - // We pass 'true' for UpdateValidityUIBits' aIsFocused argument - // regardless because we need the UI to update _now_ or the user will - // wonder why the step behavior isn't functioning. - UpdateValidityUIBits(true); - UpdateValidityElementStates(true); + // We pass 'true' for SetUserInteracted because we need the UI to update + // _now_ or the user will wonder why the step behavior isn't functioning. + SetUserInteracted(true); return; } } @@ -3664,18 +3672,12 @@ static bool ActivatesWithKeyboard(FormControlType aType, uint32_t aKeyCode) { } nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { - if (aVisitor.mEvent->mMessage == eFocus || - aVisitor.mEvent->mMessage == eBlur) { - if (aVisitor.mEvent->mMessage == eBlur) { - if (mIsDraggingRange) { - FinishRangeThumbDrag(); - } else if (mNumberControlSpinnerIsSpinning) { - StopNumberControlSpinnerSpin(); - } + if (aVisitor.mEvent->mMessage == eBlur) { + if (mIsDraggingRange) { + FinishRangeThumbDrag(); + } else if (mNumberControlSpinnerIsSpinning) { + StopNumberControlSpinnerSpin(); } - - UpdateValidityUIBits(aVisitor.mEvent->mMessage == eFocus); - UpdateValidityElementStates(true); } nsresult rv = NS_OK; @@ -4076,11 +4078,14 @@ void HTMLInputElement::ActivationBehavior(EventChainPostVisitor& aVisitor) { } if (mCheckedIsToggled) { + SetUserInteracted(true); + // Fire input event and then change event. DebugOnly rvIgnored = nsContentUtils::DispatchInputEvent(this); NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored), "Failed to dispatch input event"); + // FIXME: Why is this different than every other change event? nsContentUtils::DispatchTrustedEvent( OwnerDoc(), static_cast(this), eFormChange, CanBubble::eYes, Cancelable::eNo); @@ -4094,8 +4099,7 @@ void HTMLInputElement::ActivationBehavior(EventChainPostVisitor& aVisitor) { FireEventForAccessibility(this, eFormRadioStateChange); // Fire event for the previous selected radio. nsCOMPtr content = do_QueryInterface(aVisitor.mItemData); - if (HTMLInputElement* previous = - HTMLInputElement::FromNodeOrNull(content)) { + if (auto* previous = HTMLInputElement::FromNodeOrNull(content)) { FireEventForAccessibility(previous, eFormRadioStateChange); } } @@ -5927,6 +5931,7 @@ HTMLInputElement::Reset() { SetCheckedChanged(false); SetValueChanged(false); SetLastValueChangeWasInteractive(false); + SetUserInteracted(false); switch (GetValueMode()) { case VALUE_MODE_VALUE: { @@ -6222,25 +6227,15 @@ void HTMLInputElement::UpdateValidityElementStates(bool aNotify) { ElementState state; if (IsValid()) { state |= ElementState::VALID; + if (mUserInteracted) { + state |= ElementState::USER_VALID; + } } else { state |= ElementState::INVALID; - if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) || - (mCanShowInvalidUI && ShouldShowValidityUI())) { + if (mUserInteracted) { 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; - } AddStatesSilently(state); } @@ -7251,19 +7246,12 @@ Decimal HTMLInputElement::GetDefaultStep() const { } } -void HTMLInputElement::UpdateValidityUIBits(bool aIsFocused) { - if (aIsFocused) { - // If the invalid UI is shown, we should show it while focusing (and - // update). Otherwise, we should not. - mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI(); - - // If neither invalid UI nor valid UI is shown, we shouldn't show the valid - // UI while typing. - mCanShowValidUI = ShouldShowValidityUI(); - } else { - mCanShowInvalidUI = true; - mCanShowValidUI = true; +void HTMLInputElement::SetUserInteracted(bool aInteracted) { + if (mUserInteracted == aInteracted) { + return; } + mUserInteracted = aInteracted; + UpdateValidityElementStates(true); } void HTMLInputElement::UpdateInRange(bool aNotify) { diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index 9e83938057bb..5f86e54542b0 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -15,7 +15,6 @@ #include "mozilla/UniquePtr.h" #include "mozilla/Variant.h" #include "mozilla/dom/BindingDeclarations.h" -#include "mozilla/dom/HTMLFormElement.h" // for HasEverTriedInvalidSubmit() #include "mozilla/dom/HTMLInputElementBinding.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/UnionTypes.h" @@ -36,6 +35,7 @@ #include "nsIContentPrefService2.h" #include "nsContentUtils.h" +class nsIEditor; class nsIRadioVisitor; namespace mozilla { @@ -338,7 +338,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; + void UpdateValidityElementStates(bool aNotify); MOZ_CAN_RUN_SCRIPT void MaybeUpdateAllValidityStates(bool aNotify) { // If you need to add new type which supports validationMessage, you should @@ -395,16 +395,7 @@ class HTMLInputElement final : public TextControlElement, */ void SetFilePickerFiltersFromAccept(nsIFilePicker* filePicker); - /** - * The form might need to request an update of the UI bits - * (BF_CAN_SHOW_INVALID_UI and BF_CAN_SHOW_VALID_UI) when an invalid form - * submission is tried. - * - * @param aIsFocused Whether the element is currently focused. - * - * @note The caller is responsible to call ContentStatesChanged. - */ - void UpdateValidityUIBits(bool aIsFocused); + void SetUserInteracted(bool) final; /** * Fires change event if mFocusedValue and current value held are unequal and @@ -1115,37 +1106,6 @@ class HTMLInputElement final : public TextControlElement, void SetAutoDirectionality(bool aNotify, const nsAString* aKnownValue = nullptr); - /** - * Return if an element should have a specific validity UI - * (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes). - * - * @return Whether the element should have a validity UI. - */ - bool ShouldShowValidityUI() const { - /** - * Always show the validity UI if the form has already tried to be submitted - * but was invalid. - * - * Otherwise, show the validity UI if the element's value has been changed. - */ - if (mForm && mForm->HasEverTriedInvalidSubmit()) { - return true; - } - - switch (GetValueMode()) { - case VALUE_MODE_DEFAULT: - return true; - case VALUE_MODE_DEFAULT_ON: - return GetCheckedChanged(); - case VALUE_MODE_VALUE: - case VALUE_MODE_FILENAME: - return mValueChanged; - } - - MOZ_ASSERT_UNREACHABLE("We should not be there: there are no other modes."); - return false; - } - /** * Returns the radio group container within the DOM tree that the element * is currently a member of, if one exists. @@ -1551,6 +1511,8 @@ class HTMLInputElement final : public TextControlElement, // https://html.spec.whatwg.org/#concept-fe-dirty // TODO: Maybe rename to match the spec? bool mValueChanged : 1; + // https://html.spec.whatwg.org/#user-interacted + bool mUserInteracted : 1; bool mLastValueChangeWasInteractive : 1; bool mCheckedChanged : 1; bool mChecked : 1; @@ -1561,8 +1523,6 @@ class HTMLInputElement final : public TextControlElement, bool mCheckedIsToggled : 1; bool mIndeterminate : 1; bool mInhibitRestoration : 1; - bool mCanShowValidUI : 1; - bool mCanShowInvalidUI : 1; bool mHasRange : 1; bool mIsDraggingRange : 1; bool mNumberControlSpinnerIsSpinning : 1; diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp index 125f443f7ba6..18bf2b79b28f 100644 --- a/dom/html/HTMLSelectElement.cpp +++ b/dom/html/HTMLSelectElement.cpp @@ -119,10 +119,8 @@ HTMLSelectElement::HTMLSelectElement( mDisabledChanged(false), mMutating(false), mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)), - mSelectionHasChanged(false), + mUserInteracted(false), mDefaultSelectionSet(false), - mCanShowInvalidUI(true), - mCanShowValidUI(true), mIsOpenInParentProcess(false), mNonOptionChildren(0), mOptGroupCount(0), @@ -282,7 +280,7 @@ void HTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions, // Fix the currently selected index if (aListIndex <= mSelectedIndex) { mSelectedIndex += (insertIndex - aListIndex); - SetSelectionChanged(true, aNotify); + OnSelectionChanged(); } // Get the frame stuff for notification. No need to flush here @@ -382,7 +380,7 @@ nsresult HTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions, // If this is a Combobox, no other Item will be selected. if (IsCombobox()) { mSelectedIndex = -1; - SetSelectionChanged(true, aNotify); + OnSelectionChanged(); } else { FindSelectedIndex(aListIndex, aNotify); } @@ -390,7 +388,7 @@ nsresult HTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions, // Shift the selected index if something in front of it was removed // aListIndex+numRemoved <= mSelectedIndex mSelectedIndex -= numRemoved; - SetSelectionChanged(true, aNotify); + OnSelectionChanged(); } } @@ -701,7 +699,7 @@ void HTMLSelectElement::SetSelectedIndexInternal(int32_t aIndex, bool aNotify) { selectFrame->OnSetSelectedIndex(oldSelectedIndex, mSelectedIndex); } - SetSelectionChanged(true, aNotify); + OnSelectionChanged(); } bool HTMLSelectElement::IsOptionSelectedByIndex(int32_t aIndex) const { @@ -716,7 +714,7 @@ void HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame, // Set the selected index if (aSelected && (aIndex < mSelectedIndex || mSelectedIndex < 0)) { mSelectedIndex = aIndex; - SetSelectionChanged(true, aNotify); + OnSelectionChanged(); } else if (!aSelected && aIndex == mSelectedIndex) { FindSelectedIndex(aIndex + 1, aNotify); } @@ -741,15 +739,14 @@ void HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame, void HTMLSelectElement::FindSelectedIndex(int32_t aStartIndex, bool aNotify) { mSelectedIndex = -1; - SetSelectionChanged(true, aNotify); uint32_t len = Length(); for (int32_t i = aStartIndex; i < int32_t(len); i++) { if (IsOptionSelectedByIndex(i)) { mSelectedIndex = i; - SetSelectionChanged(true, aNotify); break; } } + OnSelectionChanged(); } // XXX Consider splitting this into two functions for ease of reading: @@ -1270,27 +1267,6 @@ void HTMLSelectElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) { nsGenericHTMLFormControlElementWithState::GetEventTargetParent(aVisitor); } -nsresult HTMLSelectElement::PostHandleEvent(EventChainPostVisitor& aVisitor) { - if (aVisitor.mEvent->mMessage == eFocus) { - // If the invalid UI is shown, we should show it while focused and - // update the invalid/valid UI. - mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI(); - - // If neither invalid UI nor valid UI is shown, we shouldn't show the valid - // UI while focused. - mCanShowValidUI = ShouldShowValidityUI(); - - // We don't have to update ElementState::USER_INVALID nor - // ElementState::USER_VALID given that the states should not change. - } else if (aVisitor.mEvent->mMessage == eBlur) { - mCanShowInvalidUI = true; - mCanShowValidUI = true; - UpdateValidityElementStates(true); - } - - return nsGenericHTMLFormControlElementWithState::PostHandleEvent(aVisitor); -} - void HTMLSelectElement::UpdateValidityElementStates(bool aNotify) { AutoStateChangeNotifier notifier(*this, aNotify); RemoveStatesSilently(ElementState::VALIDITY_STATES); @@ -1301,28 +1277,16 @@ void HTMLSelectElement::UpdateValidityElementStates(bool aNotify) { ElementState state; if (IsValid()) { state |= ElementState::VALID; + if (mUserInteracted) { + state |= ElementState::USER_VALID; + } } else { state |= ElementState::INVALID; - - 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); } @@ -1453,9 +1417,9 @@ HTMLSelectElement::Reset() { SelectSomething(true); } - SetSelectionChanged(false, true); + OnSelectionChanged(); + SetUserInteracted(false); - // // Let the frame know we were reset // // Don't flush, if there's no frame yet it won't care about us being @@ -1626,18 +1590,11 @@ void HTMLSelectElement::FieldSetDisabledChanged(bool aNotify) { UpdateValidityElementStates(aNotify); } -void HTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify) { +void HTMLSelectElement::OnSelectionChanged() { if (!mDefaultSelectionSet) { return; } - UpdateSelectedOptions(); - - bool previousSelectionChangedValue = mSelectionHasChanged; - mSelectionHasChanged = aValue; - if (mSelectionHasChanged != previousSelectionChangedValue) { - UpdateValidityElementStates(aNotify); - } } void HTMLSelectElement::UpdateSelectedOptions() { @@ -1646,6 +1603,14 @@ void HTMLSelectElement::UpdateSelectedOptions() { } } +void HTMLSelectElement::SetUserInteracted(bool aInteracted) { + if (mUserInteracted == aInteracted) { + return; + } + mUserInteracted = aInteracted; + UpdateValidityElementStates(true); +} + void HTMLSelectElement::SetPreviewValue(const nsAString& aValue) { mPreviewValue = aValue; nsContentUtils::RemoveNewlines(mPreviewValue); @@ -1656,6 +1621,22 @@ void HTMLSelectElement::SetPreviewValue(const nsAString& aValue) { } } +void HTMLSelectElement::UserFinishedInteracting(bool aChanged) { + SetUserInteracted(true); + if (!aChanged) { + return; + } + + // Dispatch the input event. + DebugOnly rvIgnored = nsContentUtils::DispatchInputEvent(this); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored), + "Failed to dispatch input event"); + + // Dispatch the change event. + nsContentUtils::DispatchTrustedEvent(OwnerDoc(), this, u"change"_ns, + CanBubble::eYes, Cancelable::eNo); +} + JSObject* HTMLSelectElement::WrapNode(JSContext* aCx, JS::Handle aGivenProto) { return HTMLSelectElement_Binding::Wrap(aCx, this, aGivenProto); diff --git a/dom/html/HTMLSelectElement.h b/dom/html/HTMLSelectElement.h index fed70051def3..223da65c31fb 100644 --- a/dom/html/HTMLSelectElement.h +++ b/dom/html/HTMLSelectElement.h @@ -128,6 +128,9 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState, void GetAutocompleteInfo(AutocompleteInfo& aInfo); + // Sets the user interacted flag and fires input/change events if needed. + MOZ_CAN_RUN_SCRIPT void UserFinishedInteracting(bool aChanged); + bool Disabled() const { return GetBoolAttr(nsGkAtoms::disabled); } void SetDisabled(bool aVal, ErrorResult& aRv) { SetHTMLBoolAttr(nsGkAtoms::disabled, aVal, aRv); @@ -194,8 +197,6 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState, // nsIContent void GetEventTargetParent(EventChainPreVisitor& aVisitor) override; - MOZ_CAN_RUN_SCRIPT - nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override; bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t* aTabIndex) override; @@ -300,7 +301,7 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState, ValidityStateType aType) override; void UpdateValueMissingValidityState(); - void UpdateValidityElementStates(bool aNotify) final; + void UpdateValidityElementStates(bool aNotify); /** * Insert aElement before the node given by aBefore */ @@ -451,7 +452,7 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState, void SetSelectedIndexInternal(int32_t aIndex, bool aNotify); - void SetSelectionChanged(bool aValue, bool aNotify); + void OnSelectionChanged(); /** * Marks the selectedOptions list as dirty, so that it'll populate itself @@ -459,25 +460,7 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState, */ void UpdateSelectedOptions(); - /** - * Return whether an element should have a validity UI. - * (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes). - * - * @return Whether the element should have a validity UI. - */ - bool ShouldShowValidityUI() const { - /** - * Always show the validity UI if the form has already tried to be submitted - * but was invalid. - * - * Otherwise, show the validity UI if the selection has been changed. - */ - if (mForm && mForm->HasEverTriedInvalidSubmit()) { - return true; - } - - return mSelectionHasChanged; - } + void SetUserInteracted(bool) final; /** The options[] array */ RefPtr mOptions; @@ -495,23 +478,10 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState, * True if DoneAddingChildren will get called but shouldn't restore state. */ bool mInhibitStateRestoration : 1; - /** - * True if the selection has changed since the element's creation. - */ - bool mSelectionHasChanged : 1; - /** - * True if the default selected option has been set. - */ + /** https://html.spec.whatwg.org/#user-interacted */ + bool mUserInteracted : 1; + /** True if the default selected option has been set. */ bool mDefaultSelectionSet : 1; - /** - * True if :-moz-ui-invalid can be shown. - */ - bool mCanShowInvalidUI : 1; - /** - * True if :-moz-ui-valid can be shown. - */ - bool mCanShowValidUI : 1; - /** True if we're open in the parent process */ bool mIsOpenInParentProcess : 1; diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index 2423f3bb6dd2..046655453859 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -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 , 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 diff --git a/dom/html/HTMLTextAreaElement.h b/dom/html/HTMLTextAreaElement.h index 266be29b0f8b..ac3eb8bbf532 100644 --- a/dom/html/HTMLTextAreaElement.h +++ b/dom/html/HTMLTextAreaElement.h @@ -288,25 +288,23 @@ class HTMLTextAreaElement final : public TextControlElement, JSObject* WrapNode(JSContext*, JS::Handle aGivenProto) override; nsCOMPtr mControllers; + /** https://html.spec.whatwg.org/#user-interacted */ + bool mUserInteracted = false; /** Whether or not the value has changed since its default value was given. */ - bool mValueChanged; + bool mValueChanged = false; /** Whether or not the last change to the value was made interactively by the * user. */ - bool mLastValueChangeWasInteractive; + bool mLastValueChangeWasInteractive = false; /** Whether or not we are already handling select event. */ - bool mHandlingSelect; + bool mHandlingSelect = false; /** Whether or not we are done adding children (always true if not created by a parser */ bool mDoneAddingChildren; /** Whether state restoration should be inhibited in DoneAddingChildren. */ bool mInhibitStateRestoration; /** Whether our disabled state has changed from the default **/ - bool mDisabledChanged; - /** Whether we should make :-moz-ui-invalid apply on the element. **/ - bool mCanShowInvalidUI; - /** Whether we should make :-moz-ui-valid apply on the element. **/ - bool mCanShowValidUI; - bool mIsPreviewEnabled; + bool mDisabledChanged = false; + bool mIsPreviewEnabled = false; nsContentUtils::AutocompleteAttrState mAutocompleteAttrState; @@ -350,27 +348,6 @@ class HTMLTextAreaElement final : public TextControlElement, void SetDirectionFromValue(bool aNotify, const nsAString* aKnownValue = nullptr); - /** - * Return if an element should have a specific validity UI - * (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes). - * - * @return Whether the element should have a validity UI. - */ - bool ShouldShowValidityUI() const { - /** - * Always show the validity UI if the form has already tried to be submitted - * but was invalid. - * - * Otherwise, show the validity UI if the element's value has been changed. - */ - - if (mForm && mForm->HasEverTriedInvalidSubmit()) { - return true; - } - - return mValueChanged; - } - /** * Get the mutable state of the element. */ @@ -392,7 +369,8 @@ class HTMLTextAreaElement final : public TextControlElement, void GetSelectionRange(uint32_t* aSelectionStart, uint32_t* aSelectionEnd, ErrorResult& aRv); - void UpdateValidityElementStates(bool aNotify) final; + void SetUserInteracted(bool) final; + void UpdateValidityElementStates(bool aNotify); private: static void MapAttributesIntoRule(MappedDeclarationsBuilder&); diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index 04dcfc184c03..145b30ea75c5 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -1795,7 +1795,6 @@ void nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm, UnsetFlags(ADDED_TO_FORM); SetFormInternal(nullptr, false); AfterClearForm(aUnbindOrDelete); - UpdateValidityElementStates(true); } nsresult nsGenericHTMLFormElement::BindToTree(BindContext& aContext, @@ -2148,11 +2147,6 @@ void nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree, form->AddElementToTable(this, idVal); } } - - if (form != oldForm) { - // ui-valid / invalid depends on the form for some elements - UpdateValidityElementStates(true); - } } void nsGenericHTMLFormElement::UpdateFieldSet(bool aNotify) { diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h index 3ca31e277701..b3790314208c 100644 --- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -1022,10 +1022,9 @@ class nsGenericHTMLFormElement : public nsGenericHTMLElement { */ already_AddRefed 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) {} + // Sets the user-interacted flag in + // https://html.spec.whatwg.org/#user-interacted, if it applies. + virtual void SetUserInteracted(bool aNotify) {} protected: virtual ~nsGenericHTMLFormElement() = default; diff --git a/dom/html/nsIConstraintValidation.cpp b/dom/html/nsIConstraintValidation.cpp index 11ef8b028efc..6ccda2ea7e4c 100644 --- a/dom/html/nsIConstraintValidation.cpp +++ b/dom/html/nsIConstraintValidation.cpp @@ -83,13 +83,6 @@ bool nsIConstraintValidation::ReportValidity() { event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; element->DispatchEvent(*event); - - auto* inputElement = HTMLInputElement::FromNode(element); - if (inputElement && inputElement->State().HasState(ElementState::FOCUS)) { - inputElement->UpdateValidityUIBits(true); - inputElement->UpdateValidityElementStates(true); - } - return false; } diff --git a/dom/html/test/test_bug605124-1.html b/dom/html/test/test_bug605124-1.html index 8530b8d54465..d252987ee922 100644 --- a/dom/html/test/test_bug605124-1.html +++ b/dom/html/test/test_bug605124-1.html @@ -37,8 +37,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=605124 function checkPseudoClass(aElement, aExpected) { - is(aElement.matches(":-moz-ui-invalid"), aExpected, - "matches(':-moz-ui-invalid') should return " + aExpected + " for " + aElement); + is(aElement.matches(":user-invalid"), aExpected, + "matches(':user-invalid') should return " + aExpected + " for " + aElement); } var content = document.getElementById('content'); @@ -62,9 +62,9 @@ checkPseudoClass(select, true); content.appendChild(textarea); content.appendChild(input); content.appendChild(select); -checkPseudoClass(textarea, false); -checkPseudoClass(input, false); -checkPseudoClass(select, false); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); // Back in the form. form.appendChild(textarea); @@ -89,10 +89,9 @@ checkPseudoClass(select, true); // Remove the form. document.getElementsByTagName('table')[0].removeChild(form); -checkPseudoClass(textarea, false); -checkPseudoClass(input, false); -checkPseudoClass(select, false); - +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); diff --git a/dom/html/test/test_bug605125-2.html b/dom/html/test/test_bug605125-2.html index 650e201e3998..d06b17c084c1 100644 --- a/dom/html/test/test_bug605125-2.html +++ b/dom/html/test/test_bug605125-2.html @@ -31,15 +31,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=605125 function checkPseudoClass(aElement, aExpected) { - is(aElement.matches(":-moz-ui-valid"), aExpected, - "matches(':-moz-ui-valid') should return " + aExpected + " for " + aElement); + is(aElement.matches(":user-valid"), aExpected, + "matches(':user-valid') should return " + aExpected + " for " + aElement); } function checkElement(aElement) { checkPseudoClass(aElement, false); - // Focusing while :-moz-ui-valid doesn't apply, + // Focusing while :user-valid doesn't apply, // the pseudo-class should not apply while typing. aElement.focus(); checkPseudoClass(aElement, false); @@ -57,7 +57,7 @@ function checkElement(aElement) aElement.blur(); checkPseudoClass(aElement, true); - // Focusing while :-moz-ui-valid applies, + // Focusing while :user-valid applies, // the pseudo-class should apply while typing if appropriate. aElement.focus(); checkPseudoClass(aElement, true); @@ -76,7 +76,7 @@ function checkElement(aElement) aElement.required = true; checkPseudoClass(aElement, false); - // Focusing while :-moz-ui-invalid applies, + // Focusing while :user-invalid applies, // the pseudo-class should apply while typing if appropriate. aElement.focus(); checkPseudoClass(aElement, false); @@ -96,20 +96,15 @@ function checkSelectElement(aElement) { checkPseudoClass(aElement, false); - // Focusing while :-moz-ui-valid doesn't apply, + // Focusing while :user-valid doesn't apply, // the pseudo-class should not apply while changing selection. aElement.focus(); checkPseudoClass(aElement, false); - aElement.selectedIndex = 1; - checkPseudoClass(aElement, false); - aElement.selectedIndex = 0; - checkPseudoClass(aElement, false); - - aElement.blur(); + synthesizeKey("KEY_ArrowDown"); checkPseudoClass(aElement, true); - // Focusing while :-moz-ui-valid applies, + // Focusing while :user-valid applies, // the pseudo-class should apply while changing selection if appropriate. aElement.focus(); checkPseudoClass(aElement, true); @@ -127,12 +122,12 @@ function checkSelectElement(aElement) } checkPseudoClass(aElement, false); - // Focusing while :-moz-ui-invalid applies, + // Focusing while :user-invalid applies, // the pseudo-class should apply while changing selection if appropriate. aElement.focus(); checkPseudoClass(aElement, false); - aElement.selectedIndex = 1; + synthesizeKey("KEY_ArrowDown"); checkPseudoClass(aElement, true); aElement.selectedIndex = 0; checkPseudoClass(aElement, aElement.multiple); diff --git a/dom/html/test/test_bug610687.html b/dom/html/test/test_bug610687.html index 98f3c16584e4..fd6950cce4b0 100644 --- a/dom/html/test/test_bug610687.html +++ b/dom/html/test/test_bug610687.html @@ -11,7 +11,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=610687 Mozilla Bug 610687

-