--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1938,185 +1938,21 @@ HTMLInputElement::SetValue(Decimal aValu
if (aValue.isNaN()) {
IgnoredErrorResult rv;
SetValue(EmptyString(), aCallerType, rv);
return;
}
nsAutoString value;
- ConvertNumberToString(aValue, value);
+ mInputType->ConvertNumberToString(aValue, value);
IgnoredErrorResult rv;
SetValue(value, aCallerType, rv);
}
-bool
-HTMLInputElement::ConvertNumberToString(Decimal aValue,
- nsAString& aResultString) const
-{
- MOZ_ASSERT(DoesValueAsNumberApply(),
- "ConvertNumberToString is only implemented for types implementing .valueAsNumber");
- MOZ_ASSERT(aValue.isFinite(),
- "aValue must be a valid non-Infinite number.");
-
- aResultString.Truncate();
-
- switch (mType) {
- case NS_FORM_INPUT_NUMBER:
- case NS_FORM_INPUT_RANGE:
- {
- char buf[32];
- bool ok = aValue.toString(buf, ArrayLength(buf));
- aResultString.AssignASCII(buf);
- MOZ_ASSERT(ok, "buf not big enough");
- return ok;
- }
- case NS_FORM_INPUT_DATE:
- {
- // The specs (and our JS APIs) require |aValue| to be truncated.
- aValue = aValue.floor();
-
- double year = JS::YearFromTime(aValue.toDouble());
- double month = JS::MonthFromTime(aValue.toDouble());
- double day = JS::DayFromTime(aValue.toDouble());
-
- if (IsNaN(year) || IsNaN(month) || IsNaN(day)) {
- return false;
- }
-
- aResultString.AppendPrintf("%04.0f-%02.0f-%02.0f", year,
- month + 1, day);
-
- return true;
- }
- case NS_FORM_INPUT_TIME:
- {
- aValue = aValue.floor();
- // Per spec, we need to truncate |aValue| and we should only represent
- // times inside a day [00:00, 24:00[, which means that we should do a
- // modulo on |aValue| using the number of milliseconds in a day (86400000).
- uint32_t value =
- NS_floorModulo(aValue, Decimal::fromDouble(kMsPerDay)).toDouble();
-
- uint16_t milliseconds, seconds, minutes, hours;
- if (!GetTimeFromMs(value, &hours, &minutes, &seconds, &milliseconds)) {
- return false;
- }
-
- if (milliseconds != 0) {
- aResultString.AppendPrintf("%02d:%02d:%02d.%03d",
- hours, minutes, seconds, milliseconds);
- } else if (seconds != 0) {
- aResultString.AppendPrintf("%02d:%02d:%02d",
- hours, minutes, seconds);
- } else {
- aResultString.AppendPrintf("%02d:%02d", hours, minutes);
- }
-
- return true;
- }
- case NS_FORM_INPUT_MONTH:
- {
- aValue = aValue.floor();
-
- double month = NS_floorModulo(aValue, Decimal(12)).toDouble();
- month = (month < 0 ? month + 12 : month);
-
- double year = 1970 + (aValue.toDouble() - month) / 12;
-
- // Maximum valid month is 275760-09.
- if (year < kMinimumYear || year > kMaximumYear) {
- return false;
- }
-
- if (year == kMaximumYear && month > 8) {
- return false;
- }
-
- 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;
- }
- case NS_FORM_INPUT_DATETIME_LOCAL:
- {
- aValue = aValue.floor();
-
- uint32_t timeValue =
- NS_floorModulo(aValue, Decimal::fromDouble(kMsPerDay)).toDouble();
-
- uint16_t milliseconds, seconds, minutes, hours;
- if (!GetTimeFromMs(timeValue,
- &hours, &minutes, &seconds, &milliseconds)) {
- return false;
- }
-
- double year = JS::YearFromTime(aValue.toDouble());
- double month = JS::MonthFromTime(aValue.toDouble());
- double day = JS::DayFromTime(aValue.toDouble());
-
- if (IsNaN(year) || IsNaN(month) || IsNaN(day)) {
- return false;
- }
-
- if (milliseconds != 0) {
- aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d.%03d",
- year, month + 1, day, hours, minutes,
- seconds, milliseconds);
- } else if (seconds != 0) {
- aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d",
- year, month + 1, day, hours, minutes,
- seconds);
- } else {
- aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d",
- year, month + 1, day, hours, minutes);
- }
-
- return true;
- }
- default:
- MOZ_ASSERT(false, "Unrecognized input type");
- return false;
- }
-}
-
-
Nullable<Date>
HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
{
if (!IsDateTimeInputType(mType)) {
return Nullable<Date>();
}
switch (mType) {
@@ -4141,17 +3977,17 @@ HTMLInputElement::CancelRangeThumbDrag(b
}
if (aIsForUserEvent) {
SetValueOfRangeForUserEvent(mRangeThumbDragStartValue);
} else {
// Don't dispatch an 'input' event - at least not using
// DispatchTrustedEvent.
// TODO: decide what we should do here - bug 851782.
nsAutoString val;
- ConvertNumberToString(mRangeThumbDragStartValue, val);
+ mInputType->ConvertNumberToString(mRangeThumbDragStartValue, val);
// TODO: What should we do if SetValueInternal fails? (The allocation
// is small, so we should be fine here.)
SetValueInternal(val, nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify);
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->UpdateForValueChange();
}
@@ -4164,17 +4000,17 @@ HTMLInputElement::CancelRangeThumbDrag(b
void
HTMLInputElement::SetValueOfRangeForUserEvent(Decimal aValue)
{
MOZ_ASSERT(aValue.isFinite());
Decimal oldValue = GetValueAsDecimal();
nsAutoString val;
- ConvertNumberToString(aValue, val);
+ mInputType->ConvertNumberToString(aValue, val);
// TODO: What should we do if SetValueInternal fails? (The allocation
// is small, so we should be fine here.)
SetValueInternal(val, nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify);
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->UpdateForValueChange();
}
@@ -4267,17 +4103,17 @@ HTMLInputElement::StepNumberControlForUs
nsresult rv = GetValueIfStepped(aDirection, CALLED_FOR_USER_EVENT, &newValue);
if (NS_FAILED(rv) || !newValue.isFinite()) {
return; // value should not or will not change
}
nsAutoString newVal;
- ConvertNumberToString(newValue, newVal);
+ mInputType->ConvertNumberToString(newValue, newVal);
// TODO: What should we do if SetValueInternal fails? (The allocation
// is small, so we should be fine here.)
SetValueInternal(newVal, nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify);
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
static_cast<nsIDOMHTMLInputElement*>(this),
NS_LITERAL_STRING("input"), true,
@@ -5415,39 +5251,16 @@ HTMLInputElement::MaximumWeekInYear(uint
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;
}
bool
-HTMLInputElement::GetTimeFromMs(double aValue, uint16_t* aHours,
- uint16_t* aMinutes, uint16_t* aSeconds,
- uint16_t* aMilliseconds) const {
- MOZ_ASSERT(aValue >= 0 && aValue < kMsPerDay,
- "aValue must be milliseconds within a day!");
-
- uint32_t value = floor(aValue);
-
- *aMilliseconds = value % 1000;
- value /= 1000;
-
- *aSeconds = value % 60;
- value /= 60;
-
- *aMinutes = value % 60;
- value /= 60;
-
- *aHours = value;
-
- return true;
-}
-
-bool
HTMLInputElement::IsValidWeek(const nsAString& aValue) const
{
uint32_t year, week;
return ParseWeek(aValue, &year, &week);
}
bool
HTMLInputElement::IsValidMonth(const nsAString& aValue) const
@@ -7766,33 +7579,33 @@ HTMLInputElement::GetValidationMessage(n
Decimal valueLow = value - NS_floorModulo(value - stepBase, step);
Decimal valueHigh = value + step - NS_floorModulo(value - stepBase, step);
Decimal maximum = GetMaximum();
if (maximum.isNaN() || valueHigh <= maximum) {
nsAutoString valueLowStr, valueHighStr;
- ConvertNumberToString(valueLow, valueLowStr);
- ConvertNumberToString(valueHigh, valueHighStr);
+ mInputType->ConvertNumberToString(valueLow, valueLowStr);
+ mInputType->ConvertNumberToString(valueHigh, valueHighStr);
if (valueLowStr.Equals(valueHighStr)) {
const char16_t* params[] = { valueLowStr.get() };
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
"FormValidationStepMismatchOneValue",
params, message);
} else {
const char16_t* params[] = { valueLowStr.get(), valueHighStr.get() };
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
"FormValidationStepMismatch",
params, message);
}
} else {
nsAutoString valueLowStr;
- ConvertNumberToString(valueLow, valueLowStr);
+ mInputType->ConvertNumberToString(valueLow, valueLowStr);
const char16_t* params[] = { valueLowStr.get() };
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
"FormValidationStepMismatchOneValue",
params, message);
}
aValidationMessage = message;
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1162,29 +1162,16 @@ protected:
* Returns the radio group container if the element has one, null otherwise.
* The radio group container will be the form owner if there is one.
* The current document otherwise.
* @return the radio group container if the element has one, null otherwise.
*/
nsIRadioGroupContainer* GetRadioGroupContainer() const;
/**
- * Convert a Decimal to a string in a type specific way, ie convert a timestamp
- * to a date string if type=date or append the number string representing the
- * value if type=number.
- *
- * @param aValue the Decimal to be converted
- * @param aResultString [out] the string representing the Decimal
- * @return whether the function succeded, it will fail if the current input's
- * type is not supported or the number can't be converted to a string
- * as expected by the type.
- */
- bool ConvertNumberToString(Decimal aValue, nsAString& aResultString) const;
-
- /**
* Parse a color string of the form #XXXXXX where X should be hexa characters
* @param the string to be parsed.
* @return whether the string is a valid simple color.
* Note : this function does not consider the empty string as valid.
*/
bool IsValidSimpleColor(const nsAString& aValue) const;
/**
@@ -1311,23 +1298,16 @@ protected:
/**
* This methods returns the maximum number of week in a given year, the
* result is either 52 or 53.
*/
uint32_t MaximumWeekInYear(uint32_t aYear) const;
/**
- * This method converts aValue (milliseconds within a day) to hours, minutes,
- * seconds and milliseconds.
- */
- bool GetTimeFromMs(double aValue, uint16_t* aHours, uint16_t* aMinutes,
- uint16_t* aSeconds, uint16_t* aMilliseconds) const;
-
- /**
* This methods returns true if it's a leap year.
*/
bool IsLeapYear(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
*
--- a/dom/html/input/DateTimeInputTypes.cpp
+++ b/dom/html/input/DateTimeInputTypes.cpp
@@ -85,16 +85,39 @@ DateTimeInputTypeBase::HasStepMismatch(b
if (step == kStepAny) {
return false;
}
// Value has to be an integral multiple of step.
return NS_floorModulo(value - GetStepBase(), step) != mozilla::Decimal(0);
}
+bool
+DateTimeInputTypeBase::GetTimeFromMs(double aValue, uint16_t* aHours,
+ uint16_t* aMinutes, uint16_t* aSeconds,
+ uint16_t* aMilliseconds) const {
+ MOZ_ASSERT(aValue >= 0 && aValue < kMsPerDay,
+ "aValue must be milliseconds within a day!");
+
+ uint32_t value = floor(aValue);
+
+ *aMilliseconds = value % 1000;
+ value /= 1000;
+
+ *aSeconds = value % 60;
+ value /= 60;
+
+ *aMinutes = value % 60;
+ value /= 60;
+
+ *aHours = value;
+
+ return true;
+}
+
// input type=date
bool
DateInputType::ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const
{
uint32_t year, month, day;
if (!ParseDate(aValue, &year, &month, &day)) {
@@ -105,31 +128,87 @@ DateInputType::ConvertStringToNumber(nsA
if (!time.isValid()) {
return false;
}
aResultValue = mozilla::Decimal::fromDouble(time.toDouble());
return true;
}
+bool
+DateInputType::ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const
+{
+ MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
+
+ aResultString.Truncate();
+
+ // The specs (and our JS APIs) require |aValue| to be truncated.
+ aValue = aValue.floor();
+
+ double year = JS::YearFromTime(aValue.toDouble());
+ double month = JS::MonthFromTime(aValue.toDouble());
+ double day = JS::DayFromTime(aValue.toDouble());
+
+ if (mozilla::IsNaN(year) || mozilla::IsNaN(month) || mozilla::IsNaN(day)) {
+ return false;
+ }
+
+ aResultString.AppendPrintf("%04.0f-%02.0f-%02.0f", year, month + 1, day);
+ return true;
+}
+
// input type=time
bool
TimeInputType::ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const
{
uint32_t milliseconds;
if (!ParseTime(aValue, &milliseconds)) {
return false;
}
aResultValue = mozilla::Decimal(int32_t(milliseconds));
return true;
}
+bool
+TimeInputType::ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const
+{
+ MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
+
+ aResultString.Truncate();
+
+ aValue = aValue.floor();
+ // Per spec, we need to truncate |aValue| and we should only represent
+ // times inside a day [00:00, 24:00[, which means that we should do a
+ // modulo on |aValue| using the number of milliseconds in a day (86400000).
+ uint32_t value =
+ NS_floorModulo(aValue, mozilla::Decimal::fromDouble(kMsPerDay)).toDouble();
+
+ uint16_t milliseconds, seconds, minutes, hours;
+ if (!GetTimeFromMs(value, &hours, &minutes, &seconds, &milliseconds)) {
+ return false;
+ }
+
+ if (milliseconds != 0) {
+ aResultString.AppendPrintf("%02d:%02d:%02d.%03d",
+ hours, minutes, seconds, milliseconds);
+ } else if (seconds != 0) {
+ aResultString.AppendPrintf("%02d:%02d:%02d",
+ hours, minutes, seconds);
+ } else {
+ aResultString.AppendPrintf("%02d:%02d", hours, minutes);
+ }
+
+ return true;
+}
+
// input type=week
bool
WeekInputType::ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const
{
uint32_t year, week;
if (!ParseWeek(aValue, &year, &week)) {
@@ -145,16 +224,58 @@ WeekInputType::ConvertStringToNumber(nsA
return false;
}
double days = DaysSinceEpochFromWeek(year, week);
aResultValue = mozilla::Decimal::fromDouble(days * kMsPerDay);
return true;
}
+bool
+WeekInputType::ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const
+{
+ MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
+
+ aResultString.Truncate();
+
+ 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;
+}
+
// input type=month
bool
MonthInputType::ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const
{
uint32_t year, month;
if (!ParseMonth(aValue, &year, &month)) {
@@ -170,16 +291,45 @@ MonthInputType::ConvertStringToNumber(ns
return false;
}
int32_t months = MonthsSinceJan1970(year, month);
aResultValue = mozilla::Decimal(int32_t(months));
return true;
}
+bool
+MonthInputType::ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const
+{
+ MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
+
+ aResultString.Truncate();
+
+ aValue = aValue.floor();
+
+ double month = NS_floorModulo(aValue, mozilla::Decimal(12)).toDouble();
+ month = (month < 0 ? month + 12 : month);
+
+ double year = 1970 + (aValue.toDouble() - month) / 12;
+
+ // Maximum valid month is 275760-09.
+ if (year < kMinimumYear || year > kMaximumYear) {
+ return false;
+ }
+
+ if (year == kMaximumYear && month > 8) {
+ return false;
+ }
+
+ aResultString.AppendPrintf("%04.0f-%02.0f", year, month + 1);
+ return true;
+
+}
+
// input type=datetime-local
bool
DateTimeLocalInputType::ConvertStringToNumber(
nsAString& aValue, mozilla::Decimal& aResultValue) const
{
uint32_t year, month, day, timeInMs;
if (!ParseDateTimeLocal(aValue, &year, &month, &day, &timeInMs)) {
@@ -190,8 +340,50 @@ DateTimeLocalInputType::ConvertStringToN
timeInMs));
if (!time.isValid()) {
return false;
}
aResultValue = mozilla::Decimal::fromDouble(time.toDouble());
return true;
}
+
+bool
+DateTimeLocalInputType::ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const
+{
+ MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
+
+ aResultString.Truncate();
+
+ aValue = aValue.floor();
+
+ uint32_t timeValue =
+ NS_floorModulo(aValue, mozilla::Decimal::fromDouble(kMsPerDay)).toDouble();
+
+ uint16_t milliseconds, seconds, minutes, hours;
+ if (!GetTimeFromMs(timeValue, &hours, &minutes, &seconds, &milliseconds)) {
+ return false;
+ }
+
+ double year = JS::YearFromTime(aValue.toDouble());
+ double month = JS::MonthFromTime(aValue.toDouble());
+ double day = JS::DayFromTime(aValue.toDouble());
+
+ if (mozilla::IsNaN(year) || mozilla::IsNaN(month) || mozilla::IsNaN(day)) {
+ return false;
+ }
+
+ if (milliseconds != 0) {
+ aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d.%03d",
+ year, month + 1, day, hours, minutes,
+ seconds, milliseconds);
+ } else if (seconds != 0) {
+ aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d",
+ year, month + 1, day, hours, minutes,
+ seconds);
+ } else {
+ aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d",
+ year, month + 1, day, hours, minutes);
+ }
+
+ return true;
+}
--- a/dom/html/input/DateTimeInputTypes.h
+++ b/dom/html/input/DateTimeInputTypes.h
@@ -21,16 +21,23 @@ public:
protected:
explicit DateTimeInputTypeBase(mozilla::dom::HTMLInputElement* aInputElement)
: InputType(aInputElement)
{}
bool IsMutable() const override;
+ /**
+ * This method converts aValue (milliseconds within a day) to hours, minutes,
+ * seconds and milliseconds.
+ */
+ bool GetTimeFromMs(double aValue, uint16_t* aHours, uint16_t* aMinutes,
+ uint16_t* aSeconds, uint16_t* aMilliseconds) const;
+
// 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 month is 275760-09.
static const double kMaximumMonthInMaximumYear;
// Maximum valid week is 275760-W37.
static const double kMaximumWeekInMaximumYear;
@@ -45,16 +52,18 @@ public:
static InputType*
Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
{
return new (aMemory) DateInputType(aInputElement);
}
bool ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const override;
+ bool ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const override;
private:
explicit DateInputType(mozilla::dom::HTMLInputElement* aInputElement)
: DateTimeInputTypeBase(aInputElement)
{}
};
// input type=time
@@ -64,16 +73,18 @@ public:
static InputType*
Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
{
return new (aMemory) TimeInputType(aInputElement);
}
bool ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const override;
+ bool ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const override;
private:
explicit TimeInputType(mozilla::dom::HTMLInputElement* aInputElement)
: DateTimeInputTypeBase(aInputElement)
{}
};
// input type=week
@@ -83,16 +94,18 @@ public:
static InputType*
Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
{
return new (aMemory) WeekInputType(aInputElement);
}
bool ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const override;
+ bool ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const override;
private:
explicit WeekInputType(mozilla::dom::HTMLInputElement* aInputElement)
: DateTimeInputTypeBase(aInputElement)
{}
};
// input type=month
@@ -102,16 +115,18 @@ public:
static InputType*
Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
{
return new (aMemory) MonthInputType(aInputElement);
}
bool ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const override;
+ bool ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const override;
private:
explicit MonthInputType(mozilla::dom::HTMLInputElement* aInputElement)
: DateTimeInputTypeBase(aInputElement)
{}
};
// input type=datetime-local
@@ -121,16 +136,18 @@ public:
static InputType*
Create(mozilla::dom::HTMLInputElement* aInputElement, void* aMemory)
{
return new (aMemory) DateTimeLocalInputType(aInputElement);
}
bool ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const override;
+ bool ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const override;
private:
explicit DateTimeLocalInputType(mozilla::dom::HTMLInputElement* aInputElement)
: DateTimeInputTypeBase(aInputElement)
{}
};
--- a/dom/html/input/InputType.cpp
+++ b/dom/html/input/InputType.cpp
@@ -211,16 +211,25 @@ InputType::ConvertStringToNumber(nsAStri
mozilla::Decimal& aResultValue) const
{
NS_WARNING("InputType::ConvertStringToNumber called");
return false;
}
bool
+InputType::ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const
+{
+ NS_WARNING("InputType::ConvertNumberToString called");
+
+ return false;
+}
+
+bool
InputType::ParseDate(const nsAString& aValue, uint32_t* aYear, uint32_t* aMonth,
uint32_t* aDay) const
{
// TODO: move this function and implementation to DateTimeInpuTypeBase when
// refactoring is completed. Now we can only call HTMLInputElement::ParseDate
// from here, since the method is protected and only InputType is a friend
// class.
return mInputElement->ParseDate(aValue, aYear, aMonth, aDay);
@@ -266,8 +275,23 @@ InputType::MonthsSinceJan1970(uint32_t a
}
double
InputType::DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const
{
// see comment in InputType::ParseDate().
return mInputElement->DaysSinceEpochFromWeek(aYear, aWeek);
}
+
+uint32_t
+InputType::DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
+ bool isoWeek) const
+{
+ // see comment in InputType::ParseDate().
+ return mInputElement->DayOfWeek(aYear, aMonth, aDay, isoWeek);
+}
+
+uint32_t
+InputType::MaximumWeekInYear(uint32_t aYear) const
+{
+ // see comment in InputType::ParseDate().
+ return mInputElement->MaximumWeekInYear(aYear);
+}
--- a/dom/html/input/InputType.h
+++ b/dom/html/input/InputType.h
@@ -69,16 +69,30 @@ public:
* or parse a number string to its value if type=number.
* @param aValue the string to be parsed.
* @param aResultValue the number as a Decimal.
* @result whether the parsing was successful.
*/
virtual bool ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const;
+ /**
+ * Convert a Decimal to a string in a type specific way, ie convert a timestamp
+ * to a date string if type=date or append the number string representing the
+ * value if type=number.
+ *
+ * @param aValue the Decimal to be converted
+ * @param aResultString [out] the string representing the Decimal
+ * @return whether the function succeeded, it will fail if the current input's
+ * type is not supported or the number can't be converted to a string
+ * as expected by the type.
+ */
+ virtual bool ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const;
+
protected:
explicit InputType(mozilla::dom::HTMLInputElement* aInputElement)
: mInputElement(aInputElement)
{}
/**
* Get the mutable state of the element.
* When the element isn't mutable (immutable), the value or checkedness
@@ -191,16 +205,29 @@ protected:
int32_t MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) 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 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,
+ bool isoWeek) const;
+
+ /**
+ * This methods returns the maximum number of week in a given year, the
+ * result is either 52 or 53.
+ */
+ uint32_t MaximumWeekInYear(uint32_t aYear) const;
+
mozilla::dom::HTMLInputElement* mInputElement;
};
// Custom deleter for UniquePtr<InputType> to avoid freeing memory pre-allocated
// for InputType, but we still need to call the destructor explictly.
struct DoNotDelete { void operator()(::InputType* p) { p->~InputType(); } };
#endif /* InputType_h__ */
--- a/dom/html/input/NumericInputTypes.cpp
+++ b/dom/html/input/NumericInputTypes.cpp
@@ -77,16 +77,32 @@ NumericInputTypeBase::ConvertStringToNum
{
aResultValue = mozilla::dom::HTMLInputElement::StringToDecimal(aValue);
if (!aResultValue.isFinite()) {
return false;
}
return true;
}
+bool
+NumericInputTypeBase::ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const
+{
+ MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
+
+ aResultString.Truncate();
+
+ char buf[32];
+ bool ok = aValue.toString(buf, mozilla::ArrayLength(buf));
+ aResultString.AssignASCII(buf);
+ MOZ_ASSERT(ok, "buf not big enough");
+
+ return ok;
+}
+
/* input type=numer */
bool
NumberInputType::IsValueMissing() const
{
if (!mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
return false;
}
--- a/dom/html/input/NumericInputTypes.h
+++ b/dom/html/input/NumericInputTypes.h
@@ -15,16 +15,18 @@ public:
~NumericInputTypeBase() override {}
bool IsRangeOverflow() const override;
bool IsRangeUnderflow() const override;
bool HasStepMismatch(bool aUseZeroIfValueNaN) const override;
bool ConvertStringToNumber(nsAString& aValue,
mozilla::Decimal& aResultValue) const override;
+ bool ConvertNumberToString(mozilla::Decimal aValue,
+ nsAString& aResultString) const override;
protected:
explicit NumericInputTypeBase(mozilla::dom::HTMLInputElement* aInputElement)
: InputType(aInputElement)
{}
};
// input type=number