Merge m-c to inbound.
This commit is contained in:
@@ -282,14 +282,12 @@ function getJSON(element) {
|
||||
|
||||
// Until the input type=date/datetime/time have been implemented
|
||||
// let's return their real type even if the platform returns 'text'
|
||||
// Related to Bug 769352 - Implement <input type=date>
|
||||
// Related to Bug 777279 - Implement <input type=time>
|
||||
let attributeType = element.getAttribute("type") || "";
|
||||
|
||||
if (attributeType) {
|
||||
var typeLowerCase = attributeType.toLowerCase();
|
||||
switch (typeLowerCase) {
|
||||
case "date":
|
||||
case "time":
|
||||
case "datetime":
|
||||
case "datetime-local":
|
||||
|
||||
@@ -1899,6 +1899,7 @@ nsEventStateManager::FireContextClick()
|
||||
type == NS_FORM_INPUT_PASSWORD ||
|
||||
type == NS_FORM_INPUT_FILE ||
|
||||
type == NS_FORM_INPUT_NUMBER ||
|
||||
type == NS_FORM_INPUT_DATE ||
|
||||
type == NS_FORM_TEXTAREA);
|
||||
}
|
||||
else if (tag == nsGkAtoms::applet ||
|
||||
|
||||
@@ -48,6 +48,7 @@ enum ButtonElementTypes {
|
||||
enum InputElementTypes {
|
||||
NS_FORM_INPUT_BUTTON = NS_FORM_INPUT_ELEMENT + 1,
|
||||
NS_FORM_INPUT_CHECKBOX,
|
||||
NS_FORM_INPUT_DATE,
|
||||
NS_FORM_INPUT_EMAIL,
|
||||
NS_FORM_INPUT_FILE,
|
||||
NS_FORM_INPUT_HIDDEN,
|
||||
@@ -232,6 +233,8 @@ nsIFormControl::IsSingleLineTextControl(bool aExcludePassword, uint32_t aType)
|
||||
aType == NS_FORM_INPUT_URL ||
|
||||
// TODO: this is temporary until bug 635240 is fixed.
|
||||
aType == NS_FORM_INPUT_NUMBER ||
|
||||
// TODO: this is temporary until bug 773205 is fixed.
|
||||
aType == NS_FORM_INPUT_DATE ||
|
||||
(!aExcludePassword && aType == NS_FORM_INPUT_PASSWORD);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ ShouldBeInElements(nsIFormControl* aFormControl)
|
||||
case NS_FORM_INPUT_TEL :
|
||||
case NS_FORM_INPUT_URL :
|
||||
case NS_FORM_INPUT_NUMBER :
|
||||
case NS_FORM_INPUT_DATE :
|
||||
case NS_FORM_SELECT :
|
||||
case NS_FORM_TEXTAREA :
|
||||
case NS_FORM_FIELDSET :
|
||||
|
||||
@@ -88,11 +88,15 @@
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Util.h" // DebugOnly
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include "nsIIDNService.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
// input type=date
|
||||
#include "jsapi.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
@@ -117,6 +121,7 @@ UploadLastDir* nsHTMLInputElement::gUploadLastDir;
|
||||
static const nsAttrValue::EnumTable kInputTypeTable[] = {
|
||||
{ "button", NS_FORM_INPUT_BUTTON },
|
||||
{ "checkbox", NS_FORM_INPUT_CHECKBOX },
|
||||
{ "date", NS_FORM_INPUT_DATE },
|
||||
{ "email", NS_FORM_INPUT_EMAIL },
|
||||
{ "file", NS_FORM_INPUT_FILE },
|
||||
{ "hidden", NS_FORM_INPUT_HIDDEN },
|
||||
@@ -134,7 +139,7 @@ static const nsAttrValue::EnumTable kInputTypeTable[] = {
|
||||
};
|
||||
|
||||
// Default type is 'text'.
|
||||
static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[13];
|
||||
static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[14];
|
||||
|
||||
static const uint8_t NS_INPUT_AUTOCOMPLETE_OFF = 0;
|
||||
static const uint8_t NS_INPUT_AUTOCOMPLETE_ON = 1;
|
||||
@@ -172,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;
|
||||
|
||||
@@ -696,6 +703,7 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
case NS_FORM_INPUT_TEL:
|
||||
case NS_FORM_INPUT_URL:
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
if (mValueChanged) {
|
||||
// We don't have our default value anymore. Set our value on
|
||||
// the clone.
|
||||
@@ -1055,17 +1063,72 @@ nsHTMLInputElement::IsValueEmpty() const
|
||||
return value.IsEmpty();
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::ConvertStringToNumber(nsAString& aValue,
|
||||
double& aResultValue) const
|
||||
{
|
||||
switch (mType) {
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
{
|
||||
nsresult ec;
|
||||
aResultValue = PromiseFlatString(aValue).ToDouble(&ec);
|
||||
if (NS_FAILED(ec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NS_FORM_INPUT_DATE:
|
||||
{
|
||||
JSContext* ctx = nsContentUtils::GetContextFromDocument(OwnerDoc());
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t year, month, day;
|
||||
if (!GetValueAsDate(aValue, year, month, day)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject* date = JS_NewDateObjectMsec(ctx, 0);
|
||||
jsval rval;
|
||||
jsval fullYear[3];
|
||||
fullYear[0].setInt32(year);
|
||||
fullYear[1].setInt32(month-1);
|
||||
fullYear[2].setInt32(day);
|
||||
if (!JS::Call(ctx, date, "setUTCFullYear", 3, fullYear, &rval)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jsval timestamp;
|
||||
if (!JS::Call(ctx, date, "getTime", 0, nullptr, ×tamp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!timestamp.isNumber()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aResultValue = timestamp.toNumber();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
double
|
||||
nsHTMLInputElement::GetValueAsDouble() const
|
||||
{
|
||||
double doubleValue;
|
||||
nsAutoString stringValue;
|
||||
nsresult ec;
|
||||
|
||||
GetValueInternal(stringValue);
|
||||
doubleValue = stringValue.ToDouble(&ec);
|
||||
|
||||
return NS_SUCCEEDED(ec) ? doubleValue : MOZ_DOUBLE_NaN();
|
||||
return !ConvertStringToNumber(stringValue, doubleValue) ? MOZ_DOUBLE_NaN()
|
||||
: doubleValue;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -1140,11 +1203,121 @@ nsHTMLInputElement::GetList(nsIDOMHTMLElement** aValue)
|
||||
void
|
||||
nsHTMLInputElement::SetValue(double aValue)
|
||||
{
|
||||
MOZ_ASSERT(!MOZ_DOUBLE_IS_INFINITE(aValue), "aValue must not be Infinity!");
|
||||
|
||||
if (MOZ_DOUBLE_IS_NaN(aValue)) {
|
||||
SetValue(EmptyString());
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString value;
|
||||
value.AppendFloat(aValue);
|
||||
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}'");
|
||||
MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(aValue) && !MOZ_DOUBLE_IS_INFINITE(aValue),
|
||||
"aValue must be a valid non-Infinite number.");
|
||||
|
||||
aResultString.Truncate();
|
||||
|
||||
switch (mType) {
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
aResultString.AppendFloat(aValue);
|
||||
return true;
|
||||
case NS_FORM_INPUT_DATE:
|
||||
{
|
||||
JSContext* ctx = nsContentUtils::GetContextFromDocument(OwnerDoc());
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The specs require |aValue| to be truncated.
|
||||
aValue = floor(aValue);
|
||||
|
||||
JSObject* date = JS_NewDateObjectMsec(ctx, aValue);
|
||||
if (!date) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
aResultString.AppendPrintf("%04.0f-%02.0f-%02.0f", year.toNumber(),
|
||||
month.toNumber() + 1, day.toNumber());
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
MOZ_NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::GetValueAsDate(JSContext* aCtx, jsval* aDate)
|
||||
{
|
||||
if (mType != NS_FORM_INPUT_DATE) {
|
||||
aDate->setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t year, month, day;
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
if (!GetValueAsDate(value, year, month, day)) {
|
||||
aDate->setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject* date = JS_NewDateObjectMsec(aCtx, 0);
|
||||
jsval rval;
|
||||
jsval fullYear[3];
|
||||
fullYear[0].setInt32(year);
|
||||
fullYear[1].setInt32(month-1);
|
||||
fullYear[2].setInt32(day);
|
||||
if(!JS::Call(aCtx, date, "setUTCFullYear", 3, fullYear, &rval)) {
|
||||
aDate->setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aDate->setObjectOrNull(date);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::SetValueAsDate(JSContext* aCtx, const jsval& aDate)
|
||||
{
|
||||
if (mType != NS_FORM_INPUT_DATE) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
if (!aDate.isObject() || !JS_ObjectIsDate(aCtx, &aDate.toObject())) {
|
||||
SetValue(EmptyString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject& date = aDate.toObject();
|
||||
jsval timestamp;
|
||||
bool ret = JS::Call(aCtx, &date, "getTime", 0, nullptr, ×tamp);
|
||||
if (!ret || !timestamp.isNumber() || MOZ_DOUBLE_IS_NaN(timestamp.toNumber())) {
|
||||
SetValue(EmptyString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SetValue(timestamp.toNumber());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::GetValueAsNumber(double* aValueAsNumber)
|
||||
{
|
||||
@@ -1156,6 +1329,12 @@ nsHTMLInputElement::GetValueAsNumber(double* aValueAsNumber)
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::SetValueAsNumber(double aValueAsNumber)
|
||||
{
|
||||
// TODO: return TypeError when HTMLInputElement is converted to WebIDL, see
|
||||
// bug 825197.
|
||||
if (MOZ_DOUBLE_IS_INFINITE(aValueAsNumber)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!DoesValueAsNumberApply()) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
@@ -1167,8 +1346,8 @@ nsHTMLInputElement::SetValueAsNumber(double aValueAsNumber)
|
||||
double
|
||||
nsHTMLInputElement::GetMinAsDouble() const
|
||||
{
|
||||
// Should only be used for <input type='number'> for the moment.
|
||||
MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER);
|
||||
// Should only be used for <input type='number'/'date'> for the moment.
|
||||
MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE);
|
||||
|
||||
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::min)) {
|
||||
return MOZ_DOUBLE_NaN();
|
||||
@@ -1177,16 +1356,15 @@ nsHTMLInputElement::GetMinAsDouble() const
|
||||
nsAutoString minStr;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
|
||||
|
||||
nsresult ec;
|
||||
double min = minStr.ToDouble(&ec);
|
||||
return NS_SUCCEEDED(ec) ? min : MOZ_DOUBLE_NaN();
|
||||
double min;
|
||||
return ConvertStringToNumber(minStr, min) ? min : MOZ_DOUBLE_NaN();
|
||||
}
|
||||
|
||||
double
|
||||
nsHTMLInputElement::GetMaxAsDouble() const
|
||||
{
|
||||
// Should only be used for <input type='number'> for the moment.
|
||||
MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER);
|
||||
// Should only be used for <input type='number'/'date'> for the moment.
|
||||
MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE);
|
||||
|
||||
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::max)) {
|
||||
return MOZ_DOUBLE_NaN();
|
||||
@@ -1195,9 +1373,8 @@ nsHTMLInputElement::GetMaxAsDouble() const
|
||||
nsAutoString maxStr;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
|
||||
|
||||
nsresult ec;
|
||||
double max = maxStr.ToDouble(&ec);
|
||||
return NS_SUCCEEDED(ec) ? max : MOZ_DOUBLE_NaN();
|
||||
double max;
|
||||
return ConvertStringToNumber(maxStr, max) ? max : MOZ_DOUBLE_NaN();
|
||||
}
|
||||
|
||||
double
|
||||
@@ -1267,6 +1444,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 &&
|
||||
@@ -1373,8 +1565,8 @@ nsHTMLInputElement::MozSetFileNameArray(const PRUnichar **aFileNames, uint32_t a
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult)
|
||||
{
|
||||
// TODO: temporary until bug 635240 is fixed.
|
||||
if (mType == NS_FORM_INPUT_NUMBER) {
|
||||
// TODO: temporary until bug 635240 and 773205 are fixed.
|
||||
if (mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -2460,7 +2652,8 @@ nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
||||
(keyEvent->keyCode == NS_VK_RETURN ||
|
||||
keyEvent->keyCode == NS_VK_ENTER) &&
|
||||
(IsSingleLineTextControl(false, mType) ||
|
||||
mType == NS_FORM_INPUT_NUMBER)) {
|
||||
mType == NS_FORM_INPUT_NUMBER ||
|
||||
mType == NS_FORM_INPUT_DATE)) {
|
||||
FireChangeEventIfNeeded();
|
||||
rv = MaybeSubmitForm(aVisitor.mPresContext);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@@ -2754,9 +2947,152 @@ nsHTMLInputElement::SanitizeValue(nsAString& aValue)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_FORM_INPUT_DATE:
|
||||
{
|
||||
if (!aValue.IsEmpty() && !IsValidDate(aValue)) {
|
||||
aValue.Truncate();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::IsValidDate(nsAString& aValue) const
|
||||
{
|
||||
uint32_t year, month, day;
|
||||
return GetValueAsDate(aValue, year, month, day);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::GetValueAsDate(nsAString& aValue,
|
||||
uint32_t& aYear,
|
||||
uint32_t& aMonth,
|
||||
uint32_t& aDay) const
|
||||
{
|
||||
|
||||
/*
|
||||
* Parse the year, month, day values out a date string formatted as 'yyy-mm-dd'.
|
||||
* -The year must be 4 or more digits long, and year > 0
|
||||
* -The month must be exactly 2 digits long, and 01 <= month <= 12
|
||||
* -The day must be exactly 2 digit long, and 01 <= day <= maxday
|
||||
* Where maxday is the number of days in the month 'month' and year 'year'
|
||||
*/
|
||||
|
||||
if (aValue.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t fieldMaxSize = 0;
|
||||
int32_t fieldMinSize = 4;
|
||||
enum {
|
||||
YEAR, MONTH, DAY, NONE
|
||||
} field;
|
||||
int32_t fieldSize = 0;
|
||||
nsresult ec;
|
||||
|
||||
field = YEAR;
|
||||
for (uint32_t offset = 0; offset < aValue.Length(); ++offset) {
|
||||
// Test if the fied size is superior to its maximum size.
|
||||
if (fieldMaxSize && fieldSize > fieldMaxSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Illegal char.
|
||||
if (aValue[offset] != '-' && !NS_IsAsciiDigit(aValue[offset])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There are more characters in this field.
|
||||
if (aValue[offset] != '-' && offset != aValue.Length()-1) {
|
||||
fieldSize++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse the field.
|
||||
if (fieldSize < fieldMinSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(field) {
|
||||
case YEAR:
|
||||
aYear = PromiseFlatString(StringHead(aValue, offset)).ToInteger(&ec);
|
||||
NS_ENSURE_SUCCESS(ec, false);
|
||||
|
||||
if (aYear <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The field after year is month, which have a fixed size of 2 char.
|
||||
field = MONTH;
|
||||
fieldMaxSize = 2;
|
||||
fieldMinSize = 2;
|
||||
break;
|
||||
case MONTH:
|
||||
aMonth = PromiseFlatString(Substring(aValue,
|
||||
offset-fieldSize,
|
||||
offset)).ToInteger(&ec);
|
||||
NS_ENSURE_SUCCESS(ec, false);
|
||||
|
||||
if (aMonth < 1 || aMonth > 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The next field is the last one, we won't parse a '-',
|
||||
// so the field size will be one char smaller.
|
||||
field = DAY;
|
||||
fieldMinSize = 1;
|
||||
fieldMaxSize = 1;
|
||||
break;
|
||||
case DAY:
|
||||
aDay = PromiseFlatString(Substring(aValue,
|
||||
offset-fieldSize,
|
||||
offset + 1)).ToInteger(&ec);
|
||||
NS_ENSURE_SUCCESS(ec, false);
|
||||
|
||||
if (aDay < 1 || aDay > NumberOfDaysInMonth(aMonth, aYear)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
field = NONE;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
fieldSize = 0;
|
||||
}
|
||||
|
||||
return field == NONE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsHTMLInputElement::NumberOfDaysInMonth(uint32_t aMonth, uint32_t aYear) const
|
||||
{
|
||||
/*
|
||||
* Returns the number of days in a month.
|
||||
* Months that are |longMonths| always have 31 days.
|
||||
* Months that are not |longMonths| have 30 days except February (month 2).
|
||||
* February has 29 days during leap years which are years that are divisible by 400.
|
||||
* or divisible by 100 and 4. February has 28 days otherwise.
|
||||
*/
|
||||
|
||||
static const bool longMonths[] = { true, false, true, false, true, false,
|
||||
true, true, false, true, false, true };
|
||||
MOZ_ASSERT(aMonth <= 12 && aMonth > 0);
|
||||
|
||||
if (longMonths[aMonth-1]) {
|
||||
return 31;
|
||||
}
|
||||
|
||||
if (aMonth != 2) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
return (aYear % 400 == 0 || (aYear % 100 != 0 && aYear % 4 == 0))
|
||||
? 29 : 28;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
@@ -2771,8 +3107,9 @@ nsHTMLInputElement::ParseAttribute(int32_t aNamespaceID,
|
||||
bool success = aResult.ParseEnumValue(aValue, kInputTypeTable, false);
|
||||
if (success) {
|
||||
newType = aResult.GetEnumValue();
|
||||
if (newType == NS_FORM_INPUT_NUMBER &&
|
||||
!Preferences::GetBool("dom.experimental_forms", false)) {
|
||||
if ((newType == NS_FORM_INPUT_NUMBER ||
|
||||
newType == NS_FORM_INPUT_DATE) &&
|
||||
!Preferences::GetBool("dom.experimental_forms", false)) {
|
||||
newType = kInputDefaultType->value;
|
||||
aResult.SetTo(newType, &aValue);
|
||||
}
|
||||
@@ -3397,6 +3734,7 @@ nsHTMLInputElement::SaveState()
|
||||
case NS_FORM_INPUT_URL:
|
||||
case NS_FORM_INPUT_HIDDEN:
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
{
|
||||
if (mValueChanged) {
|
||||
inputState = new nsHTMLInputElementState();
|
||||
@@ -3581,6 +3919,7 @@ nsHTMLInputElement::RestoreState(nsPresState* aState)
|
||||
case NS_FORM_INPUT_URL:
|
||||
case NS_FORM_INPUT_HIDDEN:
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
{
|
||||
SetValueInternal(inputState->GetValue(), false, true);
|
||||
break;
|
||||
@@ -3805,6 +4144,7 @@ nsHTMLInputElement::GetValueMode() const
|
||||
case NS_FORM_INPUT_EMAIL:
|
||||
case NS_FORM_INPUT_URL:
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
return VALUE_MODE_VALUE;
|
||||
default:
|
||||
NS_NOTYETIMPLEMENTED("Unexpected input type in GetValueMode()");
|
||||
@@ -3849,6 +4189,7 @@ nsHTMLInputElement::DoesReadOnlyApply() const
|
||||
case NS_FORM_INPUT_EMAIL:
|
||||
case NS_FORM_INPUT_URL:
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
return true;
|
||||
default:
|
||||
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesReadOnlyApply()");
|
||||
@@ -3885,6 +4226,7 @@ nsHTMLInputElement::DoesRequiredApply() const
|
||||
case NS_FORM_INPUT_EMAIL:
|
||||
case NS_FORM_INPUT_URL:
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
return true;
|
||||
default:
|
||||
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
|
||||
@@ -3896,11 +4238,21 @@ nsHTMLInputElement::DoesRequiredApply() const
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::PlaceholderApplies() const
|
||||
{
|
||||
if (mType == NS_FORM_INPUT_DATE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsSingleLineTextControl(false);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::DoesPatternApply() const
|
||||
{
|
||||
// TODO: temporary until bug 635240 is fixed.
|
||||
if (mType == NS_FORM_INPUT_NUMBER) {
|
||||
if (mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3913,6 +4265,7 @@ nsHTMLInputElement::DoesMinMaxApply() const
|
||||
switch (mType)
|
||||
{
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
// TODO:
|
||||
// case NS_FORM_INPUT_RANGE:
|
||||
// All date/time types.
|
||||
@@ -3946,11 +4299,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)) {
|
||||
@@ -3963,17 +4315,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
|
||||
@@ -4164,6 +4515,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;
|
||||
}
|
||||
@@ -4386,11 +4746,18 @@ nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
||||
{
|
||||
nsXPIDLString message;
|
||||
|
||||
double max = GetMaxAsDouble();
|
||||
MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(max));
|
||||
|
||||
nsAutoString maxStr;
|
||||
maxStr.AppendFloat(max);
|
||||
if (mType == NS_FORM_INPUT_NUMBER) {
|
||||
//We want to show the value as parsed when it's a number
|
||||
double max = GetMaxAsDouble();
|
||||
MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(max));
|
||||
|
||||
maxStr.AppendFloat(max);
|
||||
} else if (mType == NS_FORM_INPUT_DATE) {
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
|
||||
} else {
|
||||
NS_NOTREACHED("Unexpected input type");
|
||||
}
|
||||
|
||||
const PRUnichar* params[] = { maxStr.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
@@ -4403,11 +4770,17 @@ nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
||||
{
|
||||
nsXPIDLString message;
|
||||
|
||||
double min = GetMinAsDouble();
|
||||
MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(min));
|
||||
|
||||
nsAutoString minStr;
|
||||
minStr.AppendFloat(min);
|
||||
if (mType == NS_FORM_INPUT_NUMBER) {
|
||||
double min = GetMinAsDouble();
|
||||
MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(min));
|
||||
|
||||
minStr.AppendFloat(min);
|
||||
} else if (mType == NS_FORM_INPUT_DATE) {
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
|
||||
} else {
|
||||
NS_NOTREACHED("Unexpected input type");
|
||||
}
|
||||
|
||||
const PRUnichar* params[] = { minStr.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
@@ -4426,6 +4799,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);
|
||||
@@ -4435,8 +4818,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,
|
||||
@@ -4444,7 +4827,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,
|
||||
@@ -4861,6 +5244,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)
|
||||
{
|
||||
@@ -4883,7 +5282,7 @@ nsHTMLInputElement::UpdateHasRange()
|
||||
{
|
||||
mHasRange = false;
|
||||
|
||||
if (mType != NS_FORM_INPUT_NUMBER) {
|
||||
if (mType != NS_FORM_INPUT_NUMBER && mType != NS_FORM_INPUT_DATE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -502,7 +502,7 @@ protected:
|
||||
/**
|
||||
* Returns whether the placeholder attribute applies for the current type.
|
||||
*/
|
||||
bool PlaceholderApplies() const { return IsSingleLineTextControl(false, mType); }
|
||||
bool PlaceholderApplies() const;
|
||||
|
||||
/**
|
||||
* Set the current default value to the value of the input element.
|
||||
@@ -560,6 +560,54 @@ protected:
|
||||
*/
|
||||
double GetValueAsDouble() const;
|
||||
|
||||
/**
|
||||
* Convert a string to a number in a type specific way,
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#concept-input-value-string-number
|
||||
* ie parse a date string to a timestamp if type=date,
|
||||
* or parse a number string to its value if type=number.
|
||||
* @param aValue the string to be parsed.
|
||||
* @param aResultValue the timestamp as a double.
|
||||
* @result whether the parsing was successful.
|
||||
*/
|
||||
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.
|
||||
* @return whether the string is a valid date.
|
||||
* Note : this function does not consider the empty string as valid.
|
||||
*/
|
||||
bool IsValidDate(nsAString& aValue) const;
|
||||
|
||||
/**
|
||||
* Parse a date string of the form yyyy-mm-dd
|
||||
* @param the string to be parsed.
|
||||
* @return the date in aYear, aMonth, aDay.
|
||||
* @return whether the parsing was successful.
|
||||
*/
|
||||
bool GetValueAsDate(nsAString& aValue,
|
||||
uint32_t& aYear,
|
||||
uint32_t& aMonth,
|
||||
uint32_t& aDay) const;
|
||||
|
||||
/**
|
||||
* This methods returns the number of days in a given month, for a given year.
|
||||
*/
|
||||
uint32_t NumberOfDaysInMonth(uint32_t aMonth, uint32_t aYear) const;
|
||||
|
||||
/**
|
||||
* Sets the value of the element to the string representation of the double.
|
||||
*
|
||||
@@ -584,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.
|
||||
@@ -653,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'.
|
||||
|
||||
@@ -159,7 +159,6 @@ MOCHITEST_FILES = \
|
||||
test_bug567938-4.html \
|
||||
test_bug569955.html \
|
||||
test_bug573969.html \
|
||||
test_bug549475.html \
|
||||
test_bug585508.html \
|
||||
test_bug561640.html \
|
||||
test_bug566064.html \
|
||||
|
||||
@@ -49,6 +49,8 @@ MOCHITEST_FILES = \
|
||||
test_valueasnumber_attribute.html \
|
||||
test_experimental_forms_pref.html \
|
||||
test_input_number_value.html \
|
||||
test_input_sanitization.html \
|
||||
test_valueasdate_attribute.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
@@ -201,10 +201,10 @@ reflectLimitedEnumerated({
|
||||
attribute: "type",
|
||||
validValues: [ "hidden", "text", "search", "tel", "url", "email", "password",
|
||||
"checkbox", "radio", "file", "submit", "image", "reset",
|
||||
"button", "number" ],
|
||||
"button", "date", "number" ],
|
||||
invalidValues: [ "this-is-probably-a-wrong-type", "", "tulip" ],
|
||||
defaultValue: "text",
|
||||
unsupportedValues: [ "datetime", "date", "month", "week", "time",
|
||||
unsupportedValues: [ "datetime", "month", "week", "time",
|
||||
"datetime-local", "range", "color" ]
|
||||
});
|
||||
|
||||
@@ -218,8 +218,8 @@ reflectString({
|
||||
// .value doesn't reflect a content attribute.
|
||||
|
||||
// .valueAsDate
|
||||
todo("valueAsDate" in document.createElement("input"),
|
||||
"valueAsDate isn't implemented yet");
|
||||
is("valueAsDate" in document.createElement("input"), true,
|
||||
"valueAsDate should be available");
|
||||
|
||||
// Deeper check will be done with bug 763305.
|
||||
is('valueAsNumber' in document.createElement("input"), true,
|
||||
|
||||
@@ -25,13 +25,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=549475
|
||||
var inputTypes =
|
||||
[
|
||||
"text", "password", "search", "tel", "hidden", "checkbox", "radio",
|
||||
"submit", "image", "reset", "button", "email", "url", "number",
|
||||
"submit", "image", "reset", "button", "email", "url", "number", "date",
|
||||
];
|
||||
|
||||
var todoTypes =
|
||||
[
|
||||
"range", "color",
|
||||
"date", "month", "week", "time", "datetime", "datetime-local",
|
||||
"month", "week", "time", "datetime", "datetime-local",
|
||||
];
|
||||
|
||||
var valueModeValue =
|
||||
@@ -40,40 +40,114 @@ var valueModeValue =
|
||||
"month", "week", "time", "datetime-local", "number", "range", "color",
|
||||
];
|
||||
|
||||
function checkDateSanitizing(element) {
|
||||
var invalidData =
|
||||
[
|
||||
"1234",
|
||||
"1234-",
|
||||
"12345",
|
||||
"1234-01",
|
||||
"1234-012",
|
||||
"1234-01-",
|
||||
"12-12",
|
||||
"999-01-01",
|
||||
"1234-56-78-91",
|
||||
"1234-567-78",
|
||||
"1234--7-78",
|
||||
"abcd-12-12",
|
||||
"thisinotadate",
|
||||
"2012-13-01",
|
||||
"1234-12-42",
|
||||
" 2012-13-01",
|
||||
" 123-01-01",
|
||||
"2012- 3-01",
|
||||
"12- 10- 01",
|
||||
" 12-0-1",
|
||||
"2012-3-001",
|
||||
"2012-12-00",
|
||||
"2012-12-1r",
|
||||
"2012-11-31",
|
||||
"2011-02-29",
|
||||
"2100-02-29",
|
||||
"a2000-01-01",
|
||||
"2000a-01-0'",
|
||||
"20aa00-01-01",
|
||||
"2000a2000-01-01",
|
||||
"2000-1-1",
|
||||
"2000-1-01",
|
||||
"2000-01-1",
|
||||
"2000-01-01 ",
|
||||
"2000- 01-01",
|
||||
"-1970-01-01",
|
||||
"0000-00-00",
|
||||
"0001-00-00",
|
||||
"0000-01-01",
|
||||
"1234-12 12",
|
||||
"1234 12-12",
|
||||
"1234 12 12",
|
||||
];
|
||||
|
||||
var validData =
|
||||
[
|
||||
"1970-01-01",
|
||||
"1234-12-12",
|
||||
"1234567890-01-02",
|
||||
"2012-12-31",
|
||||
"2012-02-29",
|
||||
"2000-02-29",
|
||||
];
|
||||
|
||||
for (data of validData) {
|
||||
element.value = data;
|
||||
is(element.value, data, "valid date should not be sanitized");
|
||||
}
|
||||
|
||||
for (data of invalidData) {
|
||||
element.value = data;
|
||||
is(element.value, "", "invalid date should be sanitized");
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeValue(aType, aValue)
|
||||
{
|
||||
switch (aType) {
|
||||
case "text":
|
||||
case "password":
|
||||
case "search":
|
||||
case "tel":
|
||||
return aValue.replace(/[\n\r]/g, "");
|
||||
case "url":
|
||||
case "email":
|
||||
return aValue.replace(/[\n\r]/g, "").replace(/^\s+|\s+$/g, "");
|
||||
case "date":
|
||||
case "month":
|
||||
case "week":
|
||||
case "time":
|
||||
case "datetime":
|
||||
case "datetime-local":
|
||||
// TODO: write the sanitize algorithm.
|
||||
return "";
|
||||
case "number":
|
||||
return (parseFloat(aValue) + "" === aValue) ? aValue : "";
|
||||
case "range":
|
||||
// TODO: write the sanitize algorithm.
|
||||
return "";
|
||||
case "color":
|
||||
// TODO: write the sanitize algorithm.
|
||||
return "";
|
||||
default:
|
||||
return aValue;
|
||||
}
|
||||
switch (aType) {
|
||||
case "text":
|
||||
case "password":
|
||||
case "search":
|
||||
case "tel":
|
||||
return aValue.replace(/[\n\r]/g, "");
|
||||
case "url":
|
||||
case "email":
|
||||
return aValue.replace(/[\n\r]/g, "").replace(/^\s+|\s+$/g, "");
|
||||
case "date":
|
||||
return "";
|
||||
case "month":
|
||||
case "week":
|
||||
case "time":
|
||||
case "datetime":
|
||||
case "datetime-local":
|
||||
// TODO: write the sanitize algorithm.
|
||||
return "";
|
||||
case "number":
|
||||
return (parseFloat(aValue) + "" === aValue) ? aValue : "";
|
||||
case "range":
|
||||
// TODO: write the sanitize algorithm.
|
||||
return "";
|
||||
case "color":
|
||||
// TODO: write the sanitize algorithm.
|
||||
return "";
|
||||
default:
|
||||
return aValue;
|
||||
}
|
||||
}
|
||||
|
||||
function checkSanitizing(element)
|
||||
{
|
||||
if (element.type == 'date') {
|
||||
checkDateSanitizing(element);
|
||||
return;
|
||||
}
|
||||
|
||||
var testData =
|
||||
[
|
||||
// For text, password, search, tel, email:
|
||||
@@ -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 ],
|
||||
@@ -90,7 +90,12 @@ for (var data of types) {
|
||||
|
||||
checkValidity(input, true, apply, false);
|
||||
|
||||
input.max = '2';
|
||||
if (input.type == 'date') {
|
||||
input.max = '2012-06-27';
|
||||
} else {
|
||||
input.max = '2';
|
||||
}
|
||||
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
if (input.type == 'url') {
|
||||
@@ -118,6 +123,36 @@ for (var data of types) {
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
file.remove(false);
|
||||
} else if (input.type == 'date') {
|
||||
input.value = '2012-06-26';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = '2012-06-27';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = 'foo';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = '2012-06-28';
|
||||
checkValidity(input, false, apply, apply);
|
||||
|
||||
input.max = '2012-06-30';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = '2012-07-05';
|
||||
checkValidity(input, false, apply, apply);
|
||||
|
||||
input.value = '1000-01-01';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = '20120-01-01';
|
||||
checkValidity(input, false, apply, apply);
|
||||
|
||||
input.max = '0050-01-01';
|
||||
checkValidity(input, false, apply, apply);
|
||||
|
||||
input.value = '0049-01-01';
|
||||
checkValidity(input, true, apply, apply);
|
||||
} else {
|
||||
input.value = '1';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
@@ -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 ],
|
||||
@@ -90,7 +90,12 @@ for (var data of types) {
|
||||
|
||||
checkValidity(input, true, apply, false);
|
||||
|
||||
input.min = '0';
|
||||
if (input.type == 'date') {
|
||||
input.min = '2012-06-27';
|
||||
} else {
|
||||
input.min = '0';
|
||||
}
|
||||
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
if (input.type == 'url') {
|
||||
@@ -118,6 +123,36 @@ for (var data of types) {
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
file.remove(false);
|
||||
} else if (input.type == 'date') {
|
||||
input.value = '2012-06-28';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = '2012-06-27';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = 'foo';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = '2012-06-26';
|
||||
checkValidity(input, false, apply, apply);
|
||||
|
||||
input.min = '2012-02-29';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = '2012-02-28';
|
||||
checkValidity(input, false, apply, apply);
|
||||
|
||||
input.value = '1000-01-01';
|
||||
checkValidity(input, false, apply, apply);
|
||||
|
||||
input.value = '20120-01-01';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.min = '0050-01-01';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
input.value = '0049-01-01';
|
||||
checkValidity(input, false, apply, apply);
|
||||
} else {
|
||||
input.value = '1';
|
||||
checkValidity(input, true, apply, apply);
|
||||
|
||||
@@ -48,6 +48,7 @@ var gInputTestData = [
|
||||
['email', true],
|
||||
['url', true],
|
||||
['number', false],
|
||||
['date', false],
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -58,7 +59,6 @@ var gInputTodoData = [
|
||||
/* type expected result */
|
||||
['range', false],
|
||||
['color', false],
|
||||
['date', false],
|
||||
['datetime', false],
|
||||
['month', false],
|
||||
['week', false],
|
||||
|
||||
@@ -261,8 +261,8 @@ var input = document.getElementById('i');
|
||||
// and |invalidTypes| are the ones which do not accept it.
|
||||
var validTypes = Array('text', 'password', 'search', 'tel', 'email', 'url');
|
||||
var barredTypes = Array('hidden', 'reset', 'button', 'submit', 'image');
|
||||
var invalidTypes = Array('checkbox', 'radio', 'file', 'number');
|
||||
// TODO: 'datetime', 'date', 'month', 'week', 'time', 'datetime-local',
|
||||
var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'date');
|
||||
// TODO: 'datetime', 'month', 'week', 'time', 'datetime-local',
|
||||
// 'range', and 'color' do not accept the @pattern too but are not
|
||||
// implemented yet.
|
||||
|
||||
|
||||
@@ -164,6 +164,8 @@ function checkInputRequiredValidity(type)
|
||||
element.value = 'http://mozilla.org/';
|
||||
} else if (element.type == 'number') {
|
||||
element.value = '42';
|
||||
} else if (element.type == 'date') {
|
||||
element.value = '2010-10-10';
|
||||
} else {
|
||||
element.value = 'foo';
|
||||
}
|
||||
@@ -352,6 +354,9 @@ function checkInputRequiredValidityForFile()
|
||||
checkNotSufferingFromBeingMissing(element);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
|
||||
|
||||
checkTextareaRequiredValidity();
|
||||
|
||||
// The require attribute behavior depend of the input type.
|
||||
@@ -370,10 +375,10 @@ for (type of typeRequireNotApply) {
|
||||
}
|
||||
|
||||
// Now, checking for all types which accept the required attribute.
|
||||
// TODO: check 'datetime', 'date', 'month', 'week', 'time' and 'datetime-local'
|
||||
// TODO: check 'datetime', 'month', 'week', 'time' and 'datetime-local'
|
||||
// when they will be implemented.
|
||||
var typeRequireApply = ["text", "password", "search", "tel", "email", "url",
|
||||
"number"];
|
||||
"number", "date"];
|
||||
|
||||
for (type of typeRequireApply) {
|
||||
checkInputRequiredValidity(type);
|
||||
@@ -383,6 +388,9 @@ checkInputRequiredValidityForCheckbox();
|
||||
checkInputRequiredValidityForRadio();
|
||||
checkInputRequiredValidityForFile();
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
206
content/html/content/test/forms/test_valueasdate_attribute.html
Normal file
206
content/html/content/test/forms/test_valueasdate_attribute.html
Normal file
@@ -0,0 +1,206 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=769370
|
||||
-->
|
||||
<head>
|
||||
<title>Test for input.valueAsDate</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=769370">Mozilla Bug 769370</a>
|
||||
<p id="display"></p>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 769370**/
|
||||
|
||||
/**
|
||||
* This test is checking .valueAsDate.
|
||||
*/
|
||||
|
||||
var element = document.createElement("input");
|
||||
|
||||
function checkAvailability()
|
||||
{
|
||||
var testData =
|
||||
[
|
||||
["text", false],
|
||||
["password", false],
|
||||
["search", false],
|
||||
["telephone", false],
|
||||
["email", false],
|
||||
["url", false],
|
||||
["hidden", false],
|
||||
["checkbox", false],
|
||||
["radio", false],
|
||||
["file", false],
|
||||
["submit", false],
|
||||
["image", false],
|
||||
["reset", false],
|
||||
["button", false],
|
||||
["number", false],
|
||||
["date", true],
|
||||
// The next types have not been implemented but will fallback to "text"
|
||||
// which has the same value.
|
||||
["range", false],
|
||||
["color", false],
|
||||
];
|
||||
|
||||
var todoList =
|
||||
[
|
||||
["datetime", true],
|
||||
["month", true],
|
||||
["week", true],
|
||||
["time", true],
|
||||
["datetime-local", true],
|
||||
];
|
||||
|
||||
for (data of testData) {
|
||||
var exceptionCatched = false;
|
||||
element.type = data[0];
|
||||
try {
|
||||
element.valueAsDate;
|
||||
} catch (e) {
|
||||
exceptionCatched = true;
|
||||
}
|
||||
is(exceptionCatched, false,
|
||||
"valueAsDate shouldn't throw exception on getting");
|
||||
|
||||
exceptionCatched = false;
|
||||
try {
|
||||
element.valueAsDate = new Date();
|
||||
} catch (e) {
|
||||
exceptionCatched = true;
|
||||
}
|
||||
is(exceptionCatched, !data[1], "valueAsDate for " + data[0] +
|
||||
" availability is not correct");
|
||||
}
|
||||
|
||||
for (data of todoList) {
|
||||
var exceptionCatched = false;
|
||||
element.type = data[0];
|
||||
try {
|
||||
element.valueAsDate;
|
||||
} catch (e) {
|
||||
exceptionCatched = true;
|
||||
}
|
||||
is(exceptionCatched, false,
|
||||
"valueAsDate shouldn't throw exception on getting");
|
||||
|
||||
exceptionCatched = false;
|
||||
try {
|
||||
element.valueAsDate= 42;
|
||||
} catch (e) {
|
||||
exceptionCatched = true;
|
||||
}
|
||||
todo_is(exceptionCatched, !data[1],
|
||||
"valueAsDate for " + data[0] + " availability is not correct");
|
||||
}
|
||||
}
|
||||
|
||||
function checkGet()
|
||||
{
|
||||
var validData =
|
||||
[
|
||||
[ "2012-07-12", 1342051200000 ],
|
||||
[ "1970-01-01", 0 ],
|
||||
[ "1970-01-02", 86400000 ],
|
||||
[ "1969-12-31", -86400000 ],
|
||||
[ "0311-01-31", -52350451200000 ],
|
||||
[ "275760-09-13", 8640000000000000 ],
|
||||
[ "0001-01-01", -62135596800000 ],
|
||||
[ "2012-02-29", 1330473600000 ],
|
||||
[ "2011-02-28", 1298851200000 ],
|
||||
];
|
||||
|
||||
var invalidData =
|
||||
[
|
||||
[ "invaliddate" ],
|
||||
[ "-001-12-31" ],
|
||||
[ "901-12-31" ],
|
||||
[ "1901-13-31" ],
|
||||
[ "1901-12-32" ],
|
||||
[ "1901-00-12" ],
|
||||
[ "1901-01-00" ],
|
||||
[ "1900-02-29" ],
|
||||
[ "0000-01-01" ],
|
||||
[ "" ],
|
||||
// This date 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-09-14", true ],
|
||||
];
|
||||
|
||||
element.type = "date";
|
||||
for (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) {
|
||||
element.value = data[0];
|
||||
is(element.valueAsDate, data[1] ? "Invalid Date" : null,
|
||||
"valueAsDate should return null " +
|
||||
"when the element value is not a valid date");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function checkSet()
|
||||
{
|
||||
var testData =
|
||||
[
|
||||
[ 1342051200000, "2012-07-12" ],
|
||||
[ 0, "1970-01-01" ],
|
||||
// Maximum valid date (limited by the ecma date object range).
|
||||
[ 8640000000000000, "275760-09-13" ],
|
||||
// Minimum valid date (limited by the input element minimum valid value).
|
||||
[ -62135596800000 , "0001-01-01" ],
|
||||
[ 1330473600000, "2012-02-29" ],
|
||||
[ 1298851200000, "2011-02-28" ],
|
||||
// "Values must be truncated to valid dates"
|
||||
[ 42.1234, "1970-01-01" ],
|
||||
[ 123.123456789123, "1970-01-01" ],
|
||||
[ 1e-1, "1970-01-01" ],
|
||||
[ 1298851200010, "2011-02-28" ],
|
||||
[ -1, "1969-12-31" ],
|
||||
[ -86400000, "1969-12-31" ],
|
||||
[ 86400000, "1970-01-02" ],
|
||||
// Negative years, this is out of range for the input element,
|
||||
// the corresponding date string is the empty string
|
||||
[ -62135596800001, "" ],
|
||||
// Invalid dates.
|
||||
[ NaN, "" ],
|
||||
];
|
||||
|
||||
element.type = "date";
|
||||
for (data of testData) {
|
||||
element.valueAsDate = new Date(data[0]);
|
||||
is(element.value, data[1], "valueAsDate should set the value to "
|
||||
+ data[1]);
|
||||
}
|
||||
|
||||
element.valueAsDate = null;
|
||||
is(element.value, "", "valueAsDate should set the value to the empty string");
|
||||
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
|
||||
checkAvailability();
|
||||
checkGet();
|
||||
checkSet();
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,7 +4,7 @@
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=636737
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 636737</title>
|
||||
<title>Test for Bug input.valueAsNumber</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
@@ -43,6 +43,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],
|
||||
@@ -51,7 +52,6 @@ function checkAvailability()
|
||||
var todoList =
|
||||
[
|
||||
["datetime", true],
|
||||
["date", true],
|
||||
["month", true],
|
||||
["week", true],
|
||||
["time", true],
|
||||
@@ -103,7 +103,7 @@ function checkAvailability()
|
||||
}
|
||||
}
|
||||
|
||||
function checkGet()
|
||||
function checkNumberGet()
|
||||
{
|
||||
var testData =
|
||||
[
|
||||
@@ -126,6 +126,8 @@ function checkGet()
|
||||
element.type = "number";
|
||||
for (data of testData) {
|
||||
element.value = data[0];
|
||||
|
||||
// Given that NaN != NaN, we have to use null when the expected value is NaN.
|
||||
if (data[1] != null) {
|
||||
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
|
||||
"floating point representation of the value");
|
||||
@@ -136,7 +138,7 @@ function checkGet()
|
||||
}
|
||||
}
|
||||
|
||||
function checkSet()
|
||||
function checkNumberSet()
|
||||
{
|
||||
var testData =
|
||||
[
|
||||
@@ -148,29 +150,156 @@ function checkSet()
|
||||
[2e1, "20"],
|
||||
[1e-1, "0.1"], // value after e can be negative
|
||||
[1E2, "100"], // E can be used instead of e
|
||||
["", null], // the empty string is not a number
|
||||
["foo", null],
|
||||
// Setting a string will set NaN.
|
||||
["foo", ""],
|
||||
// "" is converted to 0.
|
||||
["", 0],
|
||||
[42, "42"], // Keep this here, it is used by the next test.
|
||||
// Setting Infinity should throw and not change the current value.
|
||||
[Infinity, 42, true],
|
||||
[-Infinity, 42, true],
|
||||
// Setting NaN should change the value to the empty string.
|
||||
[NaN, ""],
|
||||
];
|
||||
|
||||
element.type = "number";
|
||||
for (data of testData) {
|
||||
element.valueAsNumber = data[0];
|
||||
if (data[1] != null) {
|
||||
var caught = false;
|
||||
try {
|
||||
element.valueAsNumber = data[0];
|
||||
is(element.value, data[1],
|
||||
"valueAsNumber should be able to set the value");
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
}
|
||||
|
||||
if (data[2]) {
|
||||
ok(caught, "valueAsNumber should have thrown");
|
||||
is(element.value, data[1], "value should not have changed");
|
||||
} else {
|
||||
element.valueAsNumber = testData[0];
|
||||
isnot(element.value, data[1],
|
||||
"valueAsNumber should not set the value if it's not a number");
|
||||
ok(!caught, "valueAsNumber should not have thrown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkDateGet()
|
||||
{
|
||||
var validData =
|
||||
[
|
||||
[ "2012-07-12", 1342051200000 ],
|
||||
[ "1970-01-01", 0 ],
|
||||
// We are supposed to support at least until this date.
|
||||
// (corresponding to the date object maximal value)
|
||||
[ "275760-09-13", 8640000000000000 ],
|
||||
// Minimum valid date (limited by the input element minimum valid value)
|
||||
[ "0001-01-01", -62135596800000 ],
|
||||
[ "2012-02-29", 1330473600000 ],
|
||||
[ "2011-02-28", 1298851200000 ],
|
||||
];
|
||||
|
||||
var invalidData =
|
||||
[
|
||||
"invaliddate",
|
||||
"",
|
||||
"275760-09-14",
|
||||
"999-12-31",
|
||||
"-001-12-31",
|
||||
"0000-01-01",
|
||||
"2011-02-29",
|
||||
"1901-13-31",
|
||||
"1901-12-32",
|
||||
"1901-00-12",
|
||||
"1901-01-00",
|
||||
"1900-02-29",
|
||||
];
|
||||
|
||||
element.type = "date";
|
||||
for (data of validData) {
|
||||
element.value = data[0];
|
||||
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
|
||||
"timestamp representing this date");
|
||||
}
|
||||
|
||||
for (data of invalidData) {
|
||||
element.value = data;
|
||||
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
|
||||
"when the element value is not a valid date");
|
||||
}
|
||||
}
|
||||
|
||||
function checkDateSet()
|
||||
{
|
||||
var testData =
|
||||
[
|
||||
[ 1342051200000, "2012-07-12" ],
|
||||
[ 0, "1970-01-01" ],
|
||||
// Maximum valid date (limited by the ecma date object range).
|
||||
[ 8640000000000000, "275760-09-13" ],
|
||||
// Minimum valid date (limited by the input element minimum valid value)
|
||||
[ -62135596800000, "0001-01-01" ],
|
||||
[ 1330473600000, "2012-02-29" ],
|
||||
[ 1298851200000, "2011-02-28" ],
|
||||
// "Values must be truncated to valid dates"
|
||||
[ 42.1234, "1970-01-01" ],
|
||||
[ 123.123456789123, "1970-01-01" ],
|
||||
[ 1e2, "1970-01-01" ],
|
||||
[ 1E9, "1970-01-12" ],
|
||||
[ 1e-1, "1970-01-01" ],
|
||||
[ 2e10, "1970-08-20" ],
|
||||
[ 1298851200010, "2011-02-28" ],
|
||||
[ -1, "1969-12-31" ],
|
||||
[ -86400000, "1969-12-31" ],
|
||||
[ 86400000, "1970-01-02" ],
|
||||
// Invalid numbers.
|
||||
// Those are implicitly converted to numbers
|
||||
[ "", "1970-01-01" ],
|
||||
[ true, "1970-01-01" ],
|
||||
[ false, "1970-01-01" ],
|
||||
[ null, "1970-01-01" ],
|
||||
// Those are converted to NaN, the corresponding date string is the empty string
|
||||
[ "invaliddatenumber", "" ],
|
||||
[ NaN, "" ],
|
||||
[ undefined, "" ],
|
||||
// Out of range, the corresponding date string is the empty string
|
||||
[ -62135596800001, "" ],
|
||||
// Infinity will keep the current value and throw (so we need to set a current value).
|
||||
[ 1298851200010, "2011-02-28" ],
|
||||
[ Infinity, "2011-02-28", true ],
|
||||
[ -Infinity, "2011-02-28", true ],
|
||||
];
|
||||
|
||||
element.type = "date";
|
||||
for (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 trhown");
|
||||
is(element.value, data[1], "the value should not have changed");
|
||||
} else {
|
||||
ok(!caught, "valueAsNumber should not have thrown");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
|
||||
checkAvailability();
|
||||
checkGet();
|
||||
checkSet();
|
||||
|
||||
// <input type='number'> test
|
||||
checkNumberGet();
|
||||
checkNumberSet();
|
||||
|
||||
// <input type='date'> test
|
||||
checkDateGet();
|
||||
checkDateSet();
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
@@ -35,13 +35,17 @@ var testData = [
|
||||
[ "search", true ],
|
||||
[ "password", true ],
|
||||
[ "number", true ],
|
||||
[ "date", true ],
|
||||
// 'file' is treated separatly.
|
||||
];
|
||||
|
||||
var todoTypes = [
|
||||
"datetime", "date", "month", "week", "time", "datetime-local", "range", "color"
|
||||
"datetime", "month", "week", "time", "datetime-local", "range", "color"
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
|
||||
|
||||
var length = testData.length;
|
||||
for (var i=0; i<length; ++i) {
|
||||
for (var j=0; j<length; ++j) {
|
||||
@@ -49,8 +53,13 @@ for (var i=0; i<length; ++i) {
|
||||
e.type = testData[i][0];
|
||||
|
||||
var expectedValue;
|
||||
if (testData[i][0] == 'number' || testData[j][0] == 'number') {
|
||||
if ((testData[i][0] == 'number' && testData[j][0] == 'date') ||
|
||||
(testData[i][0] == 'date' && testData[j][0] == 'number')) {
|
||||
expectedValue = '';
|
||||
} else if (testData[i][0] == 'number' || testData[j][0] == 'number') {
|
||||
expectedValue = '42';
|
||||
} else if (testData[i][0] == 'date' || testData[j][0] == 'date') {
|
||||
expectedValue = '2012-12-21';
|
||||
} else {
|
||||
expectedValue = "foo";
|
||||
}
|
||||
@@ -87,6 +96,9 @@ for (var type of todoTypes) {
|
||||
todo_is(e.type, type, type + " type isn't supported yet");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
@@ -69,6 +69,7 @@ interface nsIDOMHTMLInputElement : nsIDOMHTMLElement
|
||||
attribute DOMString defaultValue;
|
||||
attribute DOMString value;
|
||||
attribute double valueAsNumber;
|
||||
[implicit_jscontext] attribute jsval valueAsDate;
|
||||
|
||||
[optional_argc] void stepDown([optional] in long n);
|
||||
[optional_argc] void stepUp([optional] in long n);
|
||||
|
||||
@@ -3264,6 +3264,7 @@ nsWebBrowserPersist::CloneNodeWithFixedUpAttributes(
|
||||
case NS_FORM_INPUT_TEL:
|
||||
case NS_FORM_INPUT_URL:
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
nodeAsInput->GetValue(valueStr);
|
||||
// Avoid superfluous value="" serialization
|
||||
if (valueStr.IsEmpty())
|
||||
|
||||
@@ -3432,6 +3432,8 @@ nsCSSFrameConstructor::FindInputData(Element* aElement,
|
||||
SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame),
|
||||
// TODO: this is temporary until a frame is written: bug 635240.
|
||||
SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewTextControlFrame),
|
||||
// TODO: this is temporary until a frame is written: bug 773205.
|
||||
SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewTextControlFrame),
|
||||
{ NS_FORM_INPUT_SUBMIT,
|
||||
FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewGfxButtonControlFrame,
|
||||
nsCSSAnonBoxes::buttonContent) },
|
||||
|
||||
@@ -92,6 +92,12 @@ Form History test: form field autocomplete
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
<!-- form with input type='date' -->
|
||||
<form id="form14" onsubmit="return false;">
|
||||
<input type="date" name="field11">
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
@@ -134,10 +140,11 @@ fh.addEntry("field7", "value");
|
||||
fh.addEntry("field8", "value");
|
||||
fh.addEntry("field9", "value");
|
||||
fh.addEntry("field10", "42");
|
||||
fh.addEntry("field11", "2010-10-10");
|
||||
fh.addEntry("searchbar-history", "blacklist test");
|
||||
|
||||
// All these non-implemeted types might need autocomplete tests in the future.
|
||||
var todoTypes = [ "datetime", "date", "month", "week", "time", "datetime-local",
|
||||
var todoTypes = [ "datetime", "month", "week", "time", "datetime-local",
|
||||
"range", "color" ];
|
||||
var todoInput = document.createElement("input");
|
||||
for (var type of todoTypes) {
|
||||
@@ -730,6 +737,17 @@ function runTest(testNum) {
|
||||
doKey("return");
|
||||
checkForm("42");
|
||||
|
||||
input = $_(14, "field11");
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 405:
|
||||
checkMenuEntries(["2010-10-10"]);
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("2010-10-10");
|
||||
|
||||
// Go to test 500.
|
||||
fh.addEntry("field1", "value1");
|
||||
input = $_(1, "field1");
|
||||
|
||||
Reference in New Issue
Block a user