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
Родитель 1aa61dcd48
Коммит 71838e2f11
69 изменённых файлов: 203 добавлений и 1109 удалений

Просмотреть файл

@ -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
*/

Просмотреть файл

@ -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();

Просмотреть файл

@ -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<bool> 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<nsIFormControl> fc = do_QueryInterface(sortedControls[i]);
if (!control->IsDisabled()) {
nsCOMPtr<nsIFormControl> 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, <input type='image'> 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;

Просмотреть файл

@ -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

Просмотреть файл

@ -248,7 +248,7 @@ class DispatchChangeEventCallback final : public GetFilesCallback {
RefPtr<HTMLInputElement> 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<Element*>(mInput.get()), u"change"_ns,
CanBubble::eYes, Cancelable::eNo);
@ -995,6 +996,7 @@ HTMLInputElement::HTMLInputElement(already_AddRefed<dom::NodeInfo>&& 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<dom::NodeInfo>&& 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<nsresult> 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<WidgetEvent>(
OwnerDoc(), static_cast<Element*>(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<nsIContent> 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) {

Просмотреть файл

@ -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;

Просмотреть файл

@ -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<nsresult> 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<JSObject*> aGivenProto) {
return HTMLSelectElement_Binding::Wrap(aCx, this, aGivenProto);

Просмотреть файл

@ -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<HTMLOptionsCollection> 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;

Просмотреть файл

@ -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

Просмотреть файл

@ -288,25 +288,23 @@ class HTMLTextAreaElement final : public TextControlElement,
JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
nsCOMPtr<nsIControllers> 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&);

Просмотреть файл

@ -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) {

Просмотреть файл

@ -1022,10 +1022,9 @@ 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) {}
// 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;

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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);
</script>
</pre>
</body>

Просмотреть файл

@ -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);

Просмотреть файл

@ -11,7 +11,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=610687
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=610687">Mozilla Bug 610687</a>
<p id="display"></p>
<div id="content" style="display: none">
<div id="content">
<form>
<input type='radio' name='a'>
<input type='radio' name='a'>
@ -34,14 +34,14 @@ function checkPseudoClasses(aElement, aValid, aValidUI, aInvalidUI)
ok(aElement.matches(":invalid"), ":invalid should apply");
}
is(aElement.matches(":-moz-ui-valid"), aValidUI,
aValid ? ":-moz-ui-valid should apply" : ":-moz-ui-valid should not apply");
is(aElement.matches(":user-valid"), aValidUI,
aValid ? ":user-valid should apply" : ":user-valid should not apply");
is(aElement.matches(":-moz-ui-invalid"), aInvalidUI,
aInvalidUI ? ":-moz-ui-invalid should apply" : ":-moz-ui-invalid should not apply");
is(aElement.matches(":user-invalid"), aInvalidUI,
aInvalidUI ? ":user-invalid should apply" : ":user-invalid should not apply");
if (aInvalidUI && (aValid || aValidUI)) {
ok(false, ":invalid can't apply with :valid or :-moz-valid-ui");
ok(false, ":invalid can't apply with :valid or :user-valid");
}
}
@ -63,23 +63,17 @@ function checkRadios(r1, r2, r3, form)
checkPseudoClasses(r2, false, false, false);
checkPseudoClasses(r3, true, false, false);
// Suffering from being missing (with ui-invalid).
r1.checked = false;
checkPseudoClasses(r1, false, false, true);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r3, true, false, false);
// Do not suffer from being missing (with ui-valid).
r1.checked = true;
r1.click();
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, true, true, false);
checkPseudoClasses(r2, true, false, false);
checkPseudoClasses(r3, true, false, false);
// Do not suffer from being missing (with ui-valid).
r1.checked = false;
r1.required = false;
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, true, true, false);
checkPseudoClasses(r2, true, false, false);
checkPseudoClasses(r3, true, false, false);
// Suffering from being missing (with ui-invalid) with required set on one radio
@ -87,35 +81,35 @@ function checkRadios(r1, r2, r3, form)
r1.required = true;
r2.checked = false;
checkPseudoClasses(r1, false, false, true);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
checkPseudoClasses(r3, true, false, false);
// Do not suffer from being missing (with ui-valid) by checking the radio which
// hasn't the required attribute.
r2.checked = true;
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, true, true, false);
checkPseudoClasses(r2, true, false, false);
checkPseudoClasses(r3, true, false, false);
// .setCustomValidity() should not affect the entire group.
r1.checked = r2.checked = r3.checked = false;
r1.checked = false; r2.checked = false; r3.checked = false;
r1.required = false;
r1.setCustomValidity('foo');
checkPseudoClasses(r1, false, false, true);
checkPseudoClasses(r2, true, true, false);
checkPseudoClasses(r3, true, true, false);
checkPseudoClasses(r2, true, false, false);
checkPseudoClasses(r3, true, false, false);
r1.setCustomValidity('');
r2.setCustomValidity('foo');
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r3, true, true, false);
checkPseudoClasses(r2, false, false, false);
checkPseudoClasses(r3, true, false, false);
r2.setCustomValidity('');
r3.setCustomValidity('foo');
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, true, true, false);
checkPseudoClasses(r3, false, false, true);
checkPseudoClasses(r2, true, false, false);
checkPseudoClasses(r3, false, false, false);
// Removing the radio with the required attribute should make the group valid.
r1.setCustomValidity('');
@ -124,64 +118,64 @@ function checkRadios(r1, r2, r3, form)
r2.required = true;
r1.checked = r2.checked = false;
checkPseudoClasses(r1, false, false, true);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
var p = r2.parentNode;
p.removeChild(r2);
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
p.appendChild(r2);
checkPseudoClasses(r1, false, false, true);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
// Adding a radio element to an invalid group should make it invalid.
p.removeChild(r1);
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
p.appendChild(r1);
checkPseudoClasses(r1, false, false, true);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
// Adding a checked radio element to an invalid group should make it valid.
p.removeChild(r1);
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
r1.checked = true;
p.appendChild(r1);
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, true, true, false);
checkPseudoClasses(r2, true, false, false);
r1.checked = false;
// Adding an invalid radio element by changing the name attribute.
r2.name = 'c';
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
r2.name = 'a';
checkPseudoClasses(r1, false, false, true);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
// Adding an element to an invalid radio group by changing the name attribute.
r1.name = 'c';
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
r1.name = 'a';
checkPseudoClasses(r1, false, false, true);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
// Adding a checked element to an invalid radio group with the name attribute.
r1.name = 'c';
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, false, false, true);
checkPseudoClasses(r2, false, false, false);
r1.checked = true;
r1.name = 'a';
checkPseudoClasses(r1, true, true, false);
checkPseudoClasses(r2, true, true, false);
checkPseudoClasses(r2, true, false, false);
r1.checked = false;
}

Просмотреть файл

@ -26,9 +26,6 @@ interface HTMLSelectElement : HTMLElement {
[CEReactions, SetterThrows, Pure]
attribute unsigned long size;
[ChromeOnly, Pure]
readonly attribute boolean isCombobox;
[Pure]
readonly attribute DOMString type;
@ -72,6 +69,10 @@ interface HTMLSelectElement : HTMLElement {
// Chrome only interface
partial interface HTMLSelectElement {
[ChromeOnly]
undefined userFinishedInteracting(boolean changed);
[ChromeOnly, Pure]
readonly attribute boolean isCombobox;
[ChromeOnly]
attribute boolean openInParentProcess;
[ChromeOnly]

Просмотреть файл

@ -377,15 +377,7 @@ void HTMLSelectEventListener::ComboboxMightHaveChanged() {
void HTMLSelectEventListener::FireOnInputAndOnChange() {
RefPtr<HTMLSelectElement> element = mElement;
// Dispatch the input event.
DebugOnly<nsresult> rvIgnored = nsContentUtils::DispatchInputEvent(element);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
"Failed to dispatch input event");
// Dispatch the change event.
nsContentUtils::DispatchTrustedEvent(element->OwnerDoc(), element,
u"change"_ns, CanBubble::eYes,
Cancelable::eNo);
element->UserFinishedInteracting(/* aChanged = */ true);
}
static void FireDropDownEvent(HTMLSelectElement* aElement, bool aShow,

Просмотреть файл

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if input isn't valid nor barred from constraint validation,
and its checkedness has changed,
it should be affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').checked = false;
if (!document.getElementById('i').matches(':-moz-ui-invalid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i' type='checkbox' required>
</body>
</html>

Просмотреть файл

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<script>
function doTest() {
document.getElementById('t').setCustomValidity('foo');
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
</head>
<!-- Test: if input has a custom error, it should be affected by :-moz-ui-invalid
pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body>
<input class='invalid' id='t'>
</body>
</html>

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if input is not disabled and invalid, it is candidate for
constraint validation and should be affected
by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<script>
function onLoadHandler()
{
var e = document.getElementById('i');
e.setCustomValidity('foo');
e.removeAttribute('disabled');
document.documentElement.className='';
}
</script>
<body onload="onLoadHandler();">
<input class='invalid' id='i' disabled>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if input is no longer readonly, invalid and has it's value changed,
it's affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').removeAttribute('readonly');
document.getElementById('i').value = '';
document.documentElement.className='';">
<input class='invalid' id='i' readonly required>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if input isn't valid nor barred from constraint validation,
and its value has changed,
it should be affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value = 'foo';
document.documentElement.className='';">
<input id='i' class='invalid' type='email' value='bar'>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input isn't valid nor barred from constraint validation,
but its default value hasn't been changed,
it should not be affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value='';
document.documentElement.className='';">
<input id='i' class='invalid' type='file' required>
</body>
</html>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input isn't valid nor barred from constraint validation,
and its value isn't the default value,
it should be affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value='foo';
document.documentElement.className='';">
<input id='i' class='invalid' pattern='bar' value='f'>
</body>
</html>

Просмотреть файл

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if one radio in a group is suffering from a custom error, the other
radio should not be invalid. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i1').checked = false;
document.getElementById('i1').setCustomValidity('foo');
if (!document.getElementById('i1').matches(':-moz-ui-invalid') ||
document.getElementById('i2').matches(':-moz-ui-invalid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i1' name='foo' type='radio'>
<input id='i2' name='foo' type='radio'>
</body>
</html>

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').checked = false;
if (!document.getElementById('i').matches(':-moz-ui-invalid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i' type='radio' required name='i'>
</body>
</html>

Просмотреть файл

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if input isn't valid nor barred from constraint validation,
and its checkedness has changed,
it should be affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').checked = false;
if (!document.getElementById('i').matches(':-moz-ui-invalid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i' type='radio' required name='i'>
</body>
</html>

Просмотреть файл

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if one radio in a group has the required attribute and no radio is
checked, all radio in the group should have :-moz-ui-invalid
pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i1').checked = false;
if (!document.getElementById('i1').matches(':-moz-ui-invalid') ||
!document.getElementById('i2').matches(':-moz-ui-invalid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i1' name='foo' type='radio' required>
<input id='i2' name='foo' type='radio'>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input isn't valid nor barred from constraint validation,
it should be affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value='';
document.documentElement.className='';">
<input id='i' class='invalid' required>
</body>
</html>

Просмотреть файл

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if an input has a custom error when barred from constraint
validation then move a type candidate for constraint validation,
it should not be affected by :valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<script>
function doTest()
{
var i = document.getElementById('i');
i.setCustomValidity('foo');
i.type = 'text';
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
<body>
<input class='invalid' type='button' id='i'>
</body>
</html>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input isn't valid nor barred from constraint validation,
and its value is not the default value,
it should be affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value='foo';
document.documentElement.className='';">
<input id='i' class='invalid' type='url'>
</body>
</html>

Просмотреть файл

@ -1,41 +1,27 @@
== input-valid.html input-ref.html
fuzzy(0-64,0-4) == input-customerror.html input-ref.html
fuzzy(0-1,0-3) == input-disabled.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-disabled.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-not-disabled.html input-ref.html
fuzzy(0-1,0-3) == input-readonly.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-readonly.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-not-readonly-not-changed.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-not-readonly-changed.html input-ref.html
== input-required-valid.html input-withtext-ref.html
fuzzy(0-1,0-3) == input-required-invalid-default.html input-ref.html
fuzzy(0-1,0-3) == input-required-invalid-changed.html input-ref.html
fuzzy(0-2,0-5) == input-button.html input-button-ref.html
fuzzy(0-2,0-5) == input-reset.html input-button-ref.html
== input-email-invalid-default.html input-withtext-ref.html
== input-email-invalid-changed.html input-withtext-ref.html
fuzzy(0-2,0-5) == input-email-valid.html input-email-ref.html
== input-url-invalid-changed.html input-withtext-ref.html
== input-url-invalid-default.html input-withtext-ref.html
== input-url-valid.html input-url-ref.html
== input-pattern-valid.html input-withtext-ref.html
== input-pattern-invalid-default.html input-withtext-ref.html
== input-pattern-invalid-changed.html input-withtext-ref.html
fuzzy(0-2,0-5) == input-type-barred.html input-button-ref.html
fuzzy(0-64,0-4) == input-type-invalid.html input-ref.html
== input-disabled-fieldset-1.html input-fieldset-ref.html
fuzzy(0-1,0-3) == input-disabled-fieldset-2.html input-fieldset-ref.html
fuzzy(0-1,0-3) == input-fieldset-legend.html input-fieldset-legend-ref.html
== input-checkbox-required-invalid-changed.html success-ref.html
== input-checkbox-required-invalid-default.html success-ref.html
== input-radio-required-invalid-changed.html success-ref.html
== input-radio-required-invalid-default.html success-ref.html
== input-file-required-invalid-changed.html input-file-ref.html
== input-file-required-invalid-default.html input-file-ref.html
== input-radio-required.html success-ref.html
== input-radio-customerror.html success-ref.html
== input-radio-dyn-valid-1.html success-ref.html
== input-radio-dyn-valid-2.html success-ref.html
== input-radio-nogroup-required-valid.html success-ref.html
== input-radio-nogroup-required-invalid.html success-ref.html
# input type='hidden' shouldn't show

Просмотреть файл

@ -1,17 +1,12 @@
needs-focus fuzzy-if(geckoview,0-8,0-1) == select-valid.html select-ref.html
fuzzy(0-1,0-3) needs-focus == select-invalid.html select-ref.html
fuzzy(0-2,0-5) needs-focus == select-invalid-reset.html select-required-ref.html
needs-focus == select-disabled.html select-disabled-ref.html
needs-focus == select-dyn-disabled.html select-disabled-ref.html
fuzzy(0-1,0-3) needs-focus == select-dyn-not-disabled.html select-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-invalid-1.html select-required-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-invalid-2.html select-required-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-invalid-changed-1.html select-required-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-invalid-changed-2.html select-required-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-valid.html select-required-ref.html
needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html
fuzzy(0-1,0-1000) needs-focus == select-required-multiple-invalid-changed.html select-required-multiple-ref.html
needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
fuzzy-if(!Android,0-2,0-10) fuzzy-if(Android,0-9,0-1) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html
fuzzy-if(!Android,0-2,0-10) fuzzy-if(Android,0-9,0-1) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html
fuzzy(0-2,0-10) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if select is not disabled and invalid, it is candidate for
constraint validation and should be affected
by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<script>
function onLoadHandler()
{
var e = document.getElementById('s');
e.setCustomValidity('foo');
e.removeAttribute('disabled');
document.documentElement.className='';
}
</script>
<body onload="onLoadHandler();">
<select class='invalid' id='s' disabled></select>
</body>
</html>

Просмотреть файл

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<fieldset>
<legend>
<select style="background-color: green;"></select>
</legend>
</fieldset>
</body>
</html>

Просмотреть файл

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if select has a disabled fieldset ancestor, but is in the first
legend, it is not barred from constraint validation and should be
affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<script>
function onLoadHandler()
{
var e = document.getElementById('b');
e.setCustomValidity('foo');
document.documentElement.className='';
}
</script>
<body onload="onLoadHandler();">
<fieldset disabled>
<legend>
<select class='invalid' id='b'></select>
</legend>
</fieldset>
</body>
</html>

Просмотреть файл

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if select has a custom error, it should be affected by :-moz-ui-invalid
pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('s').setCustomValidity('foo');
document.documentElement.className='';">
<select class='invalid' id='s'></select>
</body>
</html>

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if select is required and the selected option has an empty
string value and the selection did changed,
:-moz-ui-invalid should apply. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('s').selectedIndex = 0;
document.documentElement.className = '';">
<select id='s' class='invalid' required>
<option selected value="">foo</option>
</select>
</body>
</html>

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if select is required and the selected option has an empty
string value and the selection did changed,
:-moz-ui-invalid should apply. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('s').selectedIndex = 0;
document.documentElement.className = '';">
<select id='s' class='invalid' required>
<option value="">foo</option>
</select>
</body>
</html>

Просмотреть файл

@ -1,14 +1,10 @@
== textarea-valid.html textarea-ref.html
== textarea-customerror.html textarea-ref.html
== textarea-disabled.html textarea-ref.html
== textarea-dyn-disabled.html textarea-ref.html
== textarea-dyn-not-disabled.html textarea-ref.html
== textarea-readonly.html textarea-ref.html
== textarea-dyn-readonly.html textarea-ref.html
== textarea-dyn-not-readonly-not-changed.html textarea-ref.html
== textarea-dyn-not-readonly-changed.html textarea-ref.html
== textarea-required-valid.html textarea-withtext-ref.html
== textarea-required-invalid.html textarea-ref.html
== textarea-required-invalid-changed.html textarea-ref.html
== textarea-disabled-fieldset-1.html textarea-fieldset-ref.html
== textarea-disabled-fieldset-2.html textarea-fieldset-ref.html

Просмотреть файл

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<script>
function doTest() {
document.getElementById('t').setCustomValidity('foo');
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
</head>
<!-- Test: if textarea has a custom error, it should be affected by :-moz-ui-invalid
pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body>
<textarea class='invalid' id='t'></textarea>
</body>
</html>

Просмотреть файл

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if textarea is not disabled and invalid, it is candidate for
constraint validation and should be affected
by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<script>
function doTest()
{
var e = document.getElementById('t');
e.setCustomValidity('foo');
e.removeAttribute('disabled');
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
<body>
<textarea class='invalid' id='t' disabled></textarea>
</body>
</html>

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<script>
function doTest() {
document.getElementById('t').removeAttribute('readonly');
document.getElementById('t').value = '';
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
</head>
<!-- Test: if textarea is no longer readonly and has it's value changed,
it's affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body>
<textarea class='invalid' id='t' readonly required></textarea>
</body>
</html>

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<script>
function doTest() {
document.getElementById('t').value = '';
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
</head>
<!-- Test: if textarea isn't valid and it's value has been changed,
it should be affected by :-moz-ui-invalid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body>
<textarea id='t' class='invalid' required></textarea>
</body>
</html>

Просмотреть файл

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if input is valid and its checkedness has changed,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').checked = false;
if (!document.getElementById('i').matches(':-moz-ui-valid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i' type='checkbox'>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if input is not disabled and its value has been changed,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').removeAttribute('disabled');
document.getElementById('i').value = '';
document.documentElement.className='';">
<input class='valid' id='i' disabled>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<!-- Test: if input is no longer readonly and its value has been changed,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').removeAttribute('readonly');
document.getElementById('i').value = '';
document.documentElement.className='';">
<input class='valid' id='i' readonly>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input is valid and its value has been changed,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value = 'foo@bar.com';
document.documentElement.className = '';">
<input id='i' class='valid' type='email'>
</body>
</html>

Просмотреть файл

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input is valid and its default value has been changed,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value='';
document.documentElement.className='';">
<input id='i' class='valid' type='file'>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input is valid and its value has been changed,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value = 'foo';
document.documentElement.className = '';">
<input id='i' class='valid' pattern='foo'>
</body>
</html>

Просмотреть файл

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i1').checked = false;
document.getElementById('i1').setCustomValidity('foo');
if (document.getElementById('i1').matches(':-moz-ui-valid') ||
!document.getElementById('i2').matches(':-moz-ui-valid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i1' name='foo' type='radio'>
<input id='i2' name='foo' type='radio'>
</body>
</html>

Просмотреть файл

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i1').checked = true;
if (!document.getElementById('i1').matches(':-moz-ui-valid') ||
!document.getElementById('i2').matches(':-moz-ui-valid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i1' name='foo' type='radio' required>
<input id='i2' name='foo' type='radio'>
</body>
</html>

Просмотреть файл

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i1').checked = true;
document.getElementById('i1').required = false;
if (!document.getElementById('i1').matches(':-moz-ui-valid') ||
!document.getElementById('i2').matches(':-moz-ui-valid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i1' name='foo' type='radio' required>
<input id='i2' name='foo' type='radio'>
</body>
</html>

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').checked = true;
if (!document.getElementById('i').matches(':-moz-ui-valid')) {
document.body.textContent='FAIL';
} else {
document.body.textContent='SUCCESS';
}
document.documentElement.className='';">
<input id='i' type='radio' required>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input is valid and its value has been changed,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value = 'foo';
document.documentElement.className = '';">
<input id='i' class='valid' required>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if input is valid and its value has been changed,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('i').value = 'http://mozilla.org/';
document.documentElement.className = '';">
<input id='i' class='valid' type='url'>
</body>
</html>

Просмотреть файл

@ -3,38 +3,26 @@ fuzzy(0-11,0-4) == input-customerror.html input-ref.html
== input-disabled.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-disabled.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-not-disabled.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-not-disabled-changed.html input-ref.html
fuzzy(0-1,0-3) == input-readonly.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-readonly.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-not-readonly.html input-ref.html
fuzzy(0-1,0-3) == input-dyn-not-readonly-changed.html input-ref.html
== input-required-valid.html input-withtext-ref.html
== input-required-valid-changed.html input-withtext-ref.html
fuzzy(0-1,0-3) == input-required-invalid.html input-ref.html
== input-button.html input-button-ref.html
== input-reset.html input-button-ref.html
== input-email-invalid.html input-withtext-ref.html
== input-email-valid.html input-email-ref.html
== input-email-valid-changed.html input-email-ref.html
== input-url-invalid.html input-withtext-ref.html
== input-url-valid.html input-url-ref.html
== input-url-valid-changed.html input-url-ref.html
== input-pattern-valid.html input-withtext-ref.html
== input-pattern-valid-changed.html input-withtext-ref.html
== input-pattern-invalid.html input-withtext-ref.html
== input-type-barred.html input-button-ref.html
fuzzy(0-64,0-4) == input-type-invalid.html input-ref.html
== input-disabled-fieldset-1.html input-fieldset-ref.html
fuzzy(0-1,0-3) == input-disabled-fieldset-2.html input-fieldset-ref.html
fuzzy(0-1,0-3) == input-fieldset-legend.html input-fieldset-legend-ref.html
== input-checkbox-valid-changed.html success-ref.html
== input-checkbox-valid-default.html success-ref.html
== input-file-valid-changed.html input-file-ref.html
== input-file-valid-default.html input-file-ref.html
== input-radio-required.html success-ref.html
== input-radio-customerror.html success-ref.html
== input-radio-dyn-valid-1.html success-ref.html
== input-radio-dyn-valid-2.html success-ref.html
== input-radio-nogroup-required-valid.html success-ref.html
== input-radio-nogroup-required-invalid.html success-ref.html
# input type='hidden' shouldn't show

Просмотреть файл

@ -7,11 +7,8 @@ fuzzy(0-1,0-3) needs-focus == select-dyn-not-disabled.html select-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-invalid.html select-required-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-valid-1.html select-required-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-valid-2.html select-required-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-valid-changed-1.html select-required-ref.html
fuzzy(0-2,0-5) needs-focus == select-required-valid-changed-2.html select-required-ref.html
needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html
needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html
fuzzy(0-1,0-1000) needs-focus == select-required-multiple-valid-changed.html select-required-multiple-ref.html
fuzzy-if(Android,0-9,0-1) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html
fuzzy-if(!Android,0-2,0-10) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html
fuzzy(0-2,0-10) needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html

Просмотреть файл

@ -1,24 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<head>
<script>
function doTest() {
document.getElementById('s').options[0].selected = false;
document.getElementById('s').options[1].selected = false;
document.getElementById('s').options[0].selected = true;
document.getElementById('s').options[1].selected = true;
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
</head>
<!-- Test: if select is required and has at least one option selected and the
selection did changed, :-moz-ui-valid should not apply. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body>
<select id='s' class='valid' required multiple>
<option selected></option>
<option selected>foo</option>
</select>
</body>
</html>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if select is required and has a selected option and the selection
did changed, :-moz-ui-valid should apply. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('s').selectedIndex = 0;
document.documentElement.className = '';">
<select id='s' class='valid' required>
<option>foo</option>
</select>
</body>
</html>

Просмотреть файл

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html class='reftest-wait'>
<!-- Test: if select is required and has a selected option and the selection
did changed, :-moz-ui-valid should apply. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('s').selectedIndex = 0;
document.documentElement.className = '';">
<select id='s' class='valid' required>
<option selected>foo</option>
</select>
</body>
</html>

Просмотреть файл

@ -3,13 +3,10 @@
== textarea-disabled.html textarea-ref.html
== textarea-dyn-disabled.html textarea-ref.html
== textarea-dyn-not-disabled.html textarea-ref.html
== textarea-dyn-not-disabled-changed.html textarea-ref.html
== textarea-readonly.html textarea-ref.html
== textarea-dyn-readonly.html textarea-ref.html
== textarea-dyn-not-readonly.html textarea-ref.html
== textarea-dyn-not-readonly-changed.html textarea-ref.html
== textarea-required-valid.html textarea-withtext-ref.html
== textarea-required-valid-changed.html textarea-withtext-ref.html
== textarea-required-invalid.html textarea-ref.html
== textarea-disabled-fieldset-1.html textarea-fieldset-ref.html
== textarea-disabled-fieldset-2.html textarea-fieldset-ref.html

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<script>
function doTest() {
document.getElementById('t').removeAttribute('disabled');
document.getElementById('t').value = '';
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
</head>
<!-- Test: if textarea is not disabled and its value has been modifie,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body>
<textarea class='valid' id='t' disabled></textarea>
</body>
</html>

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<script>
function doTest() {
document.getElementById('t').removeAttribute('readonly');
document.getElementById('t').value = '';
document.documentElement.className='';
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
</head>
<!-- Test: if textarea is no longer readonly and its value has been modified,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body>
<textarea class='valid' id='t' readonly></textarea>
</body>
</html>

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html class='reftet-wait'>
<!-- Test: if textarea is valid and its value has been modified,
it should be affected by :-moz-ui-valid pseudo-class. -->
<link rel='stylesheet' type='text/css' href='style.css'>
<body onload="document.getElementById('t').value = 'foo';
document.documentElement.className = '';">
<textarea id='t' class='valid' required></textarea>
</body>
</html>

Просмотреть файл

@ -1,13 +0,0 @@
[user-invalid.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[:user-invalid selector properly interacts with submit & reset buttons]
expected: FAIL
[required-input: A required input or textarea should match :user-invalid if a user types into it and then clears it before blurring.]
expected:
if os == "android": PASS
FAIL
[:user-invalid selector should respond to user action]
expected: FAIL

Просмотреть файл

@ -1,8 +0,0 @@
[user-valid.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[:user-valid selector properly interacts with submit & reset buttons]
expected: FAIL
[:user-valid selector should respond to user action]
expected: FAIL

Просмотреть файл

@ -249,20 +249,12 @@ SelectContentHelper.prototype = {
);
// Fire input and change events when selected option changes
if (this.initialSelection !== selectedOption) {
let inputEvent = new win.Event("input", {
bubbles: true,
composed: true,
});
let changeEvent = new win.Event("change", {
bubbles: true,
});
{
let handlingUserInput = win.windowUtils.setHandlingUserInput(true);
try {
element.dispatchEvent(inputEvent);
element.dispatchEvent(changeEvent);
element.userFinishedInteracting(
this.initialSelection !== selectedOption
);
} finally {
handlingUserInput.destruct();
}