зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1278186 - Implement valueAsNumber and valueAsDate for <input type=week>. r=smaug,Waldo
This commit is contained in:
Родитель
c89ca66d22
Коммит
c35a0bf546
|
@ -215,9 +215,13 @@ const Decimal HTMLInputElement::kDefaultStep = Decimal(1);
|
|||
const Decimal HTMLInputElement::kDefaultStepTime = Decimal(60);
|
||||
const Decimal HTMLInputElement::kStepAny = Decimal(0);
|
||||
|
||||
const double HTMLInputElement::kMaximumYear = 275760;
|
||||
const double HTMLInputElement::kMinimumYear = 1;
|
||||
const double HTMLInputElement::kMaximumYear = 275760;
|
||||
const double HTMLInputElement::kMaximumWeekInMaximumYear = 37;
|
||||
const double HTMLInputElement::kMaximumDayInMaximumYear = 13;
|
||||
const double HTMLInputElement::kMaximumMonthInMaximumYear = 9;
|
||||
const double HTMLInputElement::kMaximumWeekInYear = 53;
|
||||
const double HTMLInputElement::kMsPerDay = 24 * 60 * 60 * 1000;
|
||||
|
||||
#define NS_INPUT_ELEMENT_STATE_IID \
|
||||
{ /* dc3b3d14-23e2-4479-b513-7b369343e3a0 */ \
|
||||
|
@ -1880,12 +1884,12 @@ HTMLInputElement::ConvertStringToNumber(nsAString& aValue,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Maximum valid month is 275760-09.
|
||||
if (year < kMinimumYear || year > kMaximumYear) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (year == kMaximumYear && month > 9) {
|
||||
// Maximum valid month is 275760-09.
|
||||
if (year == kMaximumYear && month > kMaximumMonthInMaximumYear) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1893,6 +1897,26 @@ HTMLInputElement::ConvertStringToNumber(nsAString& aValue,
|
|||
aResultValue = Decimal(int32_t(months));
|
||||
return true;
|
||||
}
|
||||
case NS_FORM_INPUT_WEEK:
|
||||
{
|
||||
uint32_t year, week;
|
||||
if (!ParseWeek(aValue, &year, &week)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (year < kMinimumYear || year > kMaximumYear) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Maximum week is 275760-W37, the week of 275760-09-13.
|
||||
if (year == kMaximumYear && week > kMaximumWeekInMaximumYear) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double days = DaysSinceEpochFromWeek(year, week);
|
||||
aResultValue = Decimal::fromDouble(days * kMsPerDay);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unrecognized input type");
|
||||
return false;
|
||||
|
@ -2131,6 +2155,41 @@ HTMLInputElement::ConvertNumberToString(Decimal aValue,
|
|||
aResultString.AppendPrintf("%04.0f-%02.0f", year, month + 1);
|
||||
return true;
|
||||
}
|
||||
case NS_FORM_INPUT_WEEK:
|
||||
{
|
||||
aValue = aValue.floor();
|
||||
|
||||
// Based on ISO 8601 date.
|
||||
double year = JS::YearFromTime(aValue.toDouble());
|
||||
double month = JS::MonthFromTime(aValue.toDouble());
|
||||
double day = JS::DayFromTime(aValue.toDouble());
|
||||
// Adding 1 since day starts from 0.
|
||||
double dayInYear = JS::DayWithinYear(aValue.toDouble(), year) + 1;
|
||||
|
||||
// Adding 1 since month starts from 0.
|
||||
uint32_t isoWeekday = DayOfWeek(year, month + 1, day, true);
|
||||
// Target on Wednesday since ISO 8601 states that week 1 is the week
|
||||
// with the first Thursday of that year.
|
||||
uint32_t week = (dayInYear - isoWeekday + 10) / 7;
|
||||
|
||||
if (week < 1) {
|
||||
year--;
|
||||
if (year < 1) {
|
||||
return false;
|
||||
}
|
||||
week = MaximumWeekInYear(year);
|
||||
} else if (week > MaximumWeekInYear(year)) {
|
||||
year++;
|
||||
if (year > kMaximumYear ||
|
||||
(year == kMaximumYear && week > kMaximumWeekInMaximumYear)) {
|
||||
return false;
|
||||
}
|
||||
week = 1;
|
||||
}
|
||||
|
||||
aResultString.AppendPrintf("%04.0f-W%02d", year, week);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unrecognized input type");
|
||||
return false;
|
||||
|
@ -2141,8 +2200,7 @@ HTMLInputElement::ConvertNumberToString(Decimal aValue,
|
|||
Nullable<Date>
|
||||
HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
|
||||
{
|
||||
// TODO: this is temporary until bug 888316 is fixed.
|
||||
if (!IsDateTimeInputType(mType) || mType == NS_FORM_INPUT_WEEK) {
|
||||
if (!IsDateTimeInputType(mType)) {
|
||||
return Nullable<Date>();
|
||||
}
|
||||
|
||||
|
@ -2186,6 +2244,20 @@ HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
|
|||
JS::ClippedTime time = JS::TimeClip(JS::MakeDate(year, month - 1, 1));
|
||||
return Nullable<Date>(Date(time));
|
||||
}
|
||||
case NS_FORM_INPUT_WEEK:
|
||||
{
|
||||
uint32_t year, week;
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
if (!ParseWeek(value, &year, &week)) {
|
||||
return Nullable<Date>();
|
||||
}
|
||||
|
||||
double days = DaysSinceEpochFromWeek(year, week);
|
||||
JS::ClippedTime time = JS::TimeClip(days * kMsPerDay);
|
||||
|
||||
return Nullable<Date>(Date(time));
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Unrecognized input type");
|
||||
|
@ -2196,8 +2268,7 @@ HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
|
|||
void
|
||||
HTMLInputElement::SetValueAsDate(Nullable<Date> aDate, ErrorResult& aRv)
|
||||
{
|
||||
// TODO: this is temporary until bug 888316 is fixed.
|
||||
if (!IsDateTimeInputType(mType) || mType == NS_FORM_INPUT_WEEK) {
|
||||
if (!IsDateTimeInputType(mType)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -5096,24 +5167,31 @@ HTMLInputElement::IsLeapYear(uint32_t aYear) const
|
|||
}
|
||||
|
||||
uint32_t
|
||||
HTMLInputElement::DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay) const
|
||||
HTMLInputElement::DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
|
||||
bool isoWeek) const
|
||||
{
|
||||
// Tomohiko Sakamoto algorithm.
|
||||
int monthTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
|
||||
aYear -= aMonth < 3;
|
||||
|
||||
return (aYear + aYear / 4 - aYear / 100 + aYear / 400 +
|
||||
monthTable[aMonth - 1] + aDay) % 7;
|
||||
uint32_t day = (aYear + aYear / 4 - aYear / 100 + aYear / 400 +
|
||||
monthTable[aMonth - 1] + aDay) % 7;
|
||||
|
||||
if (isoWeek) {
|
||||
return ((day + 6) % 7) + 1;
|
||||
}
|
||||
|
||||
return day;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
HTMLInputElement::MaximumWeekInYear(uint32_t aYear) const
|
||||
{
|
||||
int day = DayOfWeek(aYear, 1, 1); // January 1.
|
||||
int day = DayOfWeek(aYear, 1, 1, true); // January 1.
|
||||
// A year starting on Thursday or a leap year starting on Wednesday has 53
|
||||
// weeks. All other years have 52 weeks.
|
||||
return day == 4 || (day == 3 && IsLeapYear(aYear)) ? kMaximumWeekInYear
|
||||
: kMaximumWeekInYear - 1;
|
||||
return day == 4 || (day == 3 && IsLeapYear(aYear)) ?
|
||||
kMaximumWeekInYear : kMaximumWeekInYear - 1;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -5228,6 +5306,25 @@ bool HTMLInputElement::ParseDate(const nsAString& aValue,
|
|||
*aDay > 0 && *aDay <= NumberOfDaysInMonth(*aMonth, *aYear);
|
||||
}
|
||||
|
||||
double
|
||||
HTMLInputElement::DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const
|
||||
{
|
||||
double days = JS::DayFromYear(aYear) + (aWeek - 1) * 7;
|
||||
uint32_t dayOneIsoWeekday = DayOfWeek(aYear, 1, 1, true);
|
||||
|
||||
// If day one of that year is on/before Thursday, we should subtract the
|
||||
// days that belong to last year in our first week, otherwise, our first
|
||||
// days belong to last year's last week, and we should add those days
|
||||
// back.
|
||||
if (dayOneIsoWeekday <= 4) {
|
||||
days -= (dayOneIsoWeekday - 1);
|
||||
} else {
|
||||
days += (7 - dayOneIsoWeekday + 1);
|
||||
}
|
||||
|
||||
return days;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
HTMLInputElement::NumberOfDaysInMonth(uint32_t aMonth, uint32_t aYear) const
|
||||
{
|
||||
|
@ -5251,8 +5348,7 @@ HTMLInputElement::NumberOfDaysInMonth(uint32_t aMonth, uint32_t aYear) const
|
|||
return 30;
|
||||
}
|
||||
|
||||
return (aYear % 400 == 0 || (aYear % 100 != 0 && aYear % 4 == 0))
|
||||
? 29 : 28;
|
||||
return IsLeapYear(aYear) ? 29 : 28;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
|
|
@ -1049,11 +1049,7 @@ protected:
|
|||
/**
|
||||
* Returns if valueAsNumber attribute applies for the current type.
|
||||
*/
|
||||
bool DoesValueAsNumberApply() const
|
||||
{
|
||||
// TODO: this is temporary until bug 888316 is fixed.
|
||||
return DoesMinMaxApply() && mType != NS_FORM_INPUT_WEEK;
|
||||
}
|
||||
bool DoesValueAsNumberApply() const { return DoesMinMaxApply(); }
|
||||
|
||||
/**
|
||||
* Returns if autocomplete attribute applies for the current type.
|
||||
|
@ -1231,6 +1227,12 @@ protected:
|
|||
uint32_t* aMonth,
|
||||
uint32_t* aDay) const;
|
||||
|
||||
/**
|
||||
* This methods returns the number of days since epoch for a given year and
|
||||
* week.
|
||||
*/
|
||||
double DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const;
|
||||
|
||||
/**
|
||||
* This methods returns the number of days in a given month, for a given year.
|
||||
*/
|
||||
|
@ -1243,9 +1245,11 @@ protected:
|
|||
int32_t MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) const;
|
||||
|
||||
/**
|
||||
* This methods returns the day of the week given a date, note that 0 = Sunday.
|
||||
* This methods returns the day of the week given a date. If @isoWeek is true,
|
||||
* 7=Sunday, otherwise, 0=Sunday.
|
||||
*/
|
||||
uint32_t DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay) const;
|
||||
uint32_t DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
|
||||
bool isoWeek) const;
|
||||
|
||||
/**
|
||||
* This methods returns the maximum number of week in a given year, the
|
||||
|
@ -1490,12 +1494,21 @@ protected:
|
|||
// Float value returned by GetStep() when the step attribute is set to 'any'.
|
||||
static const Decimal kStepAny;
|
||||
|
||||
// Maximum year limited by ECMAScript date object range, year <= 275760.
|
||||
static const double kMaximumYear;
|
||||
// Minimum year limited by HTML standard, year >= 1.
|
||||
static const double kMinimumYear;
|
||||
// Maximum year limited by ECMAScript date object range, year <= 275760.
|
||||
static const double kMaximumYear;
|
||||
// Maximum valid week is 275760-W37.
|
||||
static const double kMaximumWeekInMaximumYear;
|
||||
// Maximum valid day is 275760-09-13.
|
||||
static const double kMaximumDayInMaximumYear;
|
||||
// Maximum valid month is 275760-09.
|
||||
static const double kMaximumMonthInMaximumYear;
|
||||
// Long years in a ISO calendar have 53 weeks in them.
|
||||
static const double kMaximumWeekInYear;
|
||||
// Milliseconds in a day.
|
||||
static const double kMsPerDay;
|
||||
|
||||
|
||||
/**
|
||||
* The type of this input (<input type=...>) as an integer.
|
||||
|
|
|
@ -46,8 +46,7 @@ var validTypes =
|
|||
["time", true],
|
||||
["color", false],
|
||||
["month", true],
|
||||
// TODO: temporary set to false until bug 888316 is fixed.
|
||||
["week", false],
|
||||
["week", true],
|
||||
];
|
||||
|
||||
var todoTypes =
|
||||
|
@ -59,7 +58,7 @@ var todoTypes =
|
|||
function checkAvailability()
|
||||
{
|
||||
|
||||
for (data of validTypes) {
|
||||
for (let data of validTypes) {
|
||||
var exceptionCatched = false;
|
||||
element.type = data[0];
|
||||
try {
|
||||
|
@ -80,7 +79,7 @@ function checkAvailability()
|
|||
" availability is not correct");
|
||||
}
|
||||
|
||||
for (data of todoTypes) {
|
||||
for (let data of todoTypes) {
|
||||
var exceptionCatched = false;
|
||||
element.type = data[0];
|
||||
try {
|
||||
|
@ -104,7 +103,7 @@ function checkAvailability()
|
|||
|
||||
function checkGarbageValues()
|
||||
{
|
||||
for (type of validTypes) {
|
||||
for (let type of validTypes) {
|
||||
if (!type[1]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -129,7 +128,7 @@ function checkGarbageValues()
|
|||
"foobar", 42, {}, function() { return 42; }, function() { return Date(); }
|
||||
];
|
||||
|
||||
for (value of illegalValues) {
|
||||
for (let value of illegalValues) {
|
||||
try {
|
||||
var caught = false;
|
||||
element.valueAsDate = value;
|
||||
|
@ -177,14 +176,14 @@ function checkDateGet()
|
|||
];
|
||||
|
||||
element.type = "date";
|
||||
for (data of validData) {
|
||||
for (let data of validData) {
|
||||
element.value = data[0];
|
||||
is(element.valueAsDate.valueOf(), data[1],
|
||||
"valueAsDate should return the " +
|
||||
"valid date object representing this date");
|
||||
}
|
||||
|
||||
for (data of invalidData) {
|
||||
for (let data of invalidData) {
|
||||
element.value = data[0];
|
||||
if (data[1]) {
|
||||
is(String(element.valueAsDate), "Invalid Date",
|
||||
|
@ -225,7 +224,7 @@ function checkDateSet()
|
|||
];
|
||||
|
||||
element.type = "date";
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
element.valueAsDate = new Date(data[0]);
|
||||
is(element.value, data[1], "valueAsDate should set the value to "
|
||||
+ data[1]);
|
||||
|
@ -276,7 +275,7 @@ function checkTimeGet()
|
|||
var element = document.createElement('input');
|
||||
element.type = 'time';
|
||||
|
||||
for (test of tests) {
|
||||
for (let test of tests) {
|
||||
element.value = test.value;
|
||||
if (test.result === null) {
|
||||
is(element.valueAsDate, null, "element.valueAsDate should return null");
|
||||
|
@ -319,7 +318,7 @@ function checkTimeSet()
|
|||
var element = document.createElement('input');
|
||||
element.type = 'time';
|
||||
|
||||
for (test of tests) {
|
||||
for (let test of tests) {
|
||||
element.valueAsDate = new Date(test.value);
|
||||
is(element.value, test.result,
|
||||
"element.value should have been changed by setting valueAsDate");
|
||||
|
@ -328,7 +327,7 @@ function checkTimeSet()
|
|||
|
||||
function checkWithBustedPrototype()
|
||||
{
|
||||
for (type of validTypes) {
|
||||
for (let type of validTypes) {
|
||||
if (!type[1]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -443,14 +442,14 @@ function checkMonthGet()
|
|||
];
|
||||
|
||||
element.type = "month";
|
||||
for (data of validData) {
|
||||
for (let data of validData) {
|
||||
element.value = data[0];
|
||||
is(element.valueAsDate.valueOf(), data[1],
|
||||
"valueAsDate should return the " +
|
||||
"valid date object representing this month");
|
||||
}
|
||||
|
||||
for (data of invalidData) {
|
||||
for (let data of invalidData) {
|
||||
element.value = data[0];
|
||||
if (data[1]) {
|
||||
is(String(element.valueAsDate), "Invalid Date",
|
||||
|
@ -490,7 +489,156 @@ function checkMonthSet()
|
|||
];
|
||||
|
||||
element.type = "month";
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
element.valueAsDate = new Date(data[0]);
|
||||
is(element.value, data[1], "valueAsDate should set the value to "
|
||||
+ data[1]);
|
||||
element.valueAsDate = new testFrame.Date(data[0]);
|
||||
is(element.value, data[1], "valueAsDate with other-global date should " +
|
||||
"set the value to " + data[1]);
|
||||
}
|
||||
}
|
||||
|
||||
function checkWeekGet()
|
||||
{
|
||||
var validData =
|
||||
[
|
||||
// Common years starting on different days of week.
|
||||
[ "2007-W01", Date.UTC(2007, 0, 1) ], // Mon
|
||||
[ "2013-W01", Date.UTC(2012, 11, 31) ], // Tue
|
||||
[ "2014-W01", Date.UTC(2013, 11, 30) ], // Wed
|
||||
[ "2015-W01", Date.UTC(2014, 11, 29) ], // Thu
|
||||
[ "2010-W01", Date.UTC(2010, 0, 4) ], // Fri
|
||||
[ "2011-W01", Date.UTC(2011, 0, 3) ], // Sat
|
||||
[ "2017-W01", Date.UTC(2017, 0, 2) ], // Sun
|
||||
// Common years ending on different days of week.
|
||||
[ "2007-W52", Date.UTC(2007, 11, 24) ], // Mon
|
||||
[ "2013-W52", Date.UTC(2013, 11, 23) ], // Tue
|
||||
[ "2014-W52", Date.UTC(2014, 11, 22) ], // Wed
|
||||
[ "2015-W53", Date.UTC(2015, 11, 28) ], // Thu
|
||||
[ "2010-W52", Date.UTC(2010, 11, 27) ], // Fri
|
||||
[ "2011-W52", Date.UTC(2011, 11, 26) ], // Sat
|
||||
[ "2017-W52", Date.UTC(2017, 11, 25) ], // Sun
|
||||
// Leap years starting on different days of week.
|
||||
[ "1996-W01", Date.UTC(1996, 0, 1) ], // Mon
|
||||
[ "2008-W01", Date.UTC(2007, 11, 31) ], // Tue
|
||||
[ "2020-W01", Date.UTC(2019, 11, 30) ], // Wed
|
||||
[ "2004-W01", Date.UTC(2003, 11, 29) ], // Thu
|
||||
[ "2016-W01", Date.UTC(2016, 0, 4) ], // Fri
|
||||
[ "2000-W01", Date.UTC(2000, 0, 3) ], // Sat
|
||||
[ "2012-W01", Date.UTC(2012, 0, 2) ], // Sun
|
||||
// Leap years ending on different days of week.
|
||||
[ "2012-W52", Date.UTC(2012, 11, 24) ], // Mon
|
||||
[ "2024-W52", Date.UTC(2024, 11, 23) ], // Tue
|
||||
[ "1980-W52", Date.UTC(1980, 11, 22) ], // Wed
|
||||
[ "1992-W53", Date.UTC(1992, 11, 28) ], // Thu
|
||||
[ "2004-W53", Date.UTC(2004, 11, 27) ], // Fri
|
||||
[ "1988-W52", Date.UTC(1988, 11, 26) ], // Sat
|
||||
[ "2000-W52", Date.UTC(2000, 11, 25) ], // Sun
|
||||
// Other normal cases.
|
||||
[ "2016-W36", 1473033600000 ],
|
||||
[ "1969-W52", -864000000 ],
|
||||
[ "1970-W01", -259200000 ],
|
||||
[ "275760-W37", 8639999568000000 ],
|
||||
];
|
||||
|
||||
var invalidData =
|
||||
[
|
||||
[ "invalidweek" ],
|
||||
[ "0000-W01" ],
|
||||
[ "2016-W00" ],
|
||||
[ "123-W01" ],
|
||||
[ "2016-W53" ],
|
||||
[ "" ],
|
||||
// This week is valid for the input element, but is out of
|
||||
// the date object range. In this case, on getting valueAsDate,
|
||||
// a Date object will be created, but it will have a NaN internal value,
|
||||
// and will return the string "Invalid Date".
|
||||
[ "275760-W38", true ],
|
||||
];
|
||||
|
||||
element.type = "week";
|
||||
for (let data of validData) {
|
||||
element.value = data[0];
|
||||
is(element.valueAsDate.valueOf(), data[1],
|
||||
"valueAsDate should return the " +
|
||||
"valid date object representing this week");
|
||||
}
|
||||
|
||||
for (let data of invalidData) {
|
||||
element.value = data[0];
|
||||
if (data[1]) {
|
||||
is(String(element.valueAsDate), "Invalid Date",
|
||||
"valueAsDate should return an invalid Date object " +
|
||||
"when the element value is not a valid week");
|
||||
} else {
|
||||
is(element.valueAsDate, null,
|
||||
"valueAsDate should return null " +
|
||||
"when the element value is not a valid week");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkWeekSet()
|
||||
{
|
||||
var testData =
|
||||
[
|
||||
// Common years starting on different days of week.
|
||||
[ Date.UTC(2007, 0, 1), "2007-W01" ], // Mon
|
||||
[ Date.UTC(2013, 0, 1), "2013-W01" ], // Tue
|
||||
[ Date.UTC(2014, 0, 1), "2014-W01" ], // Wed
|
||||
[ Date.UTC(2015, 0, 1), "2015-W01" ], // Thu
|
||||
[ Date.UTC(2010, 0, 1), "2009-W53" ], // Fri
|
||||
[ Date.UTC(2011, 0, 1), "2010-W52" ], // Sat
|
||||
[ Date.UTC(2017, 0, 1), "2016-W52" ], // Sun
|
||||
// Common years ending on different days of week.
|
||||
[ Date.UTC(2007, 11, 31), "2008-W01" ], // Mon
|
||||
[ Date.UTC(2013, 11, 31), "2014-W01" ], // Tue
|
||||
[ Date.UTC(2014, 11, 31), "2015-W01" ], // Wed
|
||||
[ Date.UTC(2015, 11, 31), "2015-W53" ], // Thu
|
||||
[ Date.UTC(2010, 11, 31), "2010-W52" ], // Fri
|
||||
[ Date.UTC(2011, 11, 31), "2011-W52" ], // Sat
|
||||
[ Date.UTC(2017, 11, 31), "2017-W52" ], // Sun
|
||||
// Leap years starting on different days of week.
|
||||
[ Date.UTC(1996, 0, 1), "1996-W01" ], // Mon
|
||||
[ Date.UTC(2008, 0, 1), "2008-W01" ], // Tue
|
||||
[ Date.UTC(2020, 0, 1), "2020-W01" ], // Wed
|
||||
[ Date.UTC(2004, 0, 1), "2004-W01" ], // Thu
|
||||
[ Date.UTC(2016, 0, 1), "2015-W53" ], // Fri
|
||||
[ Date.UTC(2000, 0, 1), "1999-W52" ], // Sat
|
||||
[ Date.UTC(2012, 0, 1), "2011-W52" ], // Sun
|
||||
// Leap years ending on different days of week.
|
||||
[ Date.UTC(2012, 11, 31), "2013-W01" ], // Mon
|
||||
[ Date.UTC(2024, 11, 31), "2025-W01" ], // Tue
|
||||
[ Date.UTC(1980, 11, 31), "1981-W01" ], // Wed
|
||||
[ Date.UTC(1992, 11, 31), "1992-W53" ], // Thu
|
||||
[ Date.UTC(2004, 11, 31), "2004-W53" ], // Fri
|
||||
[ Date.UTC(1988, 11, 31), "1988-W52" ], // Sat
|
||||
[ Date.UTC(2000, 11, 31), "2000-W52" ], // Sun
|
||||
// Other normal cases.
|
||||
[ Date.UTC(2016, 8, 9), "2016-W36" ],
|
||||
[ Date.UTC(2010, 0, 3), "2009-W53" ],
|
||||
[ Date.UTC(2010, 0, 4), "2010-W01" ],
|
||||
[ Date.UTC(2010, 0, 10), "2010-W01" ],
|
||||
[ Date.UTC(2010, 0, 11), "2010-W02" ],
|
||||
[ 0, "1970-W01" ],
|
||||
// Maximum valid month (limited by the ecma date object range).
|
||||
[ 8640000000000000, "275760-W37" ],
|
||||
// Minimum valid month (limited by the input element minimum valid value).
|
||||
[ -62135596800000 , "0001-W01" ],
|
||||
// "Values must be truncated to valid week"
|
||||
[ 42.1234, "1970-W01" ],
|
||||
[ 123.123456789123, "1970-W01" ],
|
||||
[ 1e-1, "1970-W01" ],
|
||||
[ -1.1, "1970-W01" ],
|
||||
[ -345600000, "1969-W52" ],
|
||||
// Negative years, this is out of range for the input element,
|
||||
// the corresponding week string is the empty string
|
||||
[ -62135596800001, "" ],
|
||||
];
|
||||
|
||||
element.type = "week";
|
||||
for (let data of testData) {
|
||||
element.valueAsDate = new Date(data[0]);
|
||||
is(element.value, data[1], "valueAsDate should set the value to "
|
||||
+ data[1]);
|
||||
|
@ -516,7 +664,12 @@ checkTimeSet();
|
|||
checkMonthGet();
|
||||
checkMonthSet();
|
||||
|
||||
// Test <input type='week'>.
|
||||
checkWeekGet();
|
||||
checkWeekSet();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ function checkAvailability()
|
|||
["color", false],
|
||||
["month", true],
|
||||
// TODO: temporary set to false until bug 888316 is fixed.
|
||||
["week", false],
|
||||
["week", true],
|
||||
];
|
||||
|
||||
var todoList =
|
||||
|
@ -57,7 +57,7 @@ function checkAvailability()
|
|||
|
||||
var element = document.createElement('input');
|
||||
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
var exceptionCatched = false;
|
||||
element.type = data[0];
|
||||
try {
|
||||
|
@ -78,7 +78,7 @@ function checkAvailability()
|
|||
" availability is not correct");
|
||||
}
|
||||
|
||||
for (data of todoList) {
|
||||
for (let data of todoList) {
|
||||
var exceptionCatched = false;
|
||||
element.type = data[0];
|
||||
try {
|
||||
|
@ -122,7 +122,7 @@ function checkNumberGet()
|
|||
|
||||
var element = document.createElement('input');
|
||||
element.type = "number";
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
element.value = data[0];
|
||||
|
||||
// Given that NaN != NaN, we have to use null when the expected value is NaN.
|
||||
|
@ -162,7 +162,7 @@ function checkNumberSet()
|
|||
|
||||
var element = document.createElement('input');
|
||||
element.type = "number";
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
var caught = false;
|
||||
try {
|
||||
element.valueAsNumber = data[0];
|
||||
|
@ -213,7 +213,7 @@ function checkRangeGet()
|
|||
element.setAttribute("min", min); // avoids out of range sanitization
|
||||
element.setAttribute("max", max);
|
||||
element.setAttribute("step", "any"); // avoids step mismatch sanitization
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
element.value = data[0];
|
||||
|
||||
// Given that NaN != NaN, we have to use null when the expected value is NaN.
|
||||
|
@ -253,7 +253,7 @@ function checkRangeSet()
|
|||
element.setAttribute("min", min); // avoids out of range sanitization
|
||||
element.setAttribute("max", max);
|
||||
element.setAttribute("step", "any"); // avoids step mismatch sanitization
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
var caught = false;
|
||||
try {
|
||||
element.valueAsNumber = data[0];
|
||||
|
@ -305,13 +305,13 @@ function checkDateGet()
|
|||
|
||||
var element = document.createElement('input');
|
||||
element.type = "date";
|
||||
for (data of validData) {
|
||||
for (let data of validData) {
|
||||
element.value = data[0];
|
||||
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
|
||||
"timestamp representing this date");
|
||||
}
|
||||
|
||||
for (data of invalidData) {
|
||||
for (let data of invalidData) {
|
||||
element.value = data;
|
||||
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
|
||||
"when the element value is not a valid date");
|
||||
|
@ -361,7 +361,7 @@ function checkDateSet()
|
|||
|
||||
var element = document.createElement('input');
|
||||
element.type = "date";
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
var caught = false;
|
||||
|
||||
try {
|
||||
|
@ -372,7 +372,7 @@ function checkDateSet()
|
|||
}
|
||||
|
||||
if (data[2]) {
|
||||
ok(caught, "valueAsNumber should have trhown");
|
||||
ok(caught, "valueAsNumber should have thrown");
|
||||
is(element.value, data[1], "the value should not have changed");
|
||||
} else {
|
||||
ok(!caught, "valueAsNumber should not have thrown");
|
||||
|
@ -422,7 +422,7 @@ function checkTimeGet()
|
|||
var element = document.createElement('input');
|
||||
element.type = 'time';
|
||||
|
||||
for (test of tests) {
|
||||
for (let test of tests) {
|
||||
element.value = test.value;
|
||||
if (isNaN(test.result)) {
|
||||
ok(isNaN(element.valueAsNumber),
|
||||
|
@ -469,7 +469,7 @@ function checkTimeSet()
|
|||
var element = document.createElement('input');
|
||||
element.type = 'time';
|
||||
|
||||
for (test of tests) {
|
||||
for (let test of tests) {
|
||||
try {
|
||||
var caught = false;
|
||||
element.valueAsNumber = test.value;
|
||||
|
@ -488,7 +488,6 @@ function checkTimeSet()
|
|||
|
||||
function checkMonthGet()
|
||||
{
|
||||
dump("checkMonthGet\n");
|
||||
var validData =
|
||||
[
|
||||
[ "2016-07", 558 ],
|
||||
|
@ -511,13 +510,13 @@ function checkMonthGet()
|
|||
|
||||
var element = document.createElement('input');
|
||||
element.type = "month";
|
||||
for (data of validData) {
|
||||
for (let data of validData) {
|
||||
element.value = data[0];
|
||||
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
|
||||
"integer value representing this month");
|
||||
}
|
||||
|
||||
for (data of invalidData) {
|
||||
for (let data of invalidData) {
|
||||
element.value = data;
|
||||
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
|
||||
"when the element value is not a valid month");
|
||||
|
@ -564,7 +563,7 @@ function checkMonthSet()
|
|||
|
||||
var element = document.createElement('input');
|
||||
element.type = "month";
|
||||
for (data of testData) {
|
||||
for (let data of testData) {
|
||||
var caught = false;
|
||||
|
||||
try {
|
||||
|
@ -575,7 +574,163 @@ function checkMonthSet()
|
|||
}
|
||||
|
||||
if (data[2]) {
|
||||
ok(caught, "valueAsNumber should have trhown");
|
||||
ok(caught, "valueAsNumber should have thrown");
|
||||
is(element.value, data[1], "the value should not have changed");
|
||||
} else {
|
||||
ok(!caught, "valueAsNumber should not have thrown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkWeekGet()
|
||||
{
|
||||
var validData =
|
||||
[
|
||||
// Common years starting on different days of week.
|
||||
[ "2007-W01", Date.UTC(2007, 0, 1) ], // Mon
|
||||
[ "2013-W01", Date.UTC(2012, 11, 31) ], // Tue
|
||||
[ "2014-W01", Date.UTC(2013, 11, 30) ], // Wed
|
||||
[ "2015-W01", Date.UTC(2014, 11, 29) ], // Thu
|
||||
[ "2010-W01", Date.UTC(2010, 0, 4) ], // Fri
|
||||
[ "2011-W01", Date.UTC(2011, 0, 3) ], // Sat
|
||||
[ "2017-W01", Date.UTC(2017, 0, 2) ], // Sun
|
||||
// Common years ending on different days of week.
|
||||
[ "2007-W52", Date.UTC(2007, 11, 24) ], // Mon
|
||||
[ "2013-W52", Date.UTC(2013, 11, 23) ], // Tue
|
||||
[ "2014-W52", Date.UTC(2014, 11, 22) ], // Wed
|
||||
[ "2015-W53", Date.UTC(2015, 11, 28) ], // Thu
|
||||
[ "2010-W52", Date.UTC(2010, 11, 27) ], // Fri
|
||||
[ "2011-W52", Date.UTC(2011, 11, 26) ], // Sat
|
||||
[ "2017-W52", Date.UTC(2017, 11, 25) ], // Sun
|
||||
// Leap years starting on different days of week.
|
||||
[ "1996-W01", Date.UTC(1996, 0, 1) ], // Mon
|
||||
[ "2008-W01", Date.UTC(2007, 11, 31) ], // Tue
|
||||
[ "2020-W01", Date.UTC(2019, 11, 30) ], // Wed
|
||||
[ "2004-W01", Date.UTC(2003, 11, 29) ], // Thu
|
||||
[ "2016-W01", Date.UTC(2016, 0, 4) ], // Fri
|
||||
[ "2000-W01", Date.UTC(2000, 0, 3) ], // Sat
|
||||
[ "2012-W01", Date.UTC(2012, 0, 2) ], // Sun
|
||||
// Leap years ending on different days of week.
|
||||
[ "2012-W52", Date.UTC(2012, 11, 24) ], // Mon
|
||||
[ "2024-W52", Date.UTC(2024, 11, 23) ], // Tue
|
||||
[ "1980-W52", Date.UTC(1980, 11, 22) ], // Wed
|
||||
[ "1992-W53", Date.UTC(1992, 11, 28) ], // Thu
|
||||
[ "2004-W53", Date.UTC(2004, 11, 27) ], // Fri
|
||||
[ "1988-W52", Date.UTC(1988, 11, 26) ], // Sat
|
||||
[ "2000-W52", Date.UTC(2000, 11, 25) ], // Sun
|
||||
// Other normal cases.
|
||||
[ "2015-W53", Date.UTC(2015, 11, 28) ],
|
||||
[ "2016-W36", Date.UTC(2016, 8, 5) ],
|
||||
[ "1970-W01", Date.UTC(1969, 11, 29) ],
|
||||
[ "275760-W37", Date.UTC(275760, 8, 8) ],
|
||||
];
|
||||
|
||||
var invalidData =
|
||||
[
|
||||
"invalidweek",
|
||||
"0000-W01",
|
||||
"2016-W00",
|
||||
"2016-W53",
|
||||
// Out of range.
|
||||
"275760-W38",
|
||||
];
|
||||
|
||||
var element = document.createElement('input');
|
||||
element.type = "week";
|
||||
for (let data of validData) {
|
||||
dump("Test: " + data[0]);
|
||||
element.value = data[0];
|
||||
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
|
||||
"integer value representing this week");
|
||||
}
|
||||
|
||||
for (let data of invalidData) {
|
||||
element.value = data;
|
||||
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
|
||||
"when the element value is not a valid week");
|
||||
}
|
||||
}
|
||||
|
||||
function checkWeekSet()
|
||||
{
|
||||
var testData =
|
||||
[
|
||||
// Common years starting on different days of week.
|
||||
[ Date.UTC(2007, 0, 1), "2007-W01" ], // Mon
|
||||
[ Date.UTC(2013, 0, 1), "2013-W01" ], // Tue
|
||||
[ Date.UTC(2014, 0, 1), "2014-W01" ], // Wed
|
||||
[ Date.UTC(2015, 0, 1), "2015-W01" ], // Thu
|
||||
[ Date.UTC(2010, 0, 1), "2009-W53" ], // Fri
|
||||
[ Date.UTC(2011, 0, 1), "2010-W52" ], // Sat
|
||||
[ Date.UTC(2017, 0, 1), "2016-W52" ], // Sun
|
||||
// Common years ending on different days of week.
|
||||
[ Date.UTC(2007, 11, 31), "2008-W01" ], // Mon
|
||||
[ Date.UTC(2013, 11, 31), "2014-W01" ], // Tue
|
||||
[ Date.UTC(2014, 11, 31), "2015-W01" ], // Wed
|
||||
[ Date.UTC(2015, 11, 31), "2015-W53" ], // Thu
|
||||
[ Date.UTC(2010, 11, 31), "2010-W52" ], // Fri
|
||||
[ Date.UTC(2011, 11, 31), "2011-W52" ], // Sat
|
||||
[ Date.UTC(2017, 11, 31), "2017-W52" ], // Sun
|
||||
// Leap years starting on different days of week.
|
||||
[ Date.UTC(1996, 0, 1), "1996-W01" ], // Mon
|
||||
[ Date.UTC(2008, 0, 1), "2008-W01" ], // Tue
|
||||
[ Date.UTC(2020, 0, 1), "2020-W01" ], // Wed
|
||||
[ Date.UTC(2004, 0, 1), "2004-W01" ], // Thu
|
||||
[ Date.UTC(2016, 0, 1), "2015-W53" ], // Fri
|
||||
[ Date.UTC(2000, 0, 1), "1999-W52" ], // Sat
|
||||
[ Date.UTC(2012, 0, 1), "2011-W52" ], // Sun
|
||||
// Leap years ending on different days of week.
|
||||
[ Date.UTC(2012, 11, 31), "2013-W01" ], // Mon
|
||||
[ Date.UTC(2024, 11, 31), "2025-W01" ], // Tue
|
||||
[ Date.UTC(1980, 11, 31), "1981-W01" ], // Wed
|
||||
[ Date.UTC(1992, 11, 31), "1992-W53" ], // Thu
|
||||
[ Date.UTC(2004, 11, 31), "2004-W53" ], // Fri
|
||||
[ Date.UTC(1988, 11, 31), "1988-W52" ], // Sat
|
||||
[ Date.UTC(2000, 11, 31), "2000-W52" ], // Sun
|
||||
// Other normal cases.
|
||||
[ Date.UTC(2008, 8, 26), "2008-W39" ],
|
||||
[ Date.UTC(2016, 0, 4), "2016-W01" ],
|
||||
[ Date.UTC(2016, 0, 10), "2016-W01" ],
|
||||
[ Date.UTC(2016, 0, 11), "2016-W02" ],
|
||||
// Maximum valid week (limited by the ecma date object range).
|
||||
[ 8640000000000000, "275760-W37" ],
|
||||
// Minimum valid week (limited by the input element minimum valid value)
|
||||
[ -62135596800000, "0001-W01" ],
|
||||
// "Values must be truncated to valid weeks"
|
||||
[ 0.3, "1970-W01" ],
|
||||
[ 1e-1, "1970-W01" ],
|
||||
[ -1.1, "1970-W01" ],
|
||||
[ -345600000, "1969-W52" ],
|
||||
// Invalid numbers.
|
||||
// Those are implicitly converted to numbers
|
||||
[ "", "1970-W01" ],
|
||||
[ true, "1970-W01" ],
|
||||
[ false, "1970-W01" ],
|
||||
[ null, "1970-W01" ],
|
||||
// Those are converted to NaN, the corresponding week string is the empty string
|
||||
[ "invalidweek", "" ],
|
||||
[ NaN, "" ],
|
||||
[ undefined, "" ],
|
||||
// Infinity will keep the current value and throw (so we need to set a current value).
|
||||
[ Date.UTC(2016, 8, 8), "2016-W36" ],
|
||||
[ Infinity, "2016-W36", true ],
|
||||
[ -Infinity, "2016-W36", true ],
|
||||
];
|
||||
|
||||
var element = document.createElement('input');
|
||||
element.type = "week";
|
||||
for (let data of testData) {
|
||||
var caught = false;
|
||||
|
||||
try {
|
||||
element.valueAsNumber = data[0];
|
||||
is(element.value, data[1], "valueAsNumber should set the value to " + data[1]);
|
||||
} catch(e) {
|
||||
caught = true;
|
||||
}
|
||||
|
||||
if (data[2]) {
|
||||
ok(caught, "valueAsNumber should have thrown");
|
||||
is(element.value, data[1], "the value should not have changed");
|
||||
} else {
|
||||
ok(!caught, "valueAsNumber should not have thrown");
|
||||
|
@ -605,6 +760,10 @@ checkTimeSet();
|
|||
checkMonthGet();
|
||||
checkMonthSet();
|
||||
|
||||
// <input type='week'> test
|
||||
checkWeekGet();
|
||||
checkWeekSet();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -149,6 +149,22 @@ MonthFromTime(double time);
|
|||
JS_PUBLIC_API(double)
|
||||
DayFromTime(double time);
|
||||
|
||||
// Takes an integer year and returns the number of days from epoch to the given
|
||||
// year.
|
||||
// NOTE: The calculation performed by this function is literally that given in
|
||||
// the ECMAScript specification. Nonfinite years, years containing fractional
|
||||
// components, and years outside ECMAScript's date range are not handled with
|
||||
// any particular intelligence. Garbage in, garbage out.
|
||||
JS_PUBLIC_API(double)
|
||||
DayFromYear(double year);
|
||||
|
||||
// Takes an integer number of milliseconds since the epoch and an integer year,
|
||||
// returns the number of days in that year. If |time| is nonfinite, returns NaN.
|
||||
// Otherwise |time| *must* correspond to a time within the valid year |year|.
|
||||
// This should usually be ensured by computing |year| as |JS::DayFromYear(time)|.
|
||||
JS_PUBLIC_API(double)
|
||||
DayWithinYear(double time, double year);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif /* js_Date_h */
|
||||
|
|
|
@ -375,6 +375,18 @@ JS::DayFromTime(double time)
|
|||
return DateFromTime(time);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(double)
|
||||
JS::DayFromYear(double year)
|
||||
{
|
||||
return ::DayFromYear(year);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(double)
|
||||
JS::DayWithinYear(double time, double year)
|
||||
{
|
||||
return ::DayWithinYear(time, year);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a year for which any given date will fall on the same weekday.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче