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:
@@ -69,7 +69,7 @@ class HTMLButtonElement final : public nsGenericHTMLFormControlElementWithState,
|
|||||||
void DoneCreatingElement() override;
|
void DoneCreatingElement() override;
|
||||||
|
|
||||||
void UpdateBarredFromConstraintValidation();
|
void UpdateBarredFromConstraintValidation();
|
||||||
void UpdateValidityElementStates(bool aNotify) final;
|
void UpdateValidityElementStates(bool aNotify);
|
||||||
/**
|
/**
|
||||||
* Called when an attribute is about to be changed
|
* Called when an attribute is about to be changed
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class HTMLElement final : public nsGenericHTMLFormElement {
|
|||||||
void AfterClearForm(bool aUnbindOrDelete) override;
|
void AfterClearForm(bool aUnbindOrDelete) override;
|
||||||
void FieldSetDisabledChanged(bool aNotify) override;
|
void FieldSetDisabledChanged(bool aNotify) override;
|
||||||
void SaveState() override;
|
void SaveState() override;
|
||||||
void UpdateValidityElementStates(bool aNotify) final;
|
void UpdateValidityElementStates(bool aNotify);
|
||||||
|
|
||||||
void UpdateFormOwner();
|
void UpdateFormOwner();
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ HTMLFormElement::HTMLFormElement(
|
|||||||
mDeferSubmission(false),
|
mDeferSubmission(false),
|
||||||
mNotifiedObservers(false),
|
mNotifiedObservers(false),
|
||||||
mNotifiedObserversResult(false),
|
mNotifiedObserversResult(false),
|
||||||
mEverTriedInvalidSubmit(false),
|
|
||||||
mIsConstructingEntryList(false),
|
mIsConstructingEntryList(false),
|
||||||
mIsFiringSubmissionEvents(false) {
|
mIsFiringSubmissionEvents(false) {
|
||||||
// We start out valid.
|
// We start out valid.
|
||||||
@@ -261,16 +260,28 @@ void HTMLFormElement::MaybeSubmit(Element* aSubmitter) {
|
|||||||
return;
|
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) {
|
if (mIsFiringSubmissionEvents) {
|
||||||
return;
|
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);
|
AutoRestore<bool> resetFiringSubmissionEventsFlag(mIsFiringSubmissionEvents);
|
||||||
mIsFiringSubmissionEvents = true;
|
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.
|
// interactively validate the constraints of form and examine the result.
|
||||||
// If the result is negative (i.e., the constraint validation concluded
|
// If the result is negative (i.e., the constraint validation concluded
|
||||||
// that there were invalid fields and probably informed the user of this)
|
// that there were invalid fields and probably informed the user of this)
|
||||||
@@ -635,7 +646,6 @@ nsresult HTMLFormElement::DoReset() {
|
|||||||
doc->FlushPendingNotifications(FlushType::ContentAndNotify);
|
doc->FlushPendingNotifications(FlushType::ContentAndNotify);
|
||||||
}
|
}
|
||||||
|
|
||||||
mEverTriedInvalidSubmit = false;
|
|
||||||
// JBK walk the elements[] array instead of form frame controls - bug 34297
|
// JBK walk the elements[] array instead of form frame controls - bug 34297
|
||||||
uint32_t numElements = mControls->Length();
|
uint32_t numElements = mControls->Length();
|
||||||
for (uint32_t elementX = 0; elementX < numElements; ++elementX) {
|
for (uint32_t elementX = 0; elementX < numElements; ++elementX) {
|
||||||
@@ -1051,15 +1061,11 @@ nsresult HTMLFormElement::ConstructEntryList(FormData* aFormData) {
|
|||||||
nsresult rv = mControls->GetSortedControls(sortedControls);
|
nsresult rv = mControls->GetSortedControls(sortedControls);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
uint32_t len = sortedControls.Length();
|
|
||||||
|
|
||||||
//
|
|
||||||
// Walk the list of nodes and call SubmitNamesValues() on the controls
|
// Walk the list of nodes and call SubmitNamesValues() on the controls
|
||||||
//
|
for (nsGenericHTMLFormElement* control : sortedControls) {
|
||||||
for (uint32_t i = 0; i < len; ++i) {
|
|
||||||
// Disabled elements don't submit
|
// Disabled elements don't submit
|
||||||
if (!sortedControls[i]->IsDisabled()) {
|
if (!control->IsDisabled()) {
|
||||||
nsCOMPtr<nsIFormControl> fc = do_QueryInterface(sortedControls[i]);
|
nsCOMPtr<nsIFormControl> fc = do_QueryInterface(control);
|
||||||
MOZ_ASSERT(fc);
|
MOZ_ASSERT(fc);
|
||||||
// Tell the control to submit its name/value pairs to the submission
|
// Tell the control to submit its name/value pairs to the submission
|
||||||
fc->SubmitNamesValues(aFormData);
|
fc->SubmitNamesValues(aFormData);
|
||||||
@@ -1768,44 +1774,6 @@ bool HTMLFormElement::CheckValidFormSubmission() {
|
|||||||
return true;
|
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;
|
AutoJSAPI jsapi;
|
||||||
if (!jsapi.Init(GetOwnerGlobal())) {
|
if (!jsapi.Init(GetOwnerGlobal())) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -233,16 +233,7 @@ class HTMLFormElement final : public nsGenericHTMLElement,
|
|||||||
* @param aFormData the form data object
|
* @param aFormData the form data object
|
||||||
*/
|
*/
|
||||||
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
|
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
|
||||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult ConstructEntryList(FormData* aFormData);
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult ConstructEntryList(FormData*);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements form[name]. Returns form controls in this form with the correct
|
* 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);
|
RefPtr<HTMLInputElement> inputElement(mInputElement);
|
||||||
nsresult rv = nsContentUtils::DispatchInputEvent(inputElement);
|
nsresult rv = nsContentUtils::DispatchInputEvent(inputElement);
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch input event");
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch input event");
|
||||||
|
mInputElement->SetUserInteracted(true);
|
||||||
rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),
|
rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),
|
||||||
mInputElement, u"change"_ns,
|
mInputElement, u"change"_ns,
|
||||||
CanBubble::eYes, Cancelable::eNo);
|
CanBubble::eYes, Cancelable::eNo);
|
||||||
@@ -667,6 +667,7 @@ nsColorPickerShownCallback::Done(const nsAString& aColor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mValueChanged) {
|
if (mValueChanged) {
|
||||||
|
mInput->SetUserInteracted(true);
|
||||||
rv = nsContentUtils::DispatchTrustedEvent(
|
rv = nsContentUtils::DispatchTrustedEvent(
|
||||||
mInput->OwnerDoc(), static_cast<Element*>(mInput.get()), u"change"_ns,
|
mInput->OwnerDoc(), static_cast<Element*>(mInput.get()), u"change"_ns,
|
||||||
CanBubble::eYes, Cancelable::eNo);
|
CanBubble::eYes, Cancelable::eNo);
|
||||||
@@ -995,6 +996,7 @@ HTMLInputElement::HTMLInputElement(already_AddRefed<dom::NodeInfo>&& aNodeInfo,
|
|||||||
mAutocompleteInfoState(nsContentUtils::eAutocompleteAttrState_Unknown),
|
mAutocompleteInfoState(nsContentUtils::eAutocompleteAttrState_Unknown),
|
||||||
mDisabledChanged(false),
|
mDisabledChanged(false),
|
||||||
mValueChanged(false),
|
mValueChanged(false),
|
||||||
|
mUserInteracted(false),
|
||||||
mLastValueChangeWasInteractive(false),
|
mLastValueChangeWasInteractive(false),
|
||||||
mCheckedChanged(false),
|
mCheckedChanged(false),
|
||||||
mChecked(false),
|
mChecked(false),
|
||||||
@@ -1006,8 +1008,6 @@ HTMLInputElement::HTMLInputElement(already_AddRefed<dom::NodeInfo>&& aNodeInfo,
|
|||||||
mCheckedIsToggled(false),
|
mCheckedIsToggled(false),
|
||||||
mIndeterminate(false),
|
mIndeterminate(false),
|
||||||
mInhibitRestoration(aFromParser & FROM_PARSER_FRAGMENT),
|
mInhibitRestoration(aFromParser & FROM_PARSER_FRAGMENT),
|
||||||
mCanShowValidUI(true),
|
|
||||||
mCanShowInvalidUI(true),
|
|
||||||
mHasRange(false),
|
mHasRange(false),
|
||||||
mIsDraggingRange(false),
|
mIsDraggingRange(false),
|
||||||
mNumberControlSpinnerIsSpinning(false),
|
mNumberControlSpinnerIsSpinning(false),
|
||||||
@@ -2613,15 +2613,25 @@ void HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HTMLInputElement::FireChangeEventIfNeeded() {
|
void HTMLInputElement::FireChangeEventIfNeeded() {
|
||||||
|
if (!MayFireChangeOnBlur()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We're not exposing the GetValue return value anywhere here, so it's safe to
|
// We're not exposing the GetValue return value anywhere here, so it's safe to
|
||||||
// claim to be a system caller.
|
// claim to be a system caller.
|
||||||
nsAutoString value;
|
nsAutoString value;
|
||||||
GetValue(value, CallerType::System);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch the change event.
|
// Dispatch the change event.
|
||||||
mFocusedValue = value;
|
mFocusedValue = value;
|
||||||
nsContentUtils::DispatchTrustedEvent(
|
nsContentUtils::DispatchTrustedEvent(
|
||||||
@@ -3146,9 +3156,9 @@ bool HTMLInputElement::CheckActivationBehaviorPreconditions(
|
|||||||
// we're a DOMActivate dispatched from click handling, it will not be set.
|
// we're a DOMActivate dispatched from click handling, it will not be set.
|
||||||
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
||||||
bool outerActivateEvent =
|
bool outerActivateEvent =
|
||||||
((mouseEvent && mouseEvent->IsLeftClickEvent()) ||
|
(mouseEvent && mouseEvent->IsLeftClickEvent()) ||
|
||||||
(aVisitor.mEvent->mMessage == eLegacyDOMActivate &&
|
(aVisitor.mEvent->mMessage == eLegacyDOMActivate &&
|
||||||
!mInInternalActivate));
|
!mInInternalActivate);
|
||||||
if (outerActivateEvent) {
|
if (outerActivateEvent) {
|
||||||
aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
|
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
|
// the user. (IsValid() can return false if the 'required' attribute is
|
||||||
// set and the value is the empty string.)
|
// set and the value is the empty string.)
|
||||||
if (!IsValueEmpty()) {
|
if (!IsValueEmpty()) {
|
||||||
// We pass 'true' for UpdateValidityUIBits' aIsFocused argument
|
// We pass 'true' for SetUserInteracted because we need the UI to update
|
||||||
// regardless because we need the UI to update _now_ or the user will
|
// _now_ or the user will wonder why the step behavior isn't functioning.
|
||||||
// wonder why the step behavior isn't functioning.
|
SetUserInteracted(true);
|
||||||
UpdateValidityUIBits(true);
|
|
||||||
UpdateValidityElementStates(true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3664,8 +3672,6 @@ static bool ActivatesWithKeyboard(FormControlType aType, uint32_t aKeyCode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
||||||
if (aVisitor.mEvent->mMessage == eFocus ||
|
|
||||||
aVisitor.mEvent->mMessage == eBlur) {
|
|
||||||
if (aVisitor.mEvent->mMessage == eBlur) {
|
if (aVisitor.mEvent->mMessage == eBlur) {
|
||||||
if (mIsDraggingRange) {
|
if (mIsDraggingRange) {
|
||||||
FinishRangeThumbDrag();
|
FinishRangeThumbDrag();
|
||||||
@@ -3674,10 +3680,6 @@ nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateValidityUIBits(aVisitor.mEvent->mMessage == eFocus);
|
|
||||||
UpdateValidityElementStates(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
auto oldType = FormControlType(NS_CONTROL_TYPE(aVisitor.mItemFlags));
|
auto oldType = FormControlType(NS_CONTROL_TYPE(aVisitor.mItemFlags));
|
||||||
|
|
||||||
@@ -4076,11 +4078,14 @@ void HTMLInputElement::ActivationBehavior(EventChainPostVisitor& aVisitor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mCheckedIsToggled) {
|
if (mCheckedIsToggled) {
|
||||||
|
SetUserInteracted(true);
|
||||||
|
|
||||||
// Fire input event and then change event.
|
// Fire input event and then change event.
|
||||||
DebugOnly<nsresult> rvIgnored = nsContentUtils::DispatchInputEvent(this);
|
DebugOnly<nsresult> rvIgnored = nsContentUtils::DispatchInputEvent(this);
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||||
"Failed to dispatch input event");
|
"Failed to dispatch input event");
|
||||||
|
|
||||||
|
// FIXME: Why is this different than every other change event?
|
||||||
nsContentUtils::DispatchTrustedEvent<WidgetEvent>(
|
nsContentUtils::DispatchTrustedEvent<WidgetEvent>(
|
||||||
OwnerDoc(), static_cast<Element*>(this), eFormChange, CanBubble::eYes,
|
OwnerDoc(), static_cast<Element*>(this), eFormChange, CanBubble::eYes,
|
||||||
Cancelable::eNo);
|
Cancelable::eNo);
|
||||||
@@ -4094,8 +4099,7 @@ void HTMLInputElement::ActivationBehavior(EventChainPostVisitor& aVisitor) {
|
|||||||
FireEventForAccessibility(this, eFormRadioStateChange);
|
FireEventForAccessibility(this, eFormRadioStateChange);
|
||||||
// Fire event for the previous selected radio.
|
// Fire event for the previous selected radio.
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aVisitor.mItemData);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aVisitor.mItemData);
|
||||||
if (HTMLInputElement* previous =
|
if (auto* previous = HTMLInputElement::FromNodeOrNull(content)) {
|
||||||
HTMLInputElement::FromNodeOrNull(content)) {
|
|
||||||
FireEventForAccessibility(previous, eFormRadioStateChange);
|
FireEventForAccessibility(previous, eFormRadioStateChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5927,6 +5931,7 @@ HTMLInputElement::Reset() {
|
|||||||
SetCheckedChanged(false);
|
SetCheckedChanged(false);
|
||||||
SetValueChanged(false);
|
SetValueChanged(false);
|
||||||
SetLastValueChangeWasInteractive(false);
|
SetLastValueChangeWasInteractive(false);
|
||||||
|
SetUserInteracted(false);
|
||||||
|
|
||||||
switch (GetValueMode()) {
|
switch (GetValueMode()) {
|
||||||
case VALUE_MODE_VALUE: {
|
case VALUE_MODE_VALUE: {
|
||||||
@@ -6222,25 +6227,15 @@ void HTMLInputElement::UpdateValidityElementStates(bool aNotify) {
|
|||||||
ElementState state;
|
ElementState state;
|
||||||
if (IsValid()) {
|
if (IsValid()) {
|
||||||
state |= ElementState::VALID;
|
state |= ElementState::VALID;
|
||||||
|
if (mUserInteracted) {
|
||||||
|
state |= ElementState::USER_VALID;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
state |= ElementState::INVALID;
|
state |= ElementState::INVALID;
|
||||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
if (mUserInteracted) {
|
||||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
|
||||||
state |= ElementState::USER_INVALID;
|
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);
|
AddStatesSilently(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7251,19 +7246,12 @@ Decimal HTMLInputElement::GetDefaultStep() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLInputElement::UpdateValidityUIBits(bool aIsFocused) {
|
void HTMLInputElement::SetUserInteracted(bool aInteracted) {
|
||||||
if (aIsFocused) {
|
if (mUserInteracted == aInteracted) {
|
||||||
// If the invalid UI is shown, we should show it while focusing (and
|
return;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
mUserInteracted = aInteracted;
|
||||||
|
UpdateValidityElementStates(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLInputElement::UpdateInRange(bool aNotify) {
|
void HTMLInputElement::UpdateInRange(bool aNotify) {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/Variant.h"
|
#include "mozilla/Variant.h"
|
||||||
#include "mozilla/dom/BindingDeclarations.h"
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
#include "mozilla/dom/HTMLFormElement.h" // for HasEverTriedInvalidSubmit()
|
|
||||||
#include "mozilla/dom/HTMLInputElementBinding.h"
|
#include "mozilla/dom/HTMLInputElementBinding.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/UnionTypes.h"
|
#include "mozilla/dom/UnionTypes.h"
|
||||||
@@ -36,6 +35,7 @@
|
|||||||
#include "nsIContentPrefService2.h"
|
#include "nsIContentPrefService2.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
|
||||||
|
class nsIEditor;
|
||||||
class nsIRadioVisitor;
|
class nsIRadioVisitor;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
@@ -338,7 +338,7 @@ class HTMLInputElement final : public TextControlElement,
|
|||||||
// as needed. aNotify controls whether the element state update
|
// as needed. aNotify controls whether the element state update
|
||||||
// needs to notify.
|
// needs to notify.
|
||||||
void UpdateAllValidityStates(bool aNotify);
|
void UpdateAllValidityStates(bool aNotify);
|
||||||
void UpdateValidityElementStates(bool aNotify) final;
|
void UpdateValidityElementStates(bool aNotify);
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
void MaybeUpdateAllValidityStates(bool aNotify) {
|
void MaybeUpdateAllValidityStates(bool aNotify) {
|
||||||
// If you need to add new type which supports validationMessage, you should
|
// 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);
|
void SetFilePickerFiltersFromAccept(nsIFilePicker* filePicker);
|
||||||
|
|
||||||
/**
|
void SetUserInteracted(bool) final;
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires change event if mFocusedValue and current value held are unequal and
|
* 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,
|
void SetAutoDirectionality(bool aNotify,
|
||||||
const nsAString* aKnownValue = nullptr);
|
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
|
* Returns the radio group container within the DOM tree that the element
|
||||||
* is currently a member of, if one exists.
|
* 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
|
// https://html.spec.whatwg.org/#concept-fe-dirty
|
||||||
// TODO: Maybe rename to match the spec?
|
// TODO: Maybe rename to match the spec?
|
||||||
bool mValueChanged : 1;
|
bool mValueChanged : 1;
|
||||||
|
// https://html.spec.whatwg.org/#user-interacted
|
||||||
|
bool mUserInteracted : 1;
|
||||||
bool mLastValueChangeWasInteractive : 1;
|
bool mLastValueChangeWasInteractive : 1;
|
||||||
bool mCheckedChanged : 1;
|
bool mCheckedChanged : 1;
|
||||||
bool mChecked : 1;
|
bool mChecked : 1;
|
||||||
@@ -1561,8 +1523,6 @@ class HTMLInputElement final : public TextControlElement,
|
|||||||
bool mCheckedIsToggled : 1;
|
bool mCheckedIsToggled : 1;
|
||||||
bool mIndeterminate : 1;
|
bool mIndeterminate : 1;
|
||||||
bool mInhibitRestoration : 1;
|
bool mInhibitRestoration : 1;
|
||||||
bool mCanShowValidUI : 1;
|
|
||||||
bool mCanShowInvalidUI : 1;
|
|
||||||
bool mHasRange : 1;
|
bool mHasRange : 1;
|
||||||
bool mIsDraggingRange : 1;
|
bool mIsDraggingRange : 1;
|
||||||
bool mNumberControlSpinnerIsSpinning : 1;
|
bool mNumberControlSpinnerIsSpinning : 1;
|
||||||
|
|||||||
@@ -119,10 +119,8 @@ HTMLSelectElement::HTMLSelectElement(
|
|||||||
mDisabledChanged(false),
|
mDisabledChanged(false),
|
||||||
mMutating(false),
|
mMutating(false),
|
||||||
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
|
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
|
||||||
mSelectionHasChanged(false),
|
mUserInteracted(false),
|
||||||
mDefaultSelectionSet(false),
|
mDefaultSelectionSet(false),
|
||||||
mCanShowInvalidUI(true),
|
|
||||||
mCanShowValidUI(true),
|
|
||||||
mIsOpenInParentProcess(false),
|
mIsOpenInParentProcess(false),
|
||||||
mNonOptionChildren(0),
|
mNonOptionChildren(0),
|
||||||
mOptGroupCount(0),
|
mOptGroupCount(0),
|
||||||
@@ -282,7 +280,7 @@ void HTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,
|
|||||||
// Fix the currently selected index
|
// Fix the currently selected index
|
||||||
if (aListIndex <= mSelectedIndex) {
|
if (aListIndex <= mSelectedIndex) {
|
||||||
mSelectedIndex += (insertIndex - aListIndex);
|
mSelectedIndex += (insertIndex - aListIndex);
|
||||||
SetSelectionChanged(true, aNotify);
|
OnSelectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the frame stuff for notification. No need to flush here
|
// 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 this is a Combobox, no other Item will be selected.
|
||||||
if (IsCombobox()) {
|
if (IsCombobox()) {
|
||||||
mSelectedIndex = -1;
|
mSelectedIndex = -1;
|
||||||
SetSelectionChanged(true, aNotify);
|
OnSelectionChanged();
|
||||||
} else {
|
} else {
|
||||||
FindSelectedIndex(aListIndex, aNotify);
|
FindSelectedIndex(aListIndex, aNotify);
|
||||||
}
|
}
|
||||||
@@ -390,7 +388,7 @@ nsresult HTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
|
|||||||
// Shift the selected index if something in front of it was removed
|
// Shift the selected index if something in front of it was removed
|
||||||
// aListIndex+numRemoved <= mSelectedIndex
|
// aListIndex+numRemoved <= mSelectedIndex
|
||||||
mSelectedIndex -= numRemoved;
|
mSelectedIndex -= numRemoved;
|
||||||
SetSelectionChanged(true, aNotify);
|
OnSelectionChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,7 +699,7 @@ void HTMLSelectElement::SetSelectedIndexInternal(int32_t aIndex, bool aNotify) {
|
|||||||
selectFrame->OnSetSelectedIndex(oldSelectedIndex, mSelectedIndex);
|
selectFrame->OnSetSelectedIndex(oldSelectedIndex, mSelectedIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSelectionChanged(true, aNotify);
|
OnSelectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTMLSelectElement::IsOptionSelectedByIndex(int32_t aIndex) const {
|
bool HTMLSelectElement::IsOptionSelectedByIndex(int32_t aIndex) const {
|
||||||
@@ -716,7 +714,7 @@ void HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
|
|||||||
// Set the selected index
|
// Set the selected index
|
||||||
if (aSelected && (aIndex < mSelectedIndex || mSelectedIndex < 0)) {
|
if (aSelected && (aIndex < mSelectedIndex || mSelectedIndex < 0)) {
|
||||||
mSelectedIndex = aIndex;
|
mSelectedIndex = aIndex;
|
||||||
SetSelectionChanged(true, aNotify);
|
OnSelectionChanged();
|
||||||
} else if (!aSelected && aIndex == mSelectedIndex) {
|
} else if (!aSelected && aIndex == mSelectedIndex) {
|
||||||
FindSelectedIndex(aIndex + 1, aNotify);
|
FindSelectedIndex(aIndex + 1, aNotify);
|
||||||
}
|
}
|
||||||
@@ -741,15 +739,14 @@ void HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
|
|||||||
|
|
||||||
void HTMLSelectElement::FindSelectedIndex(int32_t aStartIndex, bool aNotify) {
|
void HTMLSelectElement::FindSelectedIndex(int32_t aStartIndex, bool aNotify) {
|
||||||
mSelectedIndex = -1;
|
mSelectedIndex = -1;
|
||||||
SetSelectionChanged(true, aNotify);
|
|
||||||
uint32_t len = Length();
|
uint32_t len = Length();
|
||||||
for (int32_t i = aStartIndex; i < int32_t(len); i++) {
|
for (int32_t i = aStartIndex; i < int32_t(len); i++) {
|
||||||
if (IsOptionSelectedByIndex(i)) {
|
if (IsOptionSelectedByIndex(i)) {
|
||||||
mSelectedIndex = i;
|
mSelectedIndex = i;
|
||||||
SetSelectionChanged(true, aNotify);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
OnSelectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX Consider splitting this into two functions for ease of reading:
|
// XXX Consider splitting this into two functions for ease of reading:
|
||||||
@@ -1270,27 +1267,6 @@ void HTMLSelectElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
|||||||
nsGenericHTMLFormControlElementWithState::GetEventTargetParent(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) {
|
void HTMLSelectElement::UpdateValidityElementStates(bool aNotify) {
|
||||||
AutoStateChangeNotifier notifier(*this, aNotify);
|
AutoStateChangeNotifier notifier(*this, aNotify);
|
||||||
RemoveStatesSilently(ElementState::VALIDITY_STATES);
|
RemoveStatesSilently(ElementState::VALIDITY_STATES);
|
||||||
@@ -1301,28 +1277,16 @@ void HTMLSelectElement::UpdateValidityElementStates(bool aNotify) {
|
|||||||
ElementState state;
|
ElementState state;
|
||||||
if (IsValid()) {
|
if (IsValid()) {
|
||||||
state |= ElementState::VALID;
|
state |= ElementState::VALID;
|
||||||
|
if (mUserInteracted) {
|
||||||
|
state |= ElementState::USER_VALID;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
state |= ElementState::INVALID;
|
state |= ElementState::INVALID;
|
||||||
|
if (mUserInteracted) {
|
||||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
|
||||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
|
||||||
state |= ElementState::USER_INVALID;
|
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);
|
AddStatesSilently(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1453,9 +1417,9 @@ HTMLSelectElement::Reset() {
|
|||||||
SelectSomething(true);
|
SelectSomething(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSelectionChanged(false, true);
|
OnSelectionChanged();
|
||||||
|
SetUserInteracted(false);
|
||||||
|
|
||||||
//
|
|
||||||
// Let the frame know we were reset
|
// Let the frame know we were reset
|
||||||
//
|
//
|
||||||
// Don't flush, if there's no frame yet it won't care about us being
|
// 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);
|
UpdateValidityElementStates(aNotify);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify) {
|
void HTMLSelectElement::OnSelectionChanged() {
|
||||||
if (!mDefaultSelectionSet) {
|
if (!mDefaultSelectionSet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateSelectedOptions();
|
UpdateSelectedOptions();
|
||||||
|
|
||||||
bool previousSelectionChangedValue = mSelectionHasChanged;
|
|
||||||
mSelectionHasChanged = aValue;
|
|
||||||
if (mSelectionHasChanged != previousSelectionChangedValue) {
|
|
||||||
UpdateValidityElementStates(aNotify);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLSelectElement::UpdateSelectedOptions() {
|
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) {
|
void HTMLSelectElement::SetPreviewValue(const nsAString& aValue) {
|
||||||
mPreviewValue = aValue;
|
mPreviewValue = aValue;
|
||||||
nsContentUtils::RemoveNewlines(mPreviewValue);
|
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,
|
JSObject* HTMLSelectElement::WrapNode(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) {
|
JS::Handle<JSObject*> aGivenProto) {
|
||||||
return HTMLSelectElement_Binding::Wrap(aCx, this, aGivenProto);
|
return HTMLSelectElement_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
|
|||||||
@@ -128,6 +128,9 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState,
|
|||||||
|
|
||||||
void GetAutocompleteInfo(AutocompleteInfo& aInfo);
|
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); }
|
bool Disabled() const { return GetBoolAttr(nsGkAtoms::disabled); }
|
||||||
void SetDisabled(bool aVal, ErrorResult& aRv) {
|
void SetDisabled(bool aVal, ErrorResult& aRv) {
|
||||||
SetHTMLBoolAttr(nsGkAtoms::disabled, aVal, aRv);
|
SetHTMLBoolAttr(nsGkAtoms::disabled, aVal, aRv);
|
||||||
@@ -194,8 +197,6 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState,
|
|||||||
|
|
||||||
// nsIContent
|
// nsIContent
|
||||||
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
||||||
MOZ_CAN_RUN_SCRIPT
|
|
||||||
nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
|
|
||||||
|
|
||||||
bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||||
int32_t* aTabIndex) override;
|
int32_t* aTabIndex) override;
|
||||||
@@ -300,7 +301,7 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState,
|
|||||||
ValidityStateType aType) override;
|
ValidityStateType aType) override;
|
||||||
|
|
||||||
void UpdateValueMissingValidityState();
|
void UpdateValueMissingValidityState();
|
||||||
void UpdateValidityElementStates(bool aNotify) final;
|
void UpdateValidityElementStates(bool aNotify);
|
||||||
/**
|
/**
|
||||||
* Insert aElement before the node given by aBefore
|
* 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 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
|
* Marks the selectedOptions list as dirty, so that it'll populate itself
|
||||||
@@ -459,25 +460,7 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState,
|
|||||||
*/
|
*/
|
||||||
void UpdateSelectedOptions();
|
void UpdateSelectedOptions();
|
||||||
|
|
||||||
/**
|
void SetUserInteracted(bool) final;
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The options[] array */
|
/** The options[] array */
|
||||||
RefPtr<HTMLOptionsCollection> mOptions;
|
RefPtr<HTMLOptionsCollection> mOptions;
|
||||||
@@ -495,23 +478,10 @@ class HTMLSelectElement final : public nsGenericHTMLFormControlElementWithState,
|
|||||||
* True if DoneAddingChildren will get called but shouldn't restore state.
|
* True if DoneAddingChildren will get called but shouldn't restore state.
|
||||||
*/
|
*/
|
||||||
bool mInhibitStateRestoration : 1;
|
bool mInhibitStateRestoration : 1;
|
||||||
/**
|
/** https://html.spec.whatwg.org/#user-interacted */
|
||||||
* True if the selection has changed since the element's creation.
|
bool mUserInteracted : 1;
|
||||||
*/
|
/** True if the default selected option has been set. */
|
||||||
bool mSelectionHasChanged : 1;
|
|
||||||
/**
|
|
||||||
* True if the default selected option has been set.
|
|
||||||
*/
|
|
||||||
bool mDefaultSelectionSet : 1;
|
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 */
|
/** True if we're open in the parent process */
|
||||||
bool mIsOpenInParentProcess : 1;
|
bool mIsOpenInParentProcess : 1;
|
||||||
|
|
||||||
|
|||||||
@@ -48,15 +48,8 @@ HTMLTextAreaElement::HTMLTextAreaElement(
|
|||||||
FromParser aFromParser)
|
FromParser aFromParser)
|
||||||
: TextControlElement(std::move(aNodeInfo), aFromParser,
|
: TextControlElement(std::move(aNodeInfo), aFromParser,
|
||||||
FormControlType::Textarea),
|
FormControlType::Textarea),
|
||||||
mValueChanged(false),
|
|
||||||
mLastValueChangeWasInteractive(false),
|
|
||||||
mHandlingSelect(false),
|
|
||||||
mDoneAddingChildren(!aFromParser),
|
mDoneAddingChildren(!aFromParser),
|
||||||
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
|
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
|
||||||
mDisabledChanged(false),
|
|
||||||
mCanShowInvalidUI(true),
|
|
||||||
mCanShowValidUI(true),
|
|
||||||
mIsPreviewEnabled(false),
|
|
||||||
mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
|
mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
|
||||||
mState(TextControlState::Construct(this)) {
|
mState(TextControlState::Construct(this)) {
|
||||||
AddMutationObserver(this);
|
AddMutationObserver(this);
|
||||||
@@ -465,6 +458,13 @@ void HTMLTextAreaElement::FireChangeEventIfNeeded() {
|
|||||||
nsString value;
|
nsString value;
|
||||||
GetValueInternal(value, true);
|
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)) {
|
if (mFocusedValue.Equals(value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -480,24 +480,6 @@ nsresult HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
|||||||
mHandlingSelect = false;
|
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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,6 +636,7 @@ nsresult HTMLTextAreaElement::Reset() {
|
|||||||
nsAutoString resetVal;
|
nsAutoString resetVal;
|
||||||
GetDefaultValue(resetVal, IgnoreErrors());
|
GetDefaultValue(resetVal, IgnoreErrors());
|
||||||
SetValueChanged(false);
|
SetValueChanged(false);
|
||||||
|
SetUserInteracted(false);
|
||||||
|
|
||||||
nsresult rv = SetValueInternal(resetVal, ValueSetterOption::ByInternalAPI);
|
nsresult rv = SetValueInternal(resetVal, ValueSetterOption::ByInternalAPI);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
@@ -751,28 +734,15 @@ void HTMLTextAreaElement::UpdateValidityElementStates(bool aNotify) {
|
|||||||
ElementState state;
|
ElementState state;
|
||||||
if (IsValid()) {
|
if (IsValid()) {
|
||||||
state |= ElementState::VALID;
|
state |= ElementState::VALID;
|
||||||
|
if (mUserInteracted) {
|
||||||
|
state |= ElementState::USER_VALID;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
state |= ElementState::INVALID;
|
state |= ElementState::INVALID;
|
||||||
// :-moz-ui-invalid always apply if the element suffers from a custom
|
if (mUserInteracted) {
|
||||||
// error.
|
|
||||||
if (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
|
||||||
(mCanShowInvalidUI && ShouldShowValidityUI())) {
|
|
||||||
state |= ElementState::USER_INVALID;
|
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);
|
AddStatesSilently(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1156,6 +1126,14 @@ bool HTMLTextAreaElement::HasCachedSelection() {
|
|||||||
return mState->IsSelectionCached();
|
return mState->IsSelectionCached();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTMLTextAreaElement::SetUserInteracted(bool aInteracted) {
|
||||||
|
if (mUserInteracted == aInteracted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mUserInteracted = aInteracted;
|
||||||
|
UpdateValidityElementStates(true);
|
||||||
|
}
|
||||||
|
|
||||||
void HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify) {
|
void HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify) {
|
||||||
// This *has* to be called before UpdateBarredFromConstraintValidation and
|
// This *has* to be called before UpdateBarredFromConstraintValidation and
|
||||||
// UpdateValueMissingValidityState because these two functions depend on our
|
// 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;
|
JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
nsCOMPtr<nsIControllers> mControllers;
|
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. */
|
/** 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
|
/** Whether or not the last change to the value was made interactively by the
|
||||||
* user. */
|
* user. */
|
||||||
bool mLastValueChangeWasInteractive;
|
bool mLastValueChangeWasInteractive = false;
|
||||||
/** Whether or not we are already handling select event. */
|
/** 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
|
/** Whether or not we are done adding children (always true if not
|
||||||
created by a parser */
|
created by a parser */
|
||||||
bool mDoneAddingChildren;
|
bool mDoneAddingChildren;
|
||||||
/** Whether state restoration should be inhibited in DoneAddingChildren. */
|
/** Whether state restoration should be inhibited in DoneAddingChildren. */
|
||||||
bool mInhibitStateRestoration;
|
bool mInhibitStateRestoration;
|
||||||
/** Whether our disabled state has changed from the default **/
|
/** Whether our disabled state has changed from the default **/
|
||||||
bool mDisabledChanged;
|
bool mDisabledChanged = false;
|
||||||
/** Whether we should make :-moz-ui-invalid apply on the element. **/
|
bool mIsPreviewEnabled = false;
|
||||||
bool mCanShowInvalidUI;
|
|
||||||
/** Whether we should make :-moz-ui-valid apply on the element. **/
|
|
||||||
bool mCanShowValidUI;
|
|
||||||
bool mIsPreviewEnabled;
|
|
||||||
|
|
||||||
nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
|
nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
|
||||||
|
|
||||||
@@ -350,27 +348,6 @@ class HTMLTextAreaElement final : public TextControlElement,
|
|||||||
void SetDirectionFromValue(bool aNotify,
|
void SetDirectionFromValue(bool aNotify,
|
||||||
const nsAString* aKnownValue = nullptr);
|
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.
|
* Get the mutable state of the element.
|
||||||
*/
|
*/
|
||||||
@@ -392,7 +369,8 @@ class HTMLTextAreaElement final : public TextControlElement,
|
|||||||
void GetSelectionRange(uint32_t* aSelectionStart, uint32_t* aSelectionEnd,
|
void GetSelectionRange(uint32_t* aSelectionStart, uint32_t* aSelectionEnd,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
void UpdateValidityElementStates(bool aNotify) final;
|
void SetUserInteracted(bool) final;
|
||||||
|
void UpdateValidityElementStates(bool aNotify);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void MapAttributesIntoRule(MappedDeclarationsBuilder&);
|
static void MapAttributesIntoRule(MappedDeclarationsBuilder&);
|
||||||
|
|||||||
@@ -1795,7 +1795,6 @@ void nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm,
|
|||||||
UnsetFlags(ADDED_TO_FORM);
|
UnsetFlags(ADDED_TO_FORM);
|
||||||
SetFormInternal(nullptr, false);
|
SetFormInternal(nullptr, false);
|
||||||
AfterClearForm(aUnbindOrDelete);
|
AfterClearForm(aUnbindOrDelete);
|
||||||
UpdateValidityElementStates(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsGenericHTMLFormElement::BindToTree(BindContext& aContext,
|
nsresult nsGenericHTMLFormElement::BindToTree(BindContext& aContext,
|
||||||
@@ -2148,11 +2147,6 @@ void nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
|
|||||||
form->AddElementToTable(this, idVal);
|
form->AddElementToTable(this, idVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (form != oldForm) {
|
|
||||||
// ui-valid / invalid depends on the form for some elements
|
|
||||||
UpdateValidityElementStates(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsGenericHTMLFormElement::UpdateFieldSet(bool aNotify) {
|
void nsGenericHTMLFormElement::UpdateFieldSet(bool aNotify) {
|
||||||
|
|||||||
@@ -1022,10 +1022,9 @@ class nsGenericHTMLFormElement : public nsGenericHTMLElement {
|
|||||||
*/
|
*/
|
||||||
already_AddRefed<nsILayoutHistoryState> GetLayoutHistory(bool aRead);
|
already_AddRefed<nsILayoutHistoryState> GetLayoutHistory(bool aRead);
|
||||||
|
|
||||||
// Form changes (in particular whether our current form has been submitted
|
// Sets the user-interacted flag in
|
||||||
// invalidly) affect the user-valid/user-invalid pseudo-classes. Sub-classes
|
// https://html.spec.whatwg.org/#user-interacted, if it applies.
|
||||||
// can override this to react to it.
|
virtual void SetUserInteracted(bool aNotify) {}
|
||||||
virtual void UpdateValidityElementStates(bool aNotify) {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~nsGenericHTMLFormElement() = default;
|
virtual ~nsGenericHTMLFormElement() = default;
|
||||||
|
|||||||
@@ -83,13 +83,6 @@ bool nsIConstraintValidation::ReportValidity() {
|
|||||||
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
|
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
|
||||||
|
|
||||||
element->DispatchEvent(*event);
|
element->DispatchEvent(*event);
|
||||||
|
|
||||||
auto* inputElement = HTMLInputElement::FromNode(element);
|
|
||||||
if (inputElement && inputElement->State().HasState(ElementState::FOCUS)) {
|
|
||||||
inputElement->UpdateValidityUIBits(true);
|
|
||||||
inputElement->UpdateValidityElementStates(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=605124
|
|||||||
|
|
||||||
function checkPseudoClass(aElement, aExpected)
|
function checkPseudoClass(aElement, aExpected)
|
||||||
{
|
{
|
||||||
is(aElement.matches(":-moz-ui-invalid"), aExpected,
|
is(aElement.matches(":user-invalid"), aExpected,
|
||||||
"matches(':-moz-ui-invalid') should return " + aExpected + " for " + aElement);
|
"matches(':user-invalid') should return " + aExpected + " for " + aElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
var content = document.getElementById('content');
|
var content = document.getElementById('content');
|
||||||
@@ -62,9 +62,9 @@ checkPseudoClass(select, true);
|
|||||||
content.appendChild(textarea);
|
content.appendChild(textarea);
|
||||||
content.appendChild(input);
|
content.appendChild(input);
|
||||||
content.appendChild(select);
|
content.appendChild(select);
|
||||||
checkPseudoClass(textarea, false);
|
checkPseudoClass(textarea, true);
|
||||||
checkPseudoClass(input, false);
|
checkPseudoClass(input, true);
|
||||||
checkPseudoClass(select, false);
|
checkPseudoClass(select, true);
|
||||||
|
|
||||||
// Back in the form.
|
// Back in the form.
|
||||||
form.appendChild(textarea);
|
form.appendChild(textarea);
|
||||||
@@ -89,10 +89,9 @@ checkPseudoClass(select, true);
|
|||||||
|
|
||||||
// Remove the form.
|
// Remove the form.
|
||||||
document.getElementsByTagName('table')[0].removeChild(form);
|
document.getElementsByTagName('table')[0].removeChild(form);
|
||||||
checkPseudoClass(textarea, false);
|
checkPseudoClass(textarea, true);
|
||||||
checkPseudoClass(input, false);
|
checkPseudoClass(input, true);
|
||||||
checkPseudoClass(select, false);
|
checkPseudoClass(select, true);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -31,15 +31,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=605125
|
|||||||
|
|
||||||
function checkPseudoClass(aElement, aExpected)
|
function checkPseudoClass(aElement, aExpected)
|
||||||
{
|
{
|
||||||
is(aElement.matches(":-moz-ui-valid"), aExpected,
|
is(aElement.matches(":user-valid"), aExpected,
|
||||||
"matches(':-moz-ui-valid') should return " + aExpected + " for " + aElement);
|
"matches(':user-valid') should return " + aExpected + " for " + aElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkElement(aElement)
|
function checkElement(aElement)
|
||||||
{
|
{
|
||||||
checkPseudoClass(aElement, false);
|
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.
|
// the pseudo-class should not apply while typing.
|
||||||
aElement.focus();
|
aElement.focus();
|
||||||
checkPseudoClass(aElement, false);
|
checkPseudoClass(aElement, false);
|
||||||
@@ -57,7 +57,7 @@ function checkElement(aElement)
|
|||||||
aElement.blur();
|
aElement.blur();
|
||||||
checkPseudoClass(aElement, true);
|
checkPseudoClass(aElement, true);
|
||||||
|
|
||||||
// Focusing while :-moz-ui-valid applies,
|
// Focusing while :user-valid applies,
|
||||||
// the pseudo-class should apply while typing if appropriate.
|
// the pseudo-class should apply while typing if appropriate.
|
||||||
aElement.focus();
|
aElement.focus();
|
||||||
checkPseudoClass(aElement, true);
|
checkPseudoClass(aElement, true);
|
||||||
@@ -76,7 +76,7 @@ function checkElement(aElement)
|
|||||||
aElement.required = true;
|
aElement.required = true;
|
||||||
checkPseudoClass(aElement, false);
|
checkPseudoClass(aElement, false);
|
||||||
|
|
||||||
// Focusing while :-moz-ui-invalid applies,
|
// Focusing while :user-invalid applies,
|
||||||
// the pseudo-class should apply while typing if appropriate.
|
// the pseudo-class should apply while typing if appropriate.
|
||||||
aElement.focus();
|
aElement.focus();
|
||||||
checkPseudoClass(aElement, false);
|
checkPseudoClass(aElement, false);
|
||||||
@@ -96,20 +96,15 @@ function checkSelectElement(aElement)
|
|||||||
{
|
{
|
||||||
checkPseudoClass(aElement, false);
|
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.
|
// the pseudo-class should not apply while changing selection.
|
||||||
aElement.focus();
|
aElement.focus();
|
||||||
checkPseudoClass(aElement, false);
|
checkPseudoClass(aElement, false);
|
||||||
|
|
||||||
aElement.selectedIndex = 1;
|
synthesizeKey("KEY_ArrowDown");
|
||||||
checkPseudoClass(aElement, false);
|
|
||||||
aElement.selectedIndex = 0;
|
|
||||||
checkPseudoClass(aElement, false);
|
|
||||||
|
|
||||||
aElement.blur();
|
|
||||||
checkPseudoClass(aElement, true);
|
checkPseudoClass(aElement, true);
|
||||||
|
|
||||||
// Focusing while :-moz-ui-valid applies,
|
// Focusing while :user-valid applies,
|
||||||
// the pseudo-class should apply while changing selection if appropriate.
|
// the pseudo-class should apply while changing selection if appropriate.
|
||||||
aElement.focus();
|
aElement.focus();
|
||||||
checkPseudoClass(aElement, true);
|
checkPseudoClass(aElement, true);
|
||||||
@@ -127,12 +122,12 @@ function checkSelectElement(aElement)
|
|||||||
}
|
}
|
||||||
checkPseudoClass(aElement, false);
|
checkPseudoClass(aElement, false);
|
||||||
|
|
||||||
// Focusing while :-moz-ui-invalid applies,
|
// Focusing while :user-invalid applies,
|
||||||
// the pseudo-class should apply while changing selection if appropriate.
|
// the pseudo-class should apply while changing selection if appropriate.
|
||||||
aElement.focus();
|
aElement.focus();
|
||||||
checkPseudoClass(aElement, false);
|
checkPseudoClass(aElement, false);
|
||||||
|
|
||||||
aElement.selectedIndex = 1;
|
synthesizeKey("KEY_ArrowDown");
|
||||||
checkPseudoClass(aElement, true);
|
checkPseudoClass(aElement, true);
|
||||||
aElement.selectedIndex = 0;
|
aElement.selectedIndex = 0;
|
||||||
checkPseudoClass(aElement, aElement.multiple);
|
checkPseudoClass(aElement, aElement.multiple);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=610687
|
|||||||
<body>
|
<body>
|
||||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=610687">Mozilla Bug 610687</a>
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=610687">Mozilla Bug 610687</a>
|
||||||
<p id="display"></p>
|
<p id="display"></p>
|
||||||
<div id="content" style="display: none">
|
<div id="content">
|
||||||
<form>
|
<form>
|
||||||
<input type='radio' name='a'>
|
<input type='radio' name='a'>
|
||||||
<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");
|
ok(aElement.matches(":invalid"), ":invalid should apply");
|
||||||
}
|
}
|
||||||
|
|
||||||
is(aElement.matches(":-moz-ui-valid"), aValidUI,
|
is(aElement.matches(":user-valid"), aValidUI,
|
||||||
aValid ? ":-moz-ui-valid should apply" : ":-moz-ui-valid should not apply");
|
aValid ? ":user-valid should apply" : ":user-valid should not apply");
|
||||||
|
|
||||||
is(aElement.matches(":-moz-ui-invalid"), aInvalidUI,
|
is(aElement.matches(":user-invalid"), aInvalidUI,
|
||||||
aInvalidUI ? ":-moz-ui-invalid should apply" : ":-moz-ui-invalid should not apply");
|
aInvalidUI ? ":user-invalid should apply" : ":user-invalid should not apply");
|
||||||
|
|
||||||
if (aInvalidUI && (aValid || aValidUI)) {
|
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(r2, false, false, false);
|
||||||
checkPseudoClasses(r3, true, 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).
|
// Do not suffer from being missing (with ui-valid).
|
||||||
r1.checked = true;
|
r1.click();
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, true, true, false);
|
checkPseudoClasses(r2, true, false, false);
|
||||||
checkPseudoClasses(r3, true, false, false);
|
checkPseudoClasses(r3, true, false, false);
|
||||||
|
|
||||||
// Do not suffer from being missing (with ui-valid).
|
// Do not suffer from being missing (with ui-valid).
|
||||||
r1.checked = false;
|
r1.checked = false;
|
||||||
r1.required = false;
|
r1.required = false;
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, true, true, false);
|
checkPseudoClasses(r2, true, false, false);
|
||||||
checkPseudoClasses(r3, true, false, false);
|
checkPseudoClasses(r3, true, false, false);
|
||||||
|
|
||||||
// Suffering from being missing (with ui-invalid) with required set on one radio
|
// 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;
|
r1.required = true;
|
||||||
r2.checked = false;
|
r2.checked = false;
|
||||||
checkPseudoClasses(r1, false, false, true);
|
checkPseudoClasses(r1, false, false, true);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
checkPseudoClasses(r3, true, false, false);
|
checkPseudoClasses(r3, true, false, false);
|
||||||
|
|
||||||
// Do not suffer from being missing (with ui-valid) by checking the radio which
|
// Do not suffer from being missing (with ui-valid) by checking the radio which
|
||||||
// hasn't the required attribute.
|
// hasn't the required attribute.
|
||||||
r2.checked = true;
|
r2.checked = true;
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, true, true, false);
|
checkPseudoClasses(r2, true, false, false);
|
||||||
checkPseudoClasses(r3, true, false, false);
|
checkPseudoClasses(r3, true, false, false);
|
||||||
|
|
||||||
// .setCustomValidity() should not affect the entire group.
|
// .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.required = false;
|
||||||
r1.setCustomValidity('foo');
|
r1.setCustomValidity('foo');
|
||||||
checkPseudoClasses(r1, false, false, true);
|
checkPseudoClasses(r1, false, false, true);
|
||||||
checkPseudoClasses(r2, true, true, false);
|
checkPseudoClasses(r2, true, false, false);
|
||||||
checkPseudoClasses(r3, true, true, false);
|
checkPseudoClasses(r3, true, false, false);
|
||||||
|
|
||||||
r1.setCustomValidity('');
|
r1.setCustomValidity('');
|
||||||
r2.setCustomValidity('foo');
|
r2.setCustomValidity('foo');
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
checkPseudoClasses(r3, true, true, false);
|
checkPseudoClasses(r3, true, false, false);
|
||||||
|
|
||||||
r2.setCustomValidity('');
|
r2.setCustomValidity('');
|
||||||
r3.setCustomValidity('foo');
|
r3.setCustomValidity('foo');
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, true, true, false);
|
checkPseudoClasses(r2, true, false, false);
|
||||||
checkPseudoClasses(r3, false, false, true);
|
checkPseudoClasses(r3, false, false, false);
|
||||||
|
|
||||||
// Removing the radio with the required attribute should make the group valid.
|
// Removing the radio with the required attribute should make the group valid.
|
||||||
r1.setCustomValidity('');
|
r1.setCustomValidity('');
|
||||||
@@ -124,64 +118,64 @@ function checkRadios(r1, r2, r3, form)
|
|||||||
r2.required = true;
|
r2.required = true;
|
||||||
r1.checked = r2.checked = false;
|
r1.checked = r2.checked = false;
|
||||||
checkPseudoClasses(r1, false, false, true);
|
checkPseudoClasses(r1, false, false, true);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
|
|
||||||
var p = r2.parentNode;
|
var p = r2.parentNode;
|
||||||
p.removeChild(r2);
|
p.removeChild(r2);
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
|
|
||||||
p.appendChild(r2);
|
p.appendChild(r2);
|
||||||
checkPseudoClasses(r1, false, false, true);
|
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.
|
// Adding a radio element to an invalid group should make it invalid.
|
||||||
p.removeChild(r1);
|
p.removeChild(r1);
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
|
|
||||||
p.appendChild(r1);
|
p.appendChild(r1);
|
||||||
checkPseudoClasses(r1, false, false, true);
|
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.
|
// Adding a checked radio element to an invalid group should make it valid.
|
||||||
p.removeChild(r1);
|
p.removeChild(r1);
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
|
|
||||||
r1.checked = true;
|
r1.checked = true;
|
||||||
p.appendChild(r1);
|
p.appendChild(r1);
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, true, true, false);
|
checkPseudoClasses(r2, true, false, false);
|
||||||
r1.checked = false;
|
r1.checked = false;
|
||||||
|
|
||||||
// Adding an invalid radio element by changing the name attribute.
|
// Adding an invalid radio element by changing the name attribute.
|
||||||
r2.name = 'c';
|
r2.name = 'c';
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
|
|
||||||
r2.name = 'a';
|
r2.name = 'a';
|
||||||
checkPseudoClasses(r1, false, false, true);
|
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.
|
// Adding an element to an invalid radio group by changing the name attribute.
|
||||||
r1.name = 'c';
|
r1.name = 'c';
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
|
|
||||||
r1.name = 'a';
|
r1.name = 'a';
|
||||||
checkPseudoClasses(r1, false, false, true);
|
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.
|
// Adding a checked element to an invalid radio group with the name attribute.
|
||||||
r1.name = 'c';
|
r1.name = 'c';
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, false, false, true);
|
checkPseudoClasses(r2, false, false, false);
|
||||||
|
|
||||||
r1.checked = true;
|
r1.checked = true;
|
||||||
r1.name = 'a';
|
r1.name = 'a';
|
||||||
checkPseudoClasses(r1, true, true, false);
|
checkPseudoClasses(r1, true, true, false);
|
||||||
checkPseudoClasses(r2, true, true, false);
|
checkPseudoClasses(r2, true, false, false);
|
||||||
r1.checked = false;
|
r1.checked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ interface HTMLSelectElement : HTMLElement {
|
|||||||
[CEReactions, SetterThrows, Pure]
|
[CEReactions, SetterThrows, Pure]
|
||||||
attribute unsigned long size;
|
attribute unsigned long size;
|
||||||
|
|
||||||
[ChromeOnly, Pure]
|
|
||||||
readonly attribute boolean isCombobox;
|
|
||||||
|
|
||||||
[Pure]
|
[Pure]
|
||||||
readonly attribute DOMString type;
|
readonly attribute DOMString type;
|
||||||
|
|
||||||
@@ -72,6 +69,10 @@ interface HTMLSelectElement : HTMLElement {
|
|||||||
// Chrome only interface
|
// Chrome only interface
|
||||||
|
|
||||||
partial interface HTMLSelectElement {
|
partial interface HTMLSelectElement {
|
||||||
|
[ChromeOnly]
|
||||||
|
undefined userFinishedInteracting(boolean changed);
|
||||||
|
[ChromeOnly, Pure]
|
||||||
|
readonly attribute boolean isCombobox;
|
||||||
[ChromeOnly]
|
[ChromeOnly]
|
||||||
attribute boolean openInParentProcess;
|
attribute boolean openInParentProcess;
|
||||||
[ChromeOnly]
|
[ChromeOnly]
|
||||||
|
|||||||
@@ -377,15 +377,7 @@ void HTMLSelectEventListener::ComboboxMightHaveChanged() {
|
|||||||
|
|
||||||
void HTMLSelectEventListener::FireOnInputAndOnChange() {
|
void HTMLSelectEventListener::FireOnInputAndOnChange() {
|
||||||
RefPtr<HTMLSelectElement> element = mElement;
|
RefPtr<HTMLSelectElement> element = mElement;
|
||||||
// Dispatch the input event.
|
element->UserFinishedInteracting(/* aChanged = */ true);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FireDropDownEvent(HTMLSelectElement* aElement, bool aShow,
|
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
|
== 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-disabled.html input-ref.html
|
||||||
fuzzy(0-1,0-3) == input-dyn-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-readonly.html input-ref.html
|
||||||
fuzzy(0-1,0-3) == input-dyn-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-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
|
== 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-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-button.html input-button-ref.html
|
||||||
fuzzy(0-2,0-5) == input-reset.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-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
|
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-invalid-default.html input-withtext-ref.html
|
||||||
== input-url-valid.html input-url-ref.html
|
== input-url-valid.html input-url-ref.html
|
||||||
== input-pattern-valid.html input-withtext-ref.html
|
== input-pattern-valid.html input-withtext-ref.html
|
||||||
== input-pattern-invalid-default.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-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
|
== 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-disabled-fieldset-2.html input-fieldset-ref.html
|
||||||
fuzzy(0-1,0-3) == input-fieldset-legend.html input-fieldset-legend-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-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-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-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-1.html success-ref.html
|
||||||
== input-radio-dyn-valid-2.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-radio-nogroup-required-invalid.html success-ref.html
|
||||||
# input type='hidden' shouldn't show
|
# 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
|
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
|
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-disabled.html select-disabled-ref.html
|
||||||
needs-focus == select-dyn-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-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-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
|
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
|
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
|
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
|
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-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-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-valid.html textarea-ref.html
|
||||||
== textarea-customerror.html textarea-ref.html
|
|
||||||
== textarea-disabled.html textarea-ref.html
|
== textarea-disabled.html textarea-ref.html
|
||||||
== textarea-dyn-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-readonly.html textarea-ref.html
|
||||||
== textarea-dyn-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-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-valid.html textarea-withtext-ref.html
|
||||||
== textarea-required-invalid.html textarea-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-1.html textarea-fieldset-ref.html
|
||||||
== textarea-disabled-fieldset-2.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
|
== 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-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.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-readonly.html input-ref.html
|
||||||
fuzzy(0-1,0-3) == input-dyn-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.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.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
|
fuzzy(0-1,0-3) == input-required-invalid.html input-ref.html
|
||||||
== input-button.html input-button-ref.html
|
== input-button.html input-button-ref.html
|
||||||
== input-reset.html input-button-ref.html
|
== input-reset.html input-button-ref.html
|
||||||
== input-email-invalid.html input-withtext-ref.html
|
== input-email-invalid.html input-withtext-ref.html
|
||||||
== input-email-valid.html input-email-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-invalid.html input-withtext-ref.html
|
||||||
== input-url-valid.html input-url-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.html input-withtext-ref.html
|
||||||
== input-pattern-valid-changed.html input-withtext-ref.html
|
|
||||||
== input-pattern-invalid.html input-withtext-ref.html
|
== input-pattern-invalid.html input-withtext-ref.html
|
||||||
== input-type-barred.html input-button-ref.html
|
== input-type-barred.html input-button-ref.html
|
||||||
fuzzy(0-64,0-4) == input-type-invalid.html input-ref.html
|
fuzzy(0-64,0-4) == input-type-invalid.html input-ref.html
|
||||||
== input-disabled-fieldset-1.html input-fieldset-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-disabled-fieldset-2.html input-fieldset-ref.html
|
||||||
fuzzy(0-1,0-3) == input-fieldset-legend.html input-fieldset-legend-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-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-file-valid-default.html input-file-ref.html
|
||||||
== input-radio-required.html success-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-valid.html success-ref.html
|
||||||
== input-radio-nogroup-required-invalid.html success-ref.html
|
|
||||||
# input type='hidden' shouldn't show
|
# 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-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-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-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-invalid.html select-required-multiple-ref.html
|
||||||
needs-focus == select-required-multiple-valid.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-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-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
|
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-disabled.html textarea-ref.html
|
||||||
== textarea-dyn-disabled.html textarea-ref.html
|
== textarea-dyn-disabled.html textarea-ref.html
|
||||||
== textarea-dyn-not-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-readonly.html textarea-ref.html
|
||||||
== textarea-dyn-readonly.html textarea-ref.html
|
== textarea-dyn-readonly.html textarea-ref.html
|
||||||
== textarea-dyn-not-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.html textarea-withtext-ref.html
|
||||||
== textarea-required-valid-changed.html textarea-withtext-ref.html
|
|
||||||
== textarea-required-invalid.html textarea-ref.html
|
== textarea-required-invalid.html textarea-ref.html
|
||||||
== textarea-disabled-fieldset-1.html textarea-fieldset-ref.html
|
== textarea-disabled-fieldset-1.html textarea-fieldset-ref.html
|
||||||
== textarea-disabled-fieldset-2.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
|
// 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);
|
let handlingUserInput = win.windowUtils.setHandlingUserInput(true);
|
||||||
try {
|
try {
|
||||||
element.dispatchEvent(inputEvent);
|
element.userFinishedInteracting(
|
||||||
element.dispatchEvent(changeEvent);
|
this.initialSelection !== selectedOption
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
handlingUserInput.destruct();
|
handlingUserInput.destruct();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user