зеркало из https://github.com/mozilla/gecko-dev.git
Bug 769359 - Adds step attribute and stepUp/stepDown method support for <input type='date'>. r=mounir
This commit is contained in:
Родитель
1b362d7906
Коммит
e9a23b4695
|
@ -88,6 +88,7 @@
|
|||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Util.h" // DebugOnly
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include "nsIIDNService.h"
|
||||
|
||||
|
@ -176,6 +177,8 @@ static const nsAttrValue::EnumTable kInputInputmodeTable[] = {
|
|||
// Default inputmode value is "auto".
|
||||
static const nsAttrValue::EnumTable* kInputDefaultInputmode = &kInputInputmodeTable[0];
|
||||
|
||||
const double nsHTMLInputElement::kStepScaleFactorDate = 86400000;
|
||||
const double nsHTMLInputElement::kStepScaleFactorNumber = 1;
|
||||
const double nsHTMLInputElement::kDefaultStepBase = 0;
|
||||
const double nsHTMLInputElement::kStepAny = 0;
|
||||
|
||||
|
@ -1201,43 +1204,54 @@ void
|
|||
nsHTMLInputElement::SetValue(double aValue)
|
||||
{
|
||||
nsAutoString value;
|
||||
ConvertNumberToString(aValue, value);
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::ConvertNumberToString(double aValue,
|
||||
nsAString& aResultString) const
|
||||
{
|
||||
MOZ_ASSERT(mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_NUMBER,
|
||||
"ConvertNumberToString is only implemented for type='{number,date}'");
|
||||
|
||||
aResultString.Truncate();
|
||||
|
||||
switch (mType) {
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
value.AppendFloat(aValue);
|
||||
break;
|
||||
aResultString.AppendFloat(aValue);
|
||||
return true;
|
||||
case NS_FORM_INPUT_DATE:
|
||||
{
|
||||
value.Truncate();
|
||||
JSContext* ctx = nsContentUtils::GetContextFromDocument(OwnerDoc());
|
||||
if (!ctx) {
|
||||
break;
|
||||
}
|
||||
{
|
||||
JSContext* ctx = nsContentUtils::GetContextFromDocument(OwnerDoc());
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject* date = JS_NewDateObjectMsec(ctx, aValue);
|
||||
if (!date) {
|
||||
break;
|
||||
}
|
||||
// The specs require |aValue| to be truncated.
|
||||
aValue = floor(aValue);
|
||||
|
||||
jsval year, month, day;
|
||||
if(!JS::Call(ctx, date, "getUTCFullYear", 0, nullptr, &year)) {
|
||||
break;
|
||||
}
|
||||
JSObject* date = JS_NewDateObjectMsec(ctx, aValue);
|
||||
if (!date) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!JS::Call(ctx, date, "getUTCMonth", 0, nullptr, &month)) {
|
||||
break;
|
||||
}
|
||||
jsval year, month, day;
|
||||
if (!JS::Call(ctx, date, "getUTCFullYear", 0, nullptr, &year) ||
|
||||
!JS::Call(ctx, date, "getUTCMonth", 0, nullptr, &month) ||
|
||||
!JS::Call(ctx, date, "getUTCDate", 0, nullptr, &day)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!JS::Call(ctx, date, "getUTCDate", 0, nullptr, &day)) {
|
||||
break;
|
||||
}
|
||||
aResultString.AppendPrintf("%04.0f-%02.0f-%02.0f", year.toNumber(),
|
||||
month.toNumber() + 1, day.toNumber());
|
||||
|
||||
value.AppendPrintf("%04.0f-%02.0f-%02.0f", year.toNumber(),
|
||||
month.toNumber() + 1, day.toNumber());
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
MOZ_NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1415,6 +1429,21 @@ nsHTMLInputElement::ApplyStep(int32_t aStep)
|
|||
|
||||
value += aStep * step;
|
||||
|
||||
// For date inputs, the value can hold a string that is not a day. We do not
|
||||
// want to round it, as it might result in a step mismatch. Instead we want to
|
||||
// clamp to the next valid value.
|
||||
if (mType == NS_FORM_INPUT_DATE &&
|
||||
NS_floorModulo(value - GetStepBase(), GetStepScaleFactor()) != 0) {
|
||||
double validStep = EuclidLCM<uint64_t>(static_cast<uint64_t>(step),
|
||||
static_cast<uint64_t>(GetStepScaleFactor()));
|
||||
if (aStep > 0) {
|
||||
value -= NS_floorModulo(value - GetStepBase(), validStep);
|
||||
value += validStep;
|
||||
} else if (aStep < 0) {
|
||||
value -= NS_floorModulo(value - GetStepBase(), validStep);
|
||||
}
|
||||
}
|
||||
|
||||
// When stepUp() is called and the value is below min, we should clamp on
|
||||
// min unless stepUp() moves us higher than min.
|
||||
if (GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW) && aStep > 0 &&
|
||||
|
@ -4255,11 +4284,10 @@ nsHTMLInputElement::DoesMinMaxApply() const
|
|||
double
|
||||
nsHTMLInputElement::GetStep() const
|
||||
{
|
||||
NS_ASSERTION(mType == NS_FORM_INPUT_NUMBER,
|
||||
"We can't be there if type!=number!");
|
||||
MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE,
|
||||
"We can't be there if type!=number or date!");
|
||||
|
||||
// NOTE: should be defaultStep * defaultStepScaleFactor,
|
||||
// which is 1 for type=number.
|
||||
// NOTE: should be defaultStep, which is 1 for type=number and date.
|
||||
double step = 1;
|
||||
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::step)) {
|
||||
|
@ -4272,17 +4300,16 @@ nsHTMLInputElement::GetStep() const
|
|||
}
|
||||
|
||||
nsresult ec;
|
||||
// NOTE: should be multiplied by defaultStepScaleFactor,
|
||||
// which is 1 for type=number.
|
||||
step = stepStr.ToDouble(&ec);
|
||||
if (NS_FAILED(ec) || step <= 0) {
|
||||
// NOTE: we should use defaultStep * defaultStepScaleFactor,
|
||||
// which is 1 for type=number.
|
||||
// NOTE: we should use defaultStep, which is 1 for type=number and date.
|
||||
step = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return step;
|
||||
// TODO: This multiplication can lead to inexact results, we should use a
|
||||
// type that supports a better precision than double. Bug 783607.
|
||||
return step * GetStepScaleFactor();
|
||||
}
|
||||
|
||||
// nsIConstraintValidation
|
||||
|
@ -4473,6 +4500,15 @@ nsHTMLInputElement::HasStepMismatch() const
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mType == NS_FORM_INPUT_DATE) {
|
||||
// The multiplication by the stepScaleFactor for date can easily lead
|
||||
// to precision loss, since in most use cases this value should be
|
||||
// an integer (millisecond precision), we can get rid of the precision
|
||||
// loss by rounding step. This will however lead to erroneous results
|
||||
// when step was intented to have a precision superior to a millisecond.
|
||||
step = NS_round(step);
|
||||
}
|
||||
|
||||
// Value has to be an integral multiple of step.
|
||||
return NS_floorModulo(value - GetStepBase(), step) != 0;
|
||||
}
|
||||
|
@ -4748,6 +4784,16 @@ nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
|||
double step = GetStep();
|
||||
MOZ_ASSERT(step != kStepAny);
|
||||
|
||||
// In case this is a date and the step is not an integer, we don't want to
|
||||
// display the dates corresponding to the truncated timestamps of valueLow
|
||||
// and valueHigh because they might suffer from a step mismatch as well.
|
||||
// Instead we want the timestamps to correspond to a rounded day. That is,
|
||||
// we want a multiple of the step scale factor (1 day) as well as of step.
|
||||
if (mType == NS_FORM_INPUT_DATE) {
|
||||
step = EuclidLCM<uint64_t>(static_cast<uint64_t>(step),
|
||||
static_cast<uint64_t>(GetStepScaleFactor()));
|
||||
}
|
||||
|
||||
double stepBase = GetStepBase();
|
||||
|
||||
double valueLow = value - NS_floorModulo(value - stepBase, step);
|
||||
|
@ -4757,8 +4803,8 @@ nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
|||
|
||||
if (MOZ_DOUBLE_IS_NaN(max) || valueHigh <= max) {
|
||||
nsAutoString valueLowStr, valueHighStr;
|
||||
valueLowStr.AppendFloat(valueLow);
|
||||
valueHighStr.AppendFloat(valueHigh);
|
||||
ConvertNumberToString(valueLow, valueLowStr);
|
||||
ConvertNumberToString(valueHigh, valueHighStr);
|
||||
|
||||
const PRUnichar* params[] = { valueLowStr.get(), valueHighStr.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
|
@ -4766,7 +4812,7 @@ nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
|||
params, message);
|
||||
} else {
|
||||
nsAutoString valueLowStr;
|
||||
valueLowStr.AppendFloat(valueLow);
|
||||
ConvertNumberToString(valueLow, valueLowStr);
|
||||
|
||||
const PRUnichar* params[] = { valueLowStr.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
|
@ -5183,6 +5229,22 @@ nsHTMLInputElement::GetFilterFromAccept()
|
|||
return filter;
|
||||
}
|
||||
|
||||
double
|
||||
nsHTMLInputElement::GetStepScaleFactor() const
|
||||
{
|
||||
MOZ_ASSERT(DoesStepApply());
|
||||
|
||||
switch (mType) {
|
||||
case NS_FORM_INPUT_DATE:
|
||||
return kStepScaleFactorDate;
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
return kStepScaleFactorNumber;
|
||||
default:
|
||||
MOZ_NOT_REACHED();
|
||||
return MOZ_DOUBLE_NaN();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLInputElement::UpdateValidityUIBits(bool aIsFocused)
|
||||
{
|
||||
|
|
|
@ -571,6 +571,19 @@ protected:
|
|||
*/
|
||||
bool ConvertStringToNumber(nsAString& aValue, double& aResultValue) const;
|
||||
|
||||
/**
|
||||
* Convert a double 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 double to be converted
|
||||
* @param aResultString [out] the string representing the double
|
||||
* @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(double aValue, nsAString& aResultString) const;
|
||||
|
||||
/**
|
||||
* Parse a date string of the form yyyy-mm-dd
|
||||
* @param the string to be parsed.
|
||||
|
@ -619,6 +632,13 @@ protected:
|
|||
*/
|
||||
double GetMaxAsDouble() const;
|
||||
|
||||
/**
|
||||
* Get the step scale value for the current type.
|
||||
* See:
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/common-input-element-attributes.html#concept-input-step-scale
|
||||
*/
|
||||
double GetStepScaleFactor() const;
|
||||
|
||||
/**
|
||||
* Returns the current step value.
|
||||
* Returns kStepAny if the current step is "any" string.
|
||||
|
@ -688,6 +708,10 @@ protected:
|
|||
*/
|
||||
nsString mFocusedValue;
|
||||
|
||||
// Step scale factor values, for input types that have one.
|
||||
static const double kStepScaleFactorDate;
|
||||
static const double kStepScaleFactorNumber;
|
||||
|
||||
// Default step base value when a type do not have specific one.
|
||||
static const double kDefaultStepBase;
|
||||
// Float alue returned by GetStep() when the step attribute is set to 'any'.
|
||||
|
|
|
@ -28,7 +28,7 @@ var types = [
|
|||
[ 'email', false ],
|
||||
[ 'password', false ],
|
||||
[ 'datetime', true, true ],
|
||||
[ 'date', true, true ],
|
||||
[ 'date', true ],
|
||||
[ 'month', true, true ],
|
||||
[ 'week', true, true ],
|
||||
[ 'time', true, true ],
|
||||
|
@ -115,6 +115,132 @@ for (var data of types) {
|
|||
checkValidity(input, true, apply);
|
||||
|
||||
file.remove(false);
|
||||
} else if (input.type == 'date') {
|
||||
// For date, the step is calulated on the timestamp since 1970-01-01
|
||||
// which mean that for all dates prior to the epoch, this timestamp is < 0
|
||||
// and the behavior might differ, therefore we have to test for these cases.
|
||||
|
||||
// When step is 1 every date is valid
|
||||
input.value = '2012-07-05';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = 'foo';
|
||||
input.value = '1970-01-01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '-1';
|
||||
input.value = '1969-12-12';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.removeAttribute('step');
|
||||
input.value = '1500-01-01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = 'any';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = 'aNy';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = 'AnY';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = 'ANY';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
// When min is set to a valid date, there is a step base.
|
||||
input.min = '2008-02-28';
|
||||
input.step = '2';
|
||||
input.value = '2008-03-01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '2008-02-29';
|
||||
checkValidity(input, false, apply, { low: "2008-02-28", high: "2008-03-01" });
|
||||
|
||||
input.min = '2008-02-27';
|
||||
input.value = '2008-02-28';
|
||||
checkValidity(input, false, apply, { low: "2008-02-27", high: "2008-02-29" });
|
||||
|
||||
input.min = '2009-02-27';
|
||||
input.value = '2009-02-28';
|
||||
checkValidity(input, false, apply, { low: "2009-02-27", high: "2009-03-01" });
|
||||
|
||||
input.min = '2009-02-01';
|
||||
input.step = '1.1';
|
||||
input.value = '2009-02-02';
|
||||
checkValidity(input, false, apply, { low: "2009-02-01", high: "2009-02-12" });
|
||||
|
||||
// Without any step attribute the date is valid
|
||||
input.removeAttribute('step');
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.min = '1950-01-01';
|
||||
input.step = '366';
|
||||
input.value = '1951-01-01';
|
||||
checkValidity(input, false, apply, { low: "1950-01-01", high: "1951-01-02" });
|
||||
|
||||
input.min = '1951-01-01';
|
||||
input.step = '365';
|
||||
input.value = '1952-01-01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '0.9';
|
||||
input.value = '1951-01-02';
|
||||
checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-10" });
|
||||
|
||||
input.value = '1951-01-10'
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '0.5';
|
||||
input.value = '1951-01-02';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '1.5';
|
||||
input.value = '1951-01-03';
|
||||
checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-04" });
|
||||
|
||||
input.value = '1951-01-08';
|
||||
checkValidity(input, false, apply, { low: "1951-01-07", high: "1951-01-10" });
|
||||
|
||||
input.step = '3000';
|
||||
input.min= '1968-01-01';
|
||||
input.value = '1968-05-12';
|
||||
checkValidity(input, false, apply, { low: "1968-01-01", high: "1976-03-19" });
|
||||
|
||||
input.value = '1971-01-01';
|
||||
checkValidity(input, false, apply, { low: "1968-01-01", high: "1976-03-19" });
|
||||
|
||||
input.value = '1991-01-01';
|
||||
checkValidity(input, false, apply, { low: "1984-06-05", high: "1992-08-22" });
|
||||
|
||||
input.value = '1984-06-05';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '1992-08-22';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '1.1';
|
||||
input.min = '1991-01-01';
|
||||
input.value = '1991-01-01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '1991-01-02';
|
||||
checkValidity(input, false, apply, { low: "1991-01-01", high: "1991-01-12" });
|
||||
|
||||
input.value = '1991-01-12';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '1.1';
|
||||
input.min = '1969-12-20';
|
||||
input.value = '1969-12-20';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '1969-12-21';
|
||||
checkValidity(input, false, apply, { low: "1969-12-20", high: "1969-12-31" });
|
||||
|
||||
input.value = '1969-12-31';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
} else {
|
||||
// When step=0, the allowed step is 1.
|
||||
input.value = '1.2';
|
||||
|
|
|
@ -47,6 +47,7 @@ function checkAvailability()
|
|||
["reset", false],
|
||||
["button", false],
|
||||
["number", true],
|
||||
["date", true],
|
||||
// The next types have not been implemented but will fallback to "text"
|
||||
// which has the same value.
|
||||
["color", false],
|
||||
|
@ -55,7 +56,6 @@ function checkAvailability()
|
|||
var todoList =
|
||||
[
|
||||
["datetime", true],
|
||||
["date", true],
|
||||
["month", true],
|
||||
["week", true],
|
||||
["time", true],
|
||||
|
@ -107,12 +107,13 @@ function checkAvailability()
|
|||
}
|
||||
}
|
||||
|
||||
function checkStepDownForNumber()
|
||||
function checkStepDown()
|
||||
{
|
||||
// This testData is very similar to the one in checkStepUpForNumber
|
||||
// with some changes relative to stepDown.
|
||||
// This testData is very similar to the one in checkStepUp with some changes
|
||||
// relative to stepDown.
|
||||
var testData = [
|
||||
/* Initial value | step | min | max | stepDown arg | final value | exception */
|
||||
{ type: 'number', data: [
|
||||
// Regular case.
|
||||
[ '1', null, null, null, null, '0', false ],
|
||||
// Argument testing.
|
||||
|
@ -178,54 +179,124 @@ function checkStepDownForNumber()
|
|||
[ '0', 'aNy', null, null, 1, null, true ],
|
||||
// With @value = step base.
|
||||
[ '1', '2', null, null, null, '-1', false ],
|
||||
]},
|
||||
{ type: 'date', data: [
|
||||
// Regular case.
|
||||
[ '2012-07-09', null, null, null, null, '2012-07-08', false ],
|
||||
// Argument testing.
|
||||
[ '2012-07-09', null, null, null, 1, '2012-07-08', false ],
|
||||
[ '2012-07-09', null, null, null, 5, '2012-07-04', false ],
|
||||
[ '2012-07-09', null, null, null, -1, '2012-07-10', false ],
|
||||
[ '2012-07-09', null, null, null, 0, '2012-07-09', false ],
|
||||
// Month/Year wrapping.
|
||||
[ '2012-08-01', null, null, null, 1, '2012-07-31', false ],
|
||||
[ '1969-01-02', null, null, null, 4, '1968-12-29', false ],
|
||||
[ '1969-01-01', null, null, null, -365, '1970-01-01', false ],
|
||||
[ '2012-02-29', null, null, null, -1, '2012-03-01', false ],
|
||||
// Float values are rounded to integer (1.1 -> 1).
|
||||
[ '2012-01-02', null, null, null, 1.1, '2012-01-01', false ],
|
||||
[ '2012-01-02', null, null, null, 1.9, '2012-01-01', false ],
|
||||
// With step values.
|
||||
[ '2012-01-03', '0.5', null, null, null, '2012-01-02', false ],
|
||||
[ '2012-01-02', '0.5', null, null, null, '2012-01-01', false ],
|
||||
[ '2012-01-01', '2', null, null, null, '2011-12-30', false ],
|
||||
[ '2012-01-02', '0.25',null, null, 4, '2012-01-01', false ],
|
||||
[ '2012-01-15', '1.1', '2012-01-01', null, 1, '2012-01-12', false ],
|
||||
[ '2012-01-12', '1.1', '2012-01-01', null, 2, '2012-01-01', false ],
|
||||
[ '2012-01-23', '1.1', '2012-01-01', null, 10, '2012-01-12', false ],
|
||||
[ '2012-01-23', '1.1', '2012-01-01', null, 11, '2012-01-01', false ],
|
||||
[ '1968-01-12', '1.1', '1968-01-01', null, 8, '1968-01-01', false ],
|
||||
// step = 0 isn't allowed (-> step = 1).
|
||||
[ '2012-01-02', '0', null, null, null, '2012-01-01', false ],
|
||||
// step < 0 isn't allowed (-> step = 1).
|
||||
[ '2012-01-02', '-1', null, null, null, '2012-01-01', false ],
|
||||
// step = NaN isn't allowed (-> step = 1).
|
||||
[ '2012-01-02', 'foo', null, null, null, '2012-01-01', false ],
|
||||
// Min values testing.
|
||||
[ '2012-01-03', '1', 'foo', null, 2, '2012-01-01', false ],
|
||||
[ '2012-01-02', '1', '2012-01-01', null, null, '2012-01-01', false ],
|
||||
[ '2012-01-01', '1', '2012-01-01', null, null, '2012-01-01', false ],
|
||||
[ '2012-01-01', '1', '2012-01-10', null, 1, '2012-01-01', false ],
|
||||
[ '2012-01-05', '3', '2012-01-01', null, null, '2012-01-04', false ],
|
||||
[ '1969-01-01', '5', '1969-01-01', '1969-01-02', null, '1969-01-01', false ],
|
||||
// Max values testing.
|
||||
[ '2012-01-02', '1', null, 'foo', null, '2012-01-01', false ],
|
||||
[ '2012-01-02', null, null, '2012-01-05', null, '2012-01-01', false ],
|
||||
[ '2012-01-03', null, null, '2012-01-03', null, '2012-01-02', false ],
|
||||
[ '2012-01-07', null, null, '2012-01-04', 4, '2012-01-03', false ],
|
||||
[ '2012-01-07', '2', null, '2012-01-04', 3, '2012-01-01', false ],
|
||||
// Step mismatch.
|
||||
[ '2012-01-04', '2', '2012-01-01', null, null, '2012-01-03', false ],
|
||||
[ '2012-01-06', '2', '2012-01-01', null, 2, '2012-01-03', false ],
|
||||
[ '2012-01-05', '2', '2012-01-04', '2012-01-08', null, '2012-01-04', false ],
|
||||
[ '1970-01-04', '2', null, null, null, '1970-01-03', false ],
|
||||
[ '1970-01-09', '3', null, null, null, '1970-01-07', false ],
|
||||
// Clamping.
|
||||
[ '2012-05-01', null, null, '2012-01-05', null, '2012-01-05', false ],
|
||||
[ '1970-01-05', '2', '1970-01-02', '1970-01-05', null, '1970-01-04', false ],
|
||||
[ '1970-01-01', '5', '1970-01-02', '1970-01-09', 10, '1970-01-01', false ],
|
||||
[ '1970-01-07', '5', '1969-12-27', '1970-01-06', 2, '1970-01-01', false ],
|
||||
[ '1970-03-08', '3', '1970-02-01', '1970-02-07', 15, '1970-02-01', false ],
|
||||
[ '1970-01-10', '3', '1970-01-01', '1970-01-06', 2, '1970-01-04', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '', false ],
|
||||
// With step = 'any'.
|
||||
[ '2012-01-01', 'any', null, null, 1, null, true ],
|
||||
[ '2012-01-01', 'ANY', null, null, 1, null, true ],
|
||||
[ '2012-01-01', 'AnY', null, null, 1, null, true ],
|
||||
[ '2012-01-01', 'aNy', null, null, 1, null, true ],
|
||||
]},
|
||||
];
|
||||
|
||||
for (var data of testData) {
|
||||
var element = document.createElement("input");
|
||||
element.type = 'number';
|
||||
for (var test of testData) {
|
||||
for (var data of test.data) {
|
||||
var element = document.createElement("input");
|
||||
element.type = test.type;
|
||||
|
||||
if (data[0] != null) {
|
||||
element.setAttribute('value', data[0]);
|
||||
}
|
||||
|
||||
if (data[1] != null) {
|
||||
element.step = data[1];
|
||||
}
|
||||
|
||||
if (data[2] != null) {
|
||||
element.min = data[2];
|
||||
}
|
||||
|
||||
if (data[3] != null) {
|
||||
element.max = data[3];
|
||||
}
|
||||
|
||||
var exceptionCaught = false;
|
||||
try {
|
||||
if (data[4] != null) {
|
||||
element.stepDown(data[4]);
|
||||
} else {
|
||||
element.stepDown();
|
||||
if (data[0] != null) {
|
||||
element.setAttribute('value', data[0]);
|
||||
}
|
||||
|
||||
is(element.value, data[5], "The value should be " + data[5]);
|
||||
} catch (e) {
|
||||
exceptionCaught = true;
|
||||
is(element.value, data[0], e.name + "The value should not have changed");
|
||||
is(e.name, 'InvalidStateError',
|
||||
"It should be a InvalidStateError exception.");
|
||||
} finally {
|
||||
is(exceptionCaught, data[6], "exception status should be " + data[6]);
|
||||
if (data[1] != null) {
|
||||
element.step = data[1];
|
||||
}
|
||||
|
||||
if (data[2] != null) {
|
||||
element.min = data[2];
|
||||
}
|
||||
|
||||
if (data[3] != null) {
|
||||
element.max = data[3];
|
||||
}
|
||||
|
||||
var exceptionCaught = false;
|
||||
try {
|
||||
if (data[4] != null) {
|
||||
element.stepDown(data[4]);
|
||||
} else {
|
||||
element.stepDown();
|
||||
}
|
||||
|
||||
is(element.value, data[5], "The value should be " + data[5]);
|
||||
} catch (e) {
|
||||
exceptionCaught = true;
|
||||
is(element.value, data[0], e.name + "The value should not have changed");
|
||||
is(e.name, 'InvalidStateError',
|
||||
"It should be a InvalidStateError exception.");
|
||||
} finally {
|
||||
is(exceptionCaught, data[6], "exception status should be " + data[6]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkStepUpForNumber()
|
||||
function checkStepUp()
|
||||
{
|
||||
// This testData is very similar to the one in checkStepDownForNumber
|
||||
// with some changes relative to stepUp.
|
||||
// This testData is very similar to the one in checkStepDown with some changes
|
||||
// relative to stepUp.
|
||||
var testData = [
|
||||
/* Initial value | step | min | max | stepUp arg | final value | exception */
|
||||
{ type: 'number', data: [
|
||||
// Regular case.
|
||||
[ '1', null, null, null, null, '2', false ],
|
||||
// Argument testing.
|
||||
|
@ -288,44 +359,116 @@ function checkStepUpForNumber()
|
|||
[ '0', 'aNy', null, null, 1, null, true ],
|
||||
// With @value = step base.
|
||||
[ '1', '2', null, null, null, '3', false ],
|
||||
]},
|
||||
{ type: 'date', data: [
|
||||
// Regular case.
|
||||
[ '2012-07-09', null, null, null, null, '2012-07-10', false ],
|
||||
// Argument testing.
|
||||
[ '2012-07-09', null, null, null, 1, '2012-07-10', false ],
|
||||
[ '2012-07-09', null, null, null, 9, '2012-07-18', false ],
|
||||
[ '2012-07-09', null, null, null, -1, '2012-07-08', false ],
|
||||
[ '2012-07-09', null, null, null, 0, '2012-07-09', false ],
|
||||
// Month/Year wrapping.
|
||||
[ '2012-07-31', null, null, null, 1, '2012-08-01', false ],
|
||||
[ '1968-12-29', null, null, null, 4, '1969-01-02', false ],
|
||||
[ '1970-01-01', null, null, null, -365, '1969-01-01', false ],
|
||||
[ '2012-03-01', null, null, null, -1, '2012-02-29', false ],
|
||||
// Float values are rounded to integer (1.1 -> 1).
|
||||
[ '2012-01-01', null, null, null, 1.1, '2012-01-02', false ],
|
||||
[ '2012-01-01', null, null, null, 1.9, '2012-01-02', false ],
|
||||
// With step values.
|
||||
[ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ],
|
||||
[ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ],
|
||||
[ '2012-01-01', '2', null, null, null, '2012-01-03', false ],
|
||||
[ '2012-01-01', '0.25', null, null, 4, '2012-01-02', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 1, '2012-01-12', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 2, '2012-01-12', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 10, '2012-01-12', false ],
|
||||
[ '2012-01-01', '1.1', '2012-01-01', null, 11, '2012-01-23', false ],
|
||||
[ '1968-01-01', '1.1', '1968-01-01', null, 8, '1968-01-12', false ],
|
||||
// step = 0 isn't allowed (-> step = 1).
|
||||
[ '2012-01-01', '0', null, null, null, '2012-01-02', false ],
|
||||
// step < 0 isn't allowed (-> step = 1).
|
||||
[ '2012-01-01', '-1', null, null, null, '2012-01-02', false ],
|
||||
// step = NaN isn't allowed (-> step = 1).
|
||||
[ '2012-01-01', 'foo', null, null, null, '2012-01-02', false ],
|
||||
// Min values testing.
|
||||
[ '2012-01-01', '1', 'foo', null, null, '2012-01-02', false ],
|
||||
[ '2012-01-01', null, '2011-12-01', null, null, '2012-01-02', false ],
|
||||
[ '2012-01-01', null, '2012-01-02', null, null, '2012-01-02', false ],
|
||||
[ '2012-01-01', null, '2012-01-01', null, null, '2012-01-02', false ],
|
||||
[ '2012-01-01', null, '2012-01-04', null, 4, '2012-01-05', false ],
|
||||
[ '2012-01-01', '2', '2012-01-04', null, 3, '2012-01-06', false ],
|
||||
// Max values testing.
|
||||
[ '2012-01-01', '1', null, 'foo', 2, '2012-01-03', false ],
|
||||
[ '2012-01-01', '1', null, '2012-01-10', 1, '2012-01-02', false ],
|
||||
[ '2012-01-02', null, null, '2012-01-01', null, '2012-01-02', false ],
|
||||
[ '2012-01-02', null, null, '2012-01-02', null, '2012-01-02', false ],
|
||||
[ '2012-01-02', null, null, '2012-01-02', null, '2012-01-02', false ],
|
||||
[ '1969-01-02', '5', '1969-01-01', '1969-01-02', null, '1969-01-02', false ],
|
||||
// Step mismatch.
|
||||
[ '2012-01-02', '2', '2012-01-01', null, null, '2012-01-03', false ],
|
||||
[ '2012-01-02', '2', '2012-01-01', null, 2, '2012-01-05', false ],
|
||||
[ '2012-01-05', '2', '2012-01-01', '2012-01-06', null, '2012-01-05', false ],
|
||||
[ '1970-01-02', '2', null, null, null, '1970-01-03', false ],
|
||||
[ '1970-01-05', '3', null, null, null, '1970-01-07', false ],
|
||||
[ '1970-01-03', '3', null, null, null, '1970-01-04', false ],
|
||||
[ '1970-01-03', '3', '1970-01-02', null, null, '1970-01-05', false ],
|
||||
// Clamping.
|
||||
[ '2012-01-01', null, '2012-01-31', null, null, '2012-01-31', false ],
|
||||
[ '1970-01-02', '2', '1970-01-01', '1970-01-04', null, '1970-01-03', false ],
|
||||
[ '1970-01-01', '5', '1970-01-02', '1970-01-09', 10, '1970-01-07', false ],
|
||||
[ '1969-12-28', '5', '1969-12-29', '1970-01-06', 3, '1970-01-03', false ],
|
||||
[ '1970-01-01', '3', '1970-02-01', '1970-02-07', 15, '1970-02-07', false ],
|
||||
[ '1970-01-01', '3', '1970-01-01', '1970-01-06', 2, '1970-01-04', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '', false ],
|
||||
// With step = 'any'.
|
||||
[ '2012-01-01', 'any', null, null, 1, null, true ],
|
||||
[ '2012-01-01', 'ANY', null, null, 1, null, true ],
|
||||
[ '2012-01-01', 'AnY', null, null, 1, null, true ],
|
||||
[ '2012-01-01', 'aNy', null, null, 1, null, true ],
|
||||
]},
|
||||
];
|
||||
|
||||
for (var data of testData) {
|
||||
var element = document.createElement("input");
|
||||
element.type = 'number';
|
||||
for (var test of testData) {
|
||||
for (var data of test.data) {
|
||||
var element = document.createElement("input");
|
||||
element.type = test.type;
|
||||
|
||||
if (data[0] != null) {
|
||||
element.setAttribute('value', data[0]);
|
||||
}
|
||||
|
||||
if (data[1] != null) {
|
||||
element.step = data[1];
|
||||
}
|
||||
|
||||
if (data[2] != null) {
|
||||
element.min = data[2];
|
||||
}
|
||||
|
||||
if (data[3] != null) {
|
||||
element.max = data[3];
|
||||
}
|
||||
|
||||
var exceptionCaught = false;
|
||||
try {
|
||||
if (data[4] != null) {
|
||||
element.stepUp(data[4]);
|
||||
} else {
|
||||
element.stepUp();
|
||||
if (data[0] != null) {
|
||||
element.setAttribute('value', data[0]);
|
||||
}
|
||||
|
||||
is(element.value, data[5], "The value should be " + data[5]);
|
||||
} catch (e) {
|
||||
exceptionCaught = true;
|
||||
is(element.value, data[0], e.name + "The value should not have changed");
|
||||
is(e.name, 'InvalidStateError',
|
||||
"It should be a InvalidStateError exception.");
|
||||
} finally {
|
||||
is(exceptionCaught, data[6], "exception status should be " + data[6]);
|
||||
if (data[1] != null) {
|
||||
element.step = data[1];
|
||||
}
|
||||
|
||||
if (data[2] != null) {
|
||||
element.min = data[2];
|
||||
}
|
||||
|
||||
if (data[3] != null) {
|
||||
element.max = data[3];
|
||||
}
|
||||
|
||||
var exceptionCaught = false;
|
||||
try {
|
||||
if (data[4] != null) {
|
||||
element.stepUp(data[4]);
|
||||
} else {
|
||||
element.stepUp();
|
||||
}
|
||||
|
||||
is(element.value, data[5], "The value should be " + data[5]);
|
||||
} catch (e) {
|
||||
exceptionCaught = true;
|
||||
is(element.value, data[0], e.name + "The value should not have changed");
|
||||
is(e.name, 'InvalidStateError',
|
||||
"It should be a InvalidStateError exception.");
|
||||
} finally {
|
||||
is(exceptionCaught, data[6], "exception status should be " + data[6]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -335,8 +478,9 @@ SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function(
|
|||
|
||||
checkPresence();
|
||||
checkAvailability();
|
||||
checkStepDownForNumber();
|
||||
checkStepUpForNumber();
|
||||
|
||||
checkStepDown();
|
||||
checkStepUp();
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче