Bug 827161, part 2 - Implement HTML 5's ValidityState.badInput and implement the state for HTMLInputElement's number type. r=smaug

This commit is contained in:
Jonathan Watt 2014-01-30 12:54:12 +00:00
Родитель 2a8a0145a1
Коммит dc7188dcc2
18 изменённых файлов: 340 добавлений и 82 удалений

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

@ -19,8 +19,8 @@ class ValidityState;
}
#define NS_ICONSTRAINTVALIDATION_IID \
{ 0xca3824dc, 0x4f5c, 0x4878, \
{ 0xa6, 0x8a, 0x95, 0x54, 0x5f, 0xfa, 0x4b, 0xf9 } }
{ 0x983829da, 0x1aaf, 0x449c, \
{ 0xa3, 0x06, 0x85, 0xd4, 0xf0, 0x31, 0x1c, 0xf6 } }
/**
* This interface is for form elements implementing the validity constraint API.
@ -51,14 +51,16 @@ public:
enum ValidityStateType
{
VALIDITY_STATE_VALUE_MISSING = 0x01, // 0b00000001
VALIDITY_STATE_TYPE_MISMATCH = 0x02, // 0b00000010
VALIDITY_STATE_PATTERN_MISMATCH = 0x04, // 0b00000100
VALIDITY_STATE_TOO_LONG = 0x08, // 0b00001000
VALIDITY_STATE_RANGE_UNDERFLOW = 0x10, // 0b00010000
VALIDITY_STATE_RANGE_OVERFLOW = 0x20, // 0b00100000
VALIDITY_STATE_STEP_MISMATCH = 0x40, // 0b01000000
VALIDITY_STATE_CUSTOM_ERROR = 0x80 // 0b10000000
VALIDITY_STATE_VALUE_MISSING = 0x1 << 0,
VALIDITY_STATE_TYPE_MISMATCH = 0x1 << 1,
VALIDITY_STATE_PATTERN_MISMATCH = 0x1 << 2,
VALIDITY_STATE_TOO_LONG = 0x1 << 3,
//VALIDITY_STATE_TOO_SHORT = 0x1 << 4,
VALIDITY_STATE_RANGE_UNDERFLOW = 0x1 << 5,
VALIDITY_STATE_RANGE_OVERFLOW = 0x1 << 6,
VALIDITY_STATE_STEP_MISMATCH = 0x1 << 7,
VALIDITY_STATE_BAD_INPUT = 0x1 << 8,
VALIDITY_STATE_CUSTOM_ERROR = 0x1 << 9,
};
void SetValidityState(ValidityStateType mState,
@ -103,7 +105,7 @@ private:
* A bitfield representing the current validity state of the element.
* Each bit represent an error. All bits to zero means the element is valid.
*/
int8_t mValidityBitField;
int16_t mValidityBitField;
/**
* Keeps track whether the element is barred from constraint validation.

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

@ -2767,6 +2767,7 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue,
if (!mParserCreating) {
SanitizeValue(value);
}
// else SanitizeValue will be called by DoneCreatingElement
if (aSetValueChanged) {
SetValueChanged(true);
@ -2774,6 +2775,9 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue,
if (IsSingleLineTextControl(false)) {
mInputData.mState->SetValue(value, aUserInput, aSetValueChanged);
if (mType == NS_FORM_INPUT_EMAIL) {
UpdateAllValidityStates(mParserCreating);
}
} else {
mInputData.mValue = ToNewUnicode(value);
if (aSetValueChanged) {
@ -3471,7 +3475,7 @@ HTMLInputElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
numberControlFrame->GetValueOfAnonTextControl(value);
numberControlFrame->HandlingInputEvent(true);
nsWeakFrame weakNumberControlFrame(numberControlFrame);
SetValueInternal(value, false, true);
SetValueInternal(value, true, true);
if (weakNumberControlFrame.IsAlive()) {
numberControlFrame->HandlingInputEvent(false);
}
@ -6422,6 +6426,103 @@ HTMLInputElement::HasStepMismatch() const
return NS_floorModulo(value - GetStepBase(), step) != 0;
}
/**
* Splits the string on the first "@" character and punycode encodes the first
* and second parts separately before rejoining them with an "@" and returning
* the result via the aEncodedEmail out-param. Returns false if there is no
* "@" caracter, if the "@" character is at the start or end, or if the
* conversion to punycode fails.
*
* This function exists because ConvertUTF8toACE() treats 'username@domain' as
* a single label, but we need to encode the username and domain parts
* separately.
*/
static bool PunycodeEncodeEmailAddress(const nsAString& aEmail,
nsAutoCString& aEncodedEmail,
uint32_t* aIndexOfAt)
{
nsAutoCString value = NS_ConvertUTF16toUTF8(aEmail);
uint32_t length = value.Length();
uint32_t atPos = (uint32_t)value.FindChar('@');
// Email addresses must contain a '@', but can't begin or end with it.
if (atPos == (uint32_t)kNotFound || atPos == 0 || atPos == length - 1) {
return false;
}
nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
if (!idnSrv) {
NS_ERROR("nsIIDNService isn't present!");
return false;
}
const nsDependentCSubstring username = Substring(value, 0, atPos);
bool ace;
if (NS_SUCCEEDED(idnSrv->IsACE(username, &ace)) && !ace) {
nsAutoCString usernameACE;
// TODO: Bug 901347: Usernames longer than 63 chars are not converted by
// ConvertUTF8toACE(). For now, continue on even if the conversion fails.
if (NS_SUCCEEDED(idnSrv->ConvertUTF8toACE(username, usernameACE))) {
value.Replace(0, atPos, usernameACE);
atPos = usernameACE.Length();
}
}
const nsDependentCSubstring domain = Substring(value, atPos + 1);
if (NS_SUCCEEDED(idnSrv->IsACE(domain, &ace)) && !ace) {
nsAutoCString domainACE;
if (NS_FAILED(idnSrv->ConvertUTF8toACE(domain, domainACE))) {
return false;
}
value.Replace(atPos + 1, domain.Length(), domainACE);
}
aEncodedEmail = value;
*aIndexOfAt = atPos;
return true;
}
bool
HTMLInputElement::HasBadInput() const
{
if (mType == NS_FORM_INPUT_NUMBER) {
nsAutoString value;
GetValueInternal(value);
if (!value.IsEmpty()) {
// The input can't be bad, otherwise it would have been sanitized to the
// empty string.
NS_ASSERTION(!GetValueAsDecimal().isNaN(), "Should have sanitized");
return false;
}
nsNumberControlFrame* numberControlFrame =
do_QueryFrame(GetPrimaryFrame());
if (numberControlFrame &&
!numberControlFrame->AnonTextControlIsEmpty()) {
// The input the user entered failed to parse as a number.
return true;
}
return false;
}
if (mType == NS_FORM_INPUT_EMAIL) {
// With regards to suffering from bad input the spec says that only the
// punycode conversion works, so we don't care whether the email address is
// valid or not here. (If the email address is invalid then we will be
// suffering from a type mismatch.)
nsAutoString value;
nsAutoCString unused;
uint32_t unused2;
NS_ENSURE_SUCCESS(GetValueInternal(value), false);
HTMLSplitOnSpacesTokenizer tokenizer(value, ',');
while (tokenizer.hasMoreTokens()) {
if (!PunycodeEncodeEmailAddress(tokenizer.nextToken(), unused, &unused2)) {
return true;
}
}
return false;
}
return false;
}
void
HTMLInputElement::UpdateTooLongValidityState()
{
@ -6518,6 +6619,12 @@ HTMLInputElement::UpdateStepMismatchValidityState()
SetValidityState(VALIDITY_STATE_STEP_MISMATCH, HasStepMismatch());
}
void
HTMLInputElement::UpdateBadInputValidityState()
{
SetValidityState(VALIDITY_STATE_BAD_INPUT, HasBadInput());
}
void
HTMLInputElement::UpdateAllValidityStates(bool aNotify)
{
@ -6529,6 +6636,7 @@ HTMLInputElement::UpdateAllValidityStates(bool aNotify)
UpdateRangeOverflowValidityState();
UpdateRangeUnderflowValidityState();
UpdateStepMismatchValidityState();
UpdateBadInputValidityState();
if (validBefore != IsValid()) {
UpdateState(aNotify);
@ -6753,6 +6861,22 @@ HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
aValidationMessage = message;
break;
}
case VALIDITY_STATE_BAD_INPUT:
{
nsXPIDLString message;
nsAutoCString key;
if (mType == NS_FORM_INPUT_NUMBER) {
key.AssignLiteral("FormValidationBadInputNumber");
} else if (mType == NS_FORM_INPUT_EMAIL) {
key.AssignLiteral("FormValidationInvalidEmail");
} else {
return NS_ERROR_UNEXPECTED;
}
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
key.get(), message);
aValidationMessage = message;
break;
}
default:
rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
}
@ -6779,51 +6903,25 @@ HTMLInputElement::IsValidEmailAddressList(const nsAString& aValue)
bool
HTMLInputElement::IsValidEmailAddress(const nsAString& aValue)
{
nsAutoCString value = NS_ConvertUTF16toUTF8(aValue);
uint32_t i = 0;
uint32_t length = value.Length();
// Email addresses can't be empty and can't end with a '.' or '-'.
if (length == 0 || value[length - 1] == '.' || value[length - 1] == '-') {
if (aValue.IsEmpty() || aValue.Last() == '.' || aValue.Last() == '-') {
return false;
}
uint32_t atPos = (uint32_t)value.FindChar('@');
uint32_t atPos;
nsAutoCString value;
if (!PunycodeEncodeEmailAddress(aValue, value, &atPos)) {
return false;
}
uint32_t length = value.Length();
// Email addresses must contain a '@', but can't begin or end with it.
if (atPos == (uint32_t)kNotFound || atPos == 0 || atPos == length - 1) {
return false;
}
// Puny-encode the string if needed before running the validation algorithm.
nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
if (idnSrv) {
// ConvertUTF8toACE() treats 'username@domain' as a single label so we need
// to puny-encode the username and domain parts separately.
const nsDependentCSubstring username = Substring(value, 0, atPos);
bool ace;
if (NS_SUCCEEDED(idnSrv->IsACE(username, &ace)) && !ace) {
nsAutoCString usernameACE;
// TODO: Bug 901347: Usernames longer than 63 chars are not converted by
// ConvertUTF8toACE(). For now, continue on even if the conversion fails.
if (NS_SUCCEEDED(idnSrv->ConvertUTF8toACE(username, usernameACE))) {
value.Replace(0, atPos, usernameACE);
atPos = usernameACE.Length();
}
}
const nsDependentCSubstring domain = Substring(value, atPos + 1);
if (NS_SUCCEEDED(idnSrv->IsACE(domain, &ace)) && !ace) {
nsAutoCString domainACE;
if (NS_FAILED(idnSrv->ConvertUTF8toACE(domain, domainACE))) {
return false;
}
value.Replace(atPos + 1, domain.Length(), domainACE);
}
length = value.Length();
} else {
NS_ERROR("nsIIDNService isn't present!");
}
uint32_t i = 0;
// Parsing the username.
for (; i < atPos; ++i) {

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

@ -257,6 +257,7 @@ public:
bool IsRangeOverflow() const;
bool IsRangeUnderflow() const;
bool HasStepMismatch() const;
bool HasBadInput() const;
void UpdateTooLongValidityState();
void UpdateValueMissingValidityState();
void UpdateTypeMismatchValidityState();
@ -264,6 +265,7 @@ public:
void UpdateRangeOverflowValidityState();
void UpdateRangeUnderflowValidityState();
void UpdateStepMismatchValidityState();
void UpdateBadInputValidityState();
void UpdateAllValidityStates(bool aNotify);
void UpdateBarredFromConstraintValidation();
nsresult GetValidationMessage(nsAString& aValidationMessage,

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

@ -76,6 +76,13 @@ ValidityState::GetStepMismatch(bool* aStepMismatch)
return NS_OK;
}
NS_IMETHODIMP
ValidityState::GetBadInput(bool* aBadInput)
{
*aBadInput = BadInput();
return NS_OK;
}
NS_IMETHODIMP
ValidityState::GetCustomError(bool* aCustomError)
{

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

@ -60,6 +60,10 @@ public:
{
return GetValidityState(nsIConstraintValidation::VALIDITY_STATE_STEP_MISMATCH);
}
bool BadInput() const
{
return GetValidityState(nsIConstraintValidation::VALIDITY_STATE_BAD_INPUT);
}
bool CustomError() const
{
return GetValidityState(nsIConstraintValidation::VALIDITY_STATE_CUSTOM_ERROR);

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

@ -86,6 +86,8 @@ nsIConstraintValidation::GetValidationMessage(nsAString& aValidationMessage)
GetValidationMessage(aValidationMessage, VALIDITY_STATE_RANGE_UNDERFLOW);
} else if (GetValidityState(VALIDITY_STATE_STEP_MISMATCH)) {
GetValidationMessage(aValidationMessage, VALIDITY_STATE_STEP_MISMATCH);
} else if (GetValidityState(VALIDITY_STATE_BAD_INPUT)) {
GetValidationMessage(aValidationMessage, VALIDITY_STATE_BAD_INPUT);
} else {
// There should not be other validity states.
return NS_ERROR_UNEXPECTED;

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

@ -2,6 +2,7 @@
support-files =
save_restore_radio_groups.sjs
submit_invalid_file.sjs
test_input_number_data.js
[test_button_attributes_reflection.html]
[test_change_event.html]
@ -32,6 +33,9 @@ skip-if = os == "android" || appname == "b2g"
skip-if = os == "android" || appname == "b2g"
[test_input_number_rounding.html]
skip-if = os == "android"
[test_input_number_validation.html]
# We don't build ICU for Firefox for Android or Firefox OS:
skip-if = os == "android" || appname == "b2g"
[test_input_range_attr_order.html]
[test_input_range_key_events.html]
[test_input_range_mouse_and_touch_events.html]

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

@ -0,0 +1,23 @@
var tests = [
{ desc: "British English",
langTag: "en-GB", inputWithGrouping: "123,456.78",
inputWithoutGrouping: "123456.78", value: 123456.78
},
{ desc: "Farsi",
langTag: "fa", inputWithGrouping: "۱۲۳٬۴۵۶٫۷۸",
inputWithoutGrouping: "۱۲۳۴۵۶٫۷۸", value: 123456.78
},
{ desc: "French",
langTag: "fr-FR", inputWithGrouping: "123 456,78",
inputWithoutGrouping: "123456,78", value: 123456.78
},
{ desc: "German",
langTag: "de", inputWithGrouping: "123.456,78",
inputWithoutGrouping: "123456,78", value: 123456.78
},
{ desc: "Hebrew",
langTag: "he", inputWithGrouping: "123,456.78",
inputWithoutGrouping: "123456.78", value: 123456.78
},
];

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

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=844744
<title>Test localization of number control input</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="test_input_number_data.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta charset="UTF-8">
</head>
@ -31,29 +32,6 @@ SimpleTest.waitForFocus(function() {
SimpleTest.finish();
});
var tests = [
{ desc: "British English",
langTag: "en-GB", inputWithGrouping: "123,456.78",
inputWithoutGrouping: "123456.78", value: 123456.78
},
{ desc: "Farsi",
langTag: "fa", inputWithGrouping: "۱۲۳٬۴۵۶٫۷۸",
inputWithoutGrouping: "۱۲۳۴۵۶٫۷۸", value: 123456.78
},
{ desc: "French",
langTag: "fr-FR", inputWithGrouping: "123 456,78",
inputWithoutGrouping: "123456,78", value: 123456.78
},
{ desc: "German",
langTag: "de", inputWithGrouping: "123.456,78",
inputWithoutGrouping: "123456,78", value: 123456.78
},
{ desc: "Hebrew",
langTag: "he", inputWithGrouping: "123,456.78",
inputWithoutGrouping: "123456.78", value: 123456.78
},
];
var elem;
function runTest(test) {

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

@ -0,0 +1,99 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=827161
-->
<head>
<title>Test validation of number control input</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="test_input_number_data.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta charset="UTF-8">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=827161">Mozilla Bug 827161</a>
<p id="display"></p>
<div id="content">
<input id="input" type="number" step="0.01" oninvalid="invalidEventHandler(event);">
</div>
<pre id="test">
<script type="application/javascript">
/**
* Test for Bug 827161.
* This test checks that validation works correctly for <input type=number>.
**/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
startTests();
SimpleTest.finish();
});
var elem;
function runTest(test) {
elem.lang = test.langTag;
gInvalid = false; // reset
elem.value = 0;
elem.focus();
elem.select();
sendString(test.inputWithGrouping);
checkIsValid(elem, test.desc + " ('" + test.langTag + "') with grouping separator");
sendChar("a");
checkIsInvalid(elem, test.desc + " ('" + test.langTag + "') with grouping separator");
gInvalid = false; // reset
elem.value = 0;
elem.select();
sendString(test.inputWithoutGrouping);
checkIsValid(elem, test.desc + " ('" + test.langTag + "') without grouping separator");
sendChar("a");
checkIsInvalid(elem, test.desc + " ('" + test.langTag + "') without grouping separator");
}
function startTests() {
elem = document.getElementById("input");
for (var test of tests) {
runTest(test);
}
}
var gInvalid = false;
function invalidEventHandler(e)
{
is(e.type, "invalid", "Invalid event type should be 'invalid'");
gInvalid = true;
}
function checkIsValid(element, infoStr)
{
ok(!element.validity.badInput,
"Element should not suffer from bad input for " + infoStr);
ok(element.validity.valid, "Element should be valid for " + infoStr);
ok(element.checkValidity(), "checkValidity() should return true for " + infoStr);
ok(!gInvalid, "The invalid event should not have been thrown for " + infoStr);
is(element.validationMessage, '',
"Validation message should be the empty string for " + infoStr);
ok(element.mozMatchesSelector(":valid"), ":valid pseudo-class should apply for " + infoStr);
}
function checkIsInvalid(element, infoStr)
{
ok(element.validity.badInput,
"Element should suffer from bad input for " + infoStr);
ok(!element.validity.valid, "Element should not be valid for " + infoStr);
ok(!element.checkValidity(), "checkValidity() should return false for " + infoStr);
ok(gInvalid, "The invalid event should have been thrown for " + infoStr);
is(element.validationMessage, "Please enter a number.",
"Validation message is not the expected message for " + infoStr);
ok(element.mozMatchesSelector(":invalid"), ":invalid pseudo-class should apply for " + infoStr);
}
</script>
</pre>
</body>
</html>

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

@ -31,6 +31,7 @@ var input = document.getElementById('i');
var form = document.getElementById('f');
var submitFrame = document.getElementsByTagName('iframe')[0];
var testData = [];
var gCurrentTest = null;
var gValidData = [];
var gInvalidData = [];
@ -46,6 +47,19 @@ function urlify(aStr) {
return aStr.replace(':', '%3A', 'g');
}
function runTestsForNextInputType()
{
try {
testRunner.next();
} catch (e) {
if (e.toString() == '[object StopIteration]') {
SimpleTest.finish();
} else {
throw StopIteration;
}
}
}
function checkValueSubmittedIsValid()
{
is(frames['submit_frame'].location.href,
@ -56,6 +70,12 @@ function checkValueSubmittedIsValid()
input.value = "";
if (valueIndex >= gValidData.length) {
if (gCurrentTest.canHaveBadInputValidityState) {
// Don't run the submission tests on the invalid input if submission
// will be blocked by invalid input.
runTestsForNextInputType();
return;
}
valueIndex = 0;
submitFrame.onload = checkValueSubmittedIsInvalid;
testData = gInvalidData;
@ -74,15 +94,7 @@ function checkValueSubmittedIsInvalid()
if (valueIndex >= gInvalidData.length) {
if (submitMethod == sendKeyEventToSubmitForm) {
try {
testRunner.next();
} catch (e) {
if (e.toString() == '[object StopIteration]') {
SimpleTest.finish();
} else {
throw StopIteration;
}
}
runTestsForNextInputType();
return;
}
valueIndex = 0;
@ -109,6 +121,7 @@ function runTest()
var data = [
{
type: 'number',
canHaveBadInputValidityState: true,
validData: [
"42",
"-42", // should work for negative values
@ -173,6 +186,8 @@ function runTest()
];
for (test of data) {
gCurrentTest = test;
if (test.todo) {
input.type = test.type;
todo_is(input.type, test.type, test.type + " is not implemented");

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

@ -57,6 +57,7 @@ function checkConstraintValidationAPIExist(element)
validity = element.validity;
ok('valueMissing' in validity, "validity.valueMissing is not available in the DOM");
ok('typeMismatch' in validity, "validity.typeMismatch is not available in the DOM");
ok('badInput' in validity, "validity.badInput is not available in the DOM");
ok('patternMismatch' in validity, "validity.patternMismatch is not available in the DOM");
ok('tooLong' in validity, "validity.tooLong is not available in the DOM");
ok('rangeUnderflow' in validity, "validity.rangeUnderflow is not available in the DOM");
@ -75,6 +76,7 @@ function checkConstraintValidationAPIDefaultValues(element)
ok(!element.validity.valueMissing, "The element should not suffer from a constraint validation");
ok(!element.validity.typeMismatch, "The element should not suffer from a constraint validation");
ok(!element.validity.badInput, "The element should not suffer from a constraint validation");
ok(!element.validity.patternMismatch, "The element should not suffer from a constraint validation");
ok(!element.validity.tooLong, "The element should not suffer from a constraint validation");
ok(!element.validity.rangeUnderflow, "The element should not suffer from a constraint validation");
@ -152,6 +154,10 @@ function checkSpecificWillValidate()
ok(!i.willValidate, "Submit state input should be barred from constraint validation");
is(window.getComputedStyle(i, null).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
i.type = "number";
ok(i.willValidate, "Number state input should not be barred from constraint validation");
is(window.getComputedStyle(i, null).getPropertyValue('background-color'),
"rgb(0, 255, 0)", ":valid pseudo-class should apply");
i.type = "";
i.readOnly = 'true';
ok(!i.willValidate, "Readonly input should be barred from constraint validation");
@ -275,6 +281,8 @@ function checkValidityStateObjectAliveWithoutElement(element)
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.typeMismatch,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.badInput,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.patternMismatch,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.tooLong,

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

@ -13,7 +13,7 @@
* http://www.whatwg.org/specs/web-apps/current-work/#validitystate
*/
[scriptable, uuid(5e62197a-9b74-4812-b5a2-ca102e886f7a)]
[scriptable, uuid(00bed276-f1f7-492f-a039-dbd9b9efc10b)]
interface nsIDOMValidityState : nsISupports
{
readonly attribute boolean valueMissing;
@ -23,6 +23,7 @@ interface nsIDOMValidityState : nsISupports
readonly attribute boolean rangeUnderflow;
readonly attribute boolean rangeOverflow;
readonly attribute boolean stepMismatch;
readonly attribute boolean badInput;
readonly attribute boolean customError;
readonly attribute boolean valid;
};

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

@ -41,6 +41,7 @@ FormValidationRangeUnderflow=Please select a value that is higher than %S.
FormValidationStepMismatch=Please select a valid value. The two nearest valid values are %S and %S.
# LOCALIZATION NOTE (FormValidationStepMismatchOneValue): %S can be a number, a date or a time. This is called instead of FormValidationStepMismatch when the second value is the same as the first.
FormValidationStepMismatchOneValue=Please select a valid value. The nearest valid value is %S.
FormValidationBadInputNumber=Please enter a number.
GetAttributeNodeWarning=Use of getAttributeNode() is deprecated. Use getAttribute() instead.
SetAttributeNodeWarning=Use of setAttributeNode() is deprecated. Use setAttribute() instead.
GetAttributeNodeNSWarning=Use of getAttributeNodeNS() is deprecated. Use getAttributeNS() instead.

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

@ -18,7 +18,7 @@ interface ValidityState {
readonly attribute boolean rangeUnderflow;
readonly attribute boolean rangeOverflow;
readonly attribute boolean stepMismatch;
// readonly attribute boolean badInput;
readonly attribute boolean badInput;
readonly attribute boolean customError;
readonly attribute boolean valid;
};

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

@ -595,6 +595,17 @@ nsNumberControlFrame::GetValueOfAnonTextControl(nsAString& aValue)
#endif
}
bool
nsNumberControlFrame::AnonTextControlIsEmpty()
{
if (!mTextField) {
return true;
}
nsAutoString value;
HTMLInputElement::FromContent(mTextField)->GetValue(value);
return value.IsEmpty();
}
Element*
nsNumberControlFrame::GetPseudoElement(nsCSSPseudoElements::Type aType)
{

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

@ -95,6 +95,8 @@ public:
*/
void GetValueOfAnonTextControl(nsAString& aValue);
bool AnonTextControlIsEmpty();
/**
* Called to notify this frame that its HTMLInputElement is currently
* processing a DOM 'input' event.

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

@ -41,6 +41,7 @@ FormValidationRangeUnderflow=Please select a value that is higher than %S.
FormValidationStepMismatch=Please select a valid value. The two nearest valid values are %S and %S.
# LOCALIZATION NOTE (FormValidationStepMismatchOneValue): %S can be a number, a date or a time. This is called instead of FormValidationStepMismatch when the second value is the same as the first.
FormValidationStepMismatchOneValue=Please select a valid value. The nearest valid value is %S.
FormValidationBadInputNumber=Please enter a number.
GetAttributeNodeWarning=Use of getAttributeNode() is deprecated. Use getAttribute() instead.
SetAttributeNodeWarning=Use of setAttributeNode() is deprecated. Use setAttribute() instead.
GetAttributeNodeNSWarning=Use of getAttributeNodeNS() is deprecated. Use getAttributeNS() instead.