зеркало из https://github.com/mozilla/gecko-dev.git
Bug 781569 - Implement the value sanitizing algorithm for <input type=time>. r=smaug
This commit is contained in:
Родитель
9ee390fef5
Коммит
c2fbfd90b3
|
@ -2995,6 +2995,13 @@ nsHTMLInputElement::SanitizeValue(nsAString& aValue)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case NS_FORM_INPUT_TIME:
|
||||
{
|
||||
if (!aValue.IsEmpty() && !IsValidTime(aValue)) {
|
||||
aValue.Truncate();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3133,6 +3140,88 @@ nsHTMLInputElement::NumberOfDaysInMonth(uint32_t aMonth, uint32_t aYear) const
|
|||
return (aYear % 400 == 0 || (aYear % 100 != 0 && aYear % 4 == 0))
|
||||
? 29 : 28;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsHTMLInputElement::DigitSubStringToNumber(const nsAString& aStr,
|
||||
uint32_t aStart, uint32_t aLen,
|
||||
uint32_t* aRetVal)
|
||||
{
|
||||
MOZ_ASSERT(aStr.Length() > (aStart + aLen - 1));
|
||||
|
||||
for (uint32_t offset = 0; offset < aLen; ++offset) {
|
||||
if (!NS_IsAsciiDigit(aStr[aStart + offset])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult ec;
|
||||
*aRetVal = static_cast<uint32_t>(PromiseFlatString(Substring(aStr, aStart, aLen)).ToInteger(&ec));
|
||||
|
||||
return NS_SUCCEEDED(ec);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::IsValidTime(const nsAString& aValue) const
|
||||
{
|
||||
/* The string must have the following parts:
|
||||
* - HOURS: two digits, value being in [0, 23];
|
||||
* - Colon (:);
|
||||
* - MINUTES: two digits, value being in [0, 59];
|
||||
* - Optional:
|
||||
* - Colon (:);
|
||||
* - SECONDS: two digits, value being in [0, 59];
|
||||
* - Optional:
|
||||
* - DOT (.);
|
||||
* - FRACTIONAL SECONDS: one to three digits, no value range.
|
||||
*/
|
||||
|
||||
// The following format is the shorter one allowed: "HH:MM".
|
||||
if (aValue.Length() < 5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t hours;
|
||||
if (!DigitSubStringToNumber(aValue, 0, 2, &hours) || hours > 23) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hours/minutes separator.
|
||||
if (aValue[2] != ':') {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t minutes;
|
||||
if (!DigitSubStringToNumber(aValue, 3, 2, &minutes) || minutes > 59) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aValue.Length() == 5) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The following format is the next shorter one: "HH:MM:SS".
|
||||
if (aValue.Length() < 8 || aValue[5] != ':') {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t seconds;
|
||||
if (!DigitSubStringToNumber(aValue, 6, 2, &seconds) || seconds > 59) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aValue.Length() == 8) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The string must follow this format now: "HH:MM:SS.{s,ss,sss}".
|
||||
// There can be 1 to 3 digits for the fractions of seconds.
|
||||
if (aValue.Length() == 9 || aValue.Length() > 12 || aValue[8] != '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t fractionsSeconds;
|
||||
return DigitSubStringToNumber(aValue, 9, aValue.Length() - 9, &fractionsSeconds);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::ParseAttribute(int32_t aNamespaceID,
|
||||
|
|
|
@ -334,6 +334,23 @@ protected:
|
|||
*/
|
||||
static bool IsValidEmailAddressList(const nsAString& aValue);
|
||||
|
||||
/**
|
||||
* This helper method convert a sub-string that contains only digits to a
|
||||
* number (unsigned int given that it can't contain a minus sign).
|
||||
* This method will return whether the sub-string is correctly formatted
|
||||
* (ie. contains only digit) and it can be successfuly parsed to generate a
|
||||
* number).
|
||||
* If the method returns true, |aResult| will contained the parsed number.
|
||||
*
|
||||
* @param aValue the string on which the sub-string will be extracted and parsed.
|
||||
* @param aStart the beginning of the sub-string in aValue.
|
||||
* @param aLen the length of the sub-string.
|
||||
* @param aResult the parsed number.
|
||||
* @return whether the sub-string has been parsed successfully.
|
||||
*/
|
||||
static bool DigitSubStringToNumber(const nsAString& aValue, uint32_t aStart,
|
||||
uint32_t aLen, uint32_t* aResult);
|
||||
|
||||
// Helper method
|
||||
nsresult SetValueInternal(const nsAString& aValue,
|
||||
bool aUserInput,
|
||||
|
@ -609,6 +626,15 @@ protected:
|
|||
*/
|
||||
uint32_t NumberOfDaysInMonth(uint32_t aMonth, uint32_t aYear) const;
|
||||
|
||||
/**
|
||||
* Returns whether aValue is a valid time as described by HTML specifications:
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string
|
||||
*
|
||||
* @param aValue the string to be tested.
|
||||
* @return Whether the string is a valid time per HTML specifications.
|
||||
*/
|
||||
bool IsValidTime(const nsAString& aValue) const;
|
||||
|
||||
/**
|
||||
* Sets the value of the element to the string representation of the double.
|
||||
*
|
||||
|
|
|
@ -56,6 +56,7 @@ function sanitizeValue(aType, aValue)
|
|||
case "number":
|
||||
return (parseFloat(aValue) + "" === aValue) ? aValue : "";
|
||||
case "date":
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-date-string
|
||||
function getNumbersOfDaysInMonth(aMonth, aYear) {
|
||||
if (aMonth === 2) {
|
||||
return (aYear % 400 === 0 || (aYear % 100 != 0 && aYear % 4 === 0)) ? 29 : 28;
|
||||
|
@ -79,7 +80,40 @@ function sanitizeValue(aType, aValue)
|
|||
var day = Number(match[3]);
|
||||
return 1 <= day && day <= getNumbersOfDaysInMonth(month, year) ? aValue : "";
|
||||
case "time":
|
||||
return "";
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string
|
||||
var match = /^([0-9]{2}):([0-9]{2})(.*)$/.exec(aValue);
|
||||
if (!match) {
|
||||
return "";
|
||||
}
|
||||
var hours = match[1];
|
||||
if (hours < 0 || hours > 23) {
|
||||
return "";
|
||||
}
|
||||
var minutes = match[2];
|
||||
if (minutes < 0 || minutes > 59) {
|
||||
return "";
|
||||
}
|
||||
var other = match[3];
|
||||
if (other == "") {
|
||||
return aValue;
|
||||
}
|
||||
match = /^:([0-9]{2})(.*)$/.exec(other);
|
||||
if (!match) {
|
||||
return "";
|
||||
}
|
||||
var seconds = match[1];
|
||||
if (seconds < 0 || seconds > 59) {
|
||||
return "";
|
||||
}
|
||||
var other = match[2];
|
||||
if (other == "") {
|
||||
return aValue;
|
||||
}
|
||||
match = /^.([0-9]{1,3})$/.exec(other);
|
||||
if (!match) {
|
||||
return "";
|
||||
}
|
||||
return aValue;
|
||||
case "month":
|
||||
case "week":
|
||||
case "datetime":
|
||||
|
@ -102,10 +136,6 @@ function sanitizeValue(aType, aValue)
|
|||
|
||||
function checkSanitizing(element)
|
||||
{
|
||||
if (element.type === 'time') {
|
||||
return;
|
||||
}
|
||||
|
||||
var testData =
|
||||
[
|
||||
// For text, password, search, tel, email:
|
||||
|
@ -168,6 +198,63 @@ function checkSanitizing(element)
|
|||
"1234-12 12",
|
||||
"1234 12-12",
|
||||
"1234 12 12",
|
||||
// For time:
|
||||
"1",
|
||||
"10",
|
||||
"10:",
|
||||
"10:1",
|
||||
"21:21",
|
||||
":21:21",
|
||||
"-21:21",
|
||||
" 21:21",
|
||||
"21-21",
|
||||
"21:21:",
|
||||
"21:211",
|
||||
"121:211",
|
||||
"21:21 ",
|
||||
"00:00",
|
||||
"-1:00",
|
||||
"24:00",
|
||||
"00:60",
|
||||
"01:01",
|
||||
"23:59",
|
||||
"99:99",
|
||||
"8:30",
|
||||
"19:2",
|
||||
"19:a2",
|
||||
"4c:19",
|
||||
"10:.1",
|
||||
"1.:10",
|
||||
"13:37:42",
|
||||
"13:37.42",
|
||||
"13:37:42 ",
|
||||
"13:37:42.",
|
||||
"13:37:61.",
|
||||
"13:37:00",
|
||||
"13:37:99",
|
||||
"13:37:b5",
|
||||
"13:37:-1",
|
||||
"13:37:.1",
|
||||
"13:37:1.",
|
||||
"13:37:42.001",
|
||||
"13:37:42.001",
|
||||
"13:37:42.abc",
|
||||
"13:37:42.00c",
|
||||
"13:37:42.a23",
|
||||
"13:37:42.12e",
|
||||
"13:37:42.1e1",
|
||||
"13:37:42.e11",
|
||||
"13:37:42.1",
|
||||
"13:37:42.99",
|
||||
"13:37:42.0",
|
||||
"13:37:42.00",
|
||||
"13:37:42.000",
|
||||
"13:37:42.-1",
|
||||
"13:37:42.1.1",
|
||||
"13:37:42.1,1",
|
||||
"13:37:42.",
|
||||
"foo12:12",
|
||||
"13:37:42.100000000000",
|
||||
];
|
||||
|
||||
for (value of testData) {
|
||||
|
|
|
@ -44,6 +44,8 @@ var todoTypes = [
|
|||
"datetime", "month", "week", "datetime-local", "range", "color"
|
||||
];
|
||||
|
||||
var nonTrivialSanitizing = [ 'number', 'date', 'time' ];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
|
||||
|
||||
|
@ -54,13 +56,15 @@ for (var i=0; i<length; ++i) {
|
|||
e.type = testData[i][0];
|
||||
|
||||
var expectedValue;
|
||||
if ((testData[i][0] == 'number' && testData[j][0] == 'date') ||
|
||||
(testData[i][0] == 'date' && testData[j][0] == 'number')) {
|
||||
if (nonTrivialSanitizing.indexOf(testData[i][0]) != -1 &&
|
||||
nonTrivialSanitizing.indexOf(testData[j][0]) != -1) {
|
||||
expectedValue = '';
|
||||
} else if (testData[i][0] == 'number' || testData[j][0] == 'number') {
|
||||
expectedValue = '42';
|
||||
} else if (testData[i][0] == 'date' || testData[j][0] == 'date') {
|
||||
expectedValue = '2012-12-21';
|
||||
} else if (testData[i][0] == 'time' || testData[j][0] == 'time') {
|
||||
expectedValue = '21:21';
|
||||
} else {
|
||||
expectedValue = "foo";
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче