Bug 1286182 - Implement the layout for <input type=date>. r=mconley,smaug
This commit is contained in:
@@ -124,14 +124,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
|||||||
"Peaches", {"string": "linkAbbr"}, "Plums", {"string": "linkAbbr"},
|
"Peaches", {"string": "linkAbbr"}, "Plums", {"string": "linkAbbr"},
|
||||||
{"string": "listAbbr"},
|
{"string": "listAbbr"},
|
||||||
{"string": "cellInfoAbbr", "args": [ 1, 1]}]]
|
{"string": "cellInfoAbbr", "args": [ 1, 1]}]]
|
||||||
}, {
|
|
||||||
accOrElmOrID: "date",
|
|
||||||
expectedUtterance: [[{"string": "textInputType_date"},
|
|
||||||
{"string": "entry"}, "2011-09-29"], ["2011-09-29",
|
|
||||||
{"string": "textInputType_date"}, {"string": "entry"}]],
|
|
||||||
expectedBraille: [[{"string": "textInputType_date"},
|
|
||||||
{"string": "entryAbbr"}, "2011-09-29"], ["2011-09-29",
|
|
||||||
{"string": "textInputType_date"}, {"string": "entryAbbr"}]]
|
|
||||||
}, {
|
}, {
|
||||||
accOrElmOrID: "email",
|
accOrElmOrID: "email",
|
||||||
expectedUtterance: [[{"string": "textInputType_email"},
|
expectedUtterance: [[{"string": "textInputType_email"},
|
||||||
@@ -619,7 +611,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
|||||||
<label for="password">Secret Password</label><input id="password" type="password"></input>
|
<label for="password">Secret Password</label><input id="password" type="password"></input>
|
||||||
<label for="radio_unselected">any old radio button</label><input id="radio_unselected" type="radio"></input>
|
<label for="radio_unselected">any old radio button</label><input id="radio_unselected" type="radio"></input>
|
||||||
<label for="radio_selected">a unique radio button</label><input id="radio_selected" type="radio" checked></input>
|
<label for="radio_selected">a unique radio button</label><input id="radio_selected" type="radio" checked></input>
|
||||||
<input id="date" type="date" value="2011-09-29" />
|
|
||||||
<input id="email" type="email" value="test@example.com" />
|
<input id="email" type="email" value="test@example.com" />
|
||||||
<input id="search" type="search" value="This is a search" />
|
<input id="search" type="search" value="This is a search" />
|
||||||
<input id="tel" type="tel" value="555-5555" />
|
<input id="tel" type="tel" value="555-5555" />
|
||||||
|
|||||||
@@ -2763,7 +2763,8 @@ HTMLInputElement::GetOwnerDateTimeControl()
|
|||||||
HTMLInputElement::FromContentOrNull(
|
HTMLInputElement::FromContentOrNull(
|
||||||
GetParent()->GetParent()->GetParent()->GetParent());
|
GetParent()->GetParent()->GetParent()->GetParent());
|
||||||
if (ownerDateTimeControl &&
|
if (ownerDateTimeControl &&
|
||||||
ownerDateTimeControl->mType == NS_FORM_INPUT_TIME) {
|
(ownerDateTimeControl->mType == NS_FORM_INPUT_TIME ||
|
||||||
|
ownerDateTimeControl->mType == NS_FORM_INPUT_DATE)) {
|
||||||
return ownerDateTimeControl;
|
return ownerDateTimeControl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3215,7 +3216,8 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue, uint32_t aFlags)
|
|||||||
if (frame) {
|
if (frame) {
|
||||||
frame->UpdateForValueChange();
|
frame->UpdateForValueChange();
|
||||||
}
|
}
|
||||||
} else if (mType == NS_FORM_INPUT_TIME &&
|
} else if ((mType == NS_FORM_INPUT_TIME ||
|
||||||
|
mType == NS_FORM_INPUT_DATE) &&
|
||||||
!IsExperimentalMobileType(mType)) {
|
!IsExperimentalMobileType(mType)) {
|
||||||
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||||
if (frame) {
|
if (frame) {
|
||||||
@@ -3524,7 +3526,8 @@ HTMLInputElement::Blur(ErrorResult& aError)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mType == NS_FORM_INPUT_TIME && !IsExperimentalMobileType(mType)) {
|
if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
|
||||||
|
!IsExperimentalMobileType(mType)) {
|
||||||
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||||
if (frame) {
|
if (frame) {
|
||||||
frame->HandleBlurEvent();
|
frame->HandleBlurEvent();
|
||||||
@@ -3551,7 +3554,8 @@ HTMLInputElement::Focus(ErrorResult& aError)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mType == NS_FORM_INPUT_TIME && !IsExperimentalMobileType(mType)) {
|
if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
|
||||||
|
!IsExperimentalMobileType(mType)) {
|
||||||
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||||
if (frame) {
|
if (frame) {
|
||||||
frame->HandleFocusEvent();
|
frame->HandleFocusEvent();
|
||||||
@@ -3882,7 +3886,7 @@ HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mType == NS_FORM_INPUT_TIME &&
|
if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
|
||||||
!IsExperimentalMobileType(mType) &&
|
!IsExperimentalMobileType(mType) &&
|
||||||
aVisitor.mEvent->mMessage == eFocus &&
|
aVisitor.mEvent->mMessage == eFocus &&
|
||||||
aVisitor.mEvent->mOriginalTarget == this) {
|
aVisitor.mEvent->mOriginalTarget == this) {
|
||||||
@@ -4002,7 +4006,8 @@ HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
|||||||
// Stop the event if the related target's first non-native ancestor is the
|
// Stop the event if the related target's first non-native ancestor is the
|
||||||
// same as the original target's first non-native ancestor (we are moving
|
// same as the original target's first non-native ancestor (we are moving
|
||||||
// inside of the same element).
|
// inside of the same element).
|
||||||
if (mType == NS_FORM_INPUT_TIME && !IsExperimentalMobileType(mType) &&
|
if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
|
||||||
|
!IsExperimentalMobileType(mType) &&
|
||||||
(aVisitor.mEvent->mMessage == eFocus ||
|
(aVisitor.mEvent->mMessage == eFocus ||
|
||||||
aVisitor.mEvent->mMessage == eFocusIn ||
|
aVisitor.mEvent->mMessage == eFocusIn ||
|
||||||
aVisitor.mEvent->mMessage == eFocusOut ||
|
aVisitor.mEvent->mMessage == eFocusOut ||
|
||||||
@@ -7112,13 +7117,15 @@ HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t*
|
|||||||
|
|
||||||
if (mType == NS_FORM_INPUT_FILE ||
|
if (mType == NS_FORM_INPUT_FILE ||
|
||||||
mType == NS_FORM_INPUT_NUMBER ||
|
mType == NS_FORM_INPUT_NUMBER ||
|
||||||
mType == NS_FORM_INPUT_TIME) {
|
mType == NS_FORM_INPUT_TIME ||
|
||||||
|
mType == NS_FORM_INPUT_DATE) {
|
||||||
if (aTabIndex) {
|
if (aTabIndex) {
|
||||||
// We only want our native anonymous child to be tabable to, not ourself.
|
// We only want our native anonymous child to be tabable to, not ourself.
|
||||||
*aTabIndex = -1;
|
*aTabIndex = -1;
|
||||||
}
|
}
|
||||||
if (mType == NS_FORM_INPUT_NUMBER ||
|
if (mType == NS_FORM_INPUT_NUMBER ||
|
||||||
mType == NS_FORM_INPUT_TIME) {
|
mType == NS_FORM_INPUT_TIME ||
|
||||||
|
mType == NS_FORM_INPUT_DATE) {
|
||||||
*aIsFocusable = true;
|
*aIsFocusable = true;
|
||||||
} else {
|
} else {
|
||||||
*aIsFocusable = defaultFocusable;
|
*aIsFocusable = defaultFocusable;
|
||||||
|
|||||||
@@ -270,8 +270,8 @@ nsIFormControl::IsSingleLineTextControl(bool aExcludePassword, uint32_t aType)
|
|||||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||||
// On Android/B2G, date/time input appears as a normal text box.
|
// On Android/B2G, date/time input appears as a normal text box.
|
||||||
aType == NS_FORM_INPUT_TIME ||
|
aType == NS_FORM_INPUT_TIME ||
|
||||||
#endif
|
|
||||||
aType == NS_FORM_INPUT_DATE ||
|
aType == NS_FORM_INPUT_DATE ||
|
||||||
|
#endif
|
||||||
aType == NS_FORM_INPUT_MONTH ||
|
aType == NS_FORM_INPUT_MONTH ||
|
||||||
aType == NS_FORM_INPUT_WEEK ||
|
aType == NS_FORM_INPUT_WEEK ||
|
||||||
aType == NS_FORM_INPUT_DATETIME_LOCAL ||
|
aType == NS_FORM_INPUT_DATETIME_LOCAL ||
|
||||||
|
|||||||
@@ -30,8 +30,12 @@ skip-if = os == "android" # up/down arrow keys not supported on android
|
|||||||
skip-if = android_version == '18' # Android, bug 1147974
|
skip-if = android_version == '18' # Android, bug 1147974
|
||||||
[test_input_color_picker_update.html]
|
[test_input_color_picker_update.html]
|
||||||
skip-if = android_version == '18' # Android, bug 1147974
|
skip-if = android_version == '18' # Android, bug 1147974
|
||||||
|
[test_input_date_key_events.html]
|
||||||
|
skip-if = os == "android"
|
||||||
[test_input_datetime_focus_blur.html]
|
[test_input_datetime_focus_blur.html]
|
||||||
skip-if = os == "android"
|
skip-if = os == "android"
|
||||||
|
[test_input_datetime_focus_blur_events.html]
|
||||||
|
skip-if = os == "android"
|
||||||
[test_input_datetime_tabindex.html]
|
[test_input_datetime_tabindex.html]
|
||||||
skip-if = os == "android"
|
skip-if = os == "android"
|
||||||
[test_input_defaultValue.html]
|
[test_input_defaultValue.html]
|
||||||
@@ -61,8 +65,6 @@ skip-if = os == "android"
|
|||||||
[test_input_textarea_set_value_no_scroll.html]
|
[test_input_textarea_set_value_no_scroll.html]
|
||||||
[test_input_time_key_events.html]
|
[test_input_time_key_events.html]
|
||||||
skip-if = os == "android"
|
skip-if = os == "android"
|
||||||
[test_input_time_focus_blur_events.html]
|
|
||||||
skip-if = os == "android"
|
|
||||||
[test_input_types_pref.html]
|
[test_input_types_pref.html]
|
||||||
[test_input_typing_sanitization.html]
|
[test_input_typing_sanitization.html]
|
||||||
[test_input_untrusted_key_events.html]
|
[test_input_untrusted_key_events.html]
|
||||||
|
|||||||
228
dom/html/test/forms/test_input_date_key_events.html
Normal file
228
dom/html/test/forms/test_input_date_key_events.html
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1286182
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test key events for time control</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1286182">Mozilla Bug 1286182</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content">
|
||||||
|
<input id="input" type="date">
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
// Turn off Spatial Navigation because it hijacks arrow keydown events:
|
||||||
|
SimpleTest.waitForFocus(function() {
|
||||||
|
SpecialPowers.pushPrefEnv({"set":[["snav.enabled", false]]}, function() {
|
||||||
|
test();
|
||||||
|
SimpleTest.finish();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var testData = [
|
||||||
|
/**
|
||||||
|
* keys: keys to send to the input element.
|
||||||
|
* initialVal: initial value set to the input element.
|
||||||
|
* expectedVal: expected value of the input element after sending the keys.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
// Type 11222016, default order is month, day, year.
|
||||||
|
keys: ["11222016"],
|
||||||
|
initialVal: "",
|
||||||
|
expectedVal: "2016-11-22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Type 3 in the month field will automatically advance to the day field,
|
||||||
|
// then type 5 in the day field will automatically advance to the year
|
||||||
|
// field.
|
||||||
|
keys: ["352016"],
|
||||||
|
initialVal: "",
|
||||||
|
expectedVal: "2016-03-05"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Type 13 in the month field will set it to the maximum month, which is
|
||||||
|
// 12.
|
||||||
|
keys: ["13012016"],
|
||||||
|
initialVal: "",
|
||||||
|
expectedVal: "2016-12-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Type 00 in the month field will set it to the minimum month, which is 1.
|
||||||
|
keys: ["00012016"],
|
||||||
|
initialVal: "",
|
||||||
|
expectedVal: "2016-01-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Type 33 in the day field will set it to the maximum day, which is 31.
|
||||||
|
keys: ["12332016"],
|
||||||
|
initialVal: "",
|
||||||
|
expectedVal: "2016-12-31"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Type 00 in the day field will set it to the minimum day, which is 1.
|
||||||
|
keys: ["12002016"],
|
||||||
|
initialVal: "",
|
||||||
|
expectedVal: "2016-12-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Type 275769 in the year field will set it to the maximum year, which is
|
||||||
|
// 275760.
|
||||||
|
keys: ["0101275769"],
|
||||||
|
initialVal: "",
|
||||||
|
expectedVal: "275760-01-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Type 000000 in the year field will set it to the minimum year, which is
|
||||||
|
// 0001.
|
||||||
|
keys: ["0101000000"],
|
||||||
|
initialVal: "",
|
||||||
|
expectedVal: "0001-01-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Advance to year field and decrement.
|
||||||
|
keys: ["VK_TAB", "VK_TAB", "VK_DOWN"],
|
||||||
|
initialVal: "2016-11-25",
|
||||||
|
expectedVal: "2015-11-25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Right key should do the same thing as TAB key.
|
||||||
|
keys: ["VK_RIGHT", "VK_RIGHT", "VK_DOWN"],
|
||||||
|
initialVal: "2016-11-25",
|
||||||
|
expectedVal: "2015-11-25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Advance to day field then back to month field and decrement.
|
||||||
|
keys: ["VK_RIGHT", "VK_LEFT", "VK_DOWN"],
|
||||||
|
initialVal: "2000-05-01",
|
||||||
|
expectedVal: "2000-04-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Focus starts on the first field, month in this case, and increment.
|
||||||
|
keys: ["VK_UP"],
|
||||||
|
initialVal: "2000-03-01",
|
||||||
|
expectedVal: "2000-04-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Advance to day field and decrement.
|
||||||
|
keys: ["VK_TAB", "VK_DOWN"],
|
||||||
|
initialVal: "1234-01-01",
|
||||||
|
expectedVal: "1234-01-31"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Advance to day field and increment.
|
||||||
|
keys: ["VK_TAB", "VK_UP"],
|
||||||
|
initialVal: "1234-01-01",
|
||||||
|
expectedVal: "1234-01-02"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PageUp on month field increments month by 3.
|
||||||
|
keys: ["VK_PAGE_UP"],
|
||||||
|
initialVal: "1999-01-01",
|
||||||
|
expectedVal: "1999-04-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PageDown on month field decrements month by 3.
|
||||||
|
keys: ["VK_PAGE_DOWN"],
|
||||||
|
initialVal: "1999-01-01",
|
||||||
|
expectedVal: "1999-10-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PageUp on day field increments day by 7.
|
||||||
|
keys: ["VK_TAB", "VK_PAGE_UP"],
|
||||||
|
initialVal: "1999-01-01",
|
||||||
|
expectedVal: "1999-01-08"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PageDown on day field decrements day by 7.
|
||||||
|
keys: ["VK_TAB", "VK_PAGE_DOWN"],
|
||||||
|
initialVal: "1999-01-01",
|
||||||
|
expectedVal: "1999-01-25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PageUp on year field increments year by 10.
|
||||||
|
keys: ["VK_TAB", "VK_TAB", "VK_PAGE_UP"],
|
||||||
|
initialVal: "1999-01-01",
|
||||||
|
expectedVal: "2009-01-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PageDown on year field decrements year by 10.
|
||||||
|
keys: ["VK_TAB", "VK_TAB", "VK_PAGE_DOWN"],
|
||||||
|
initialVal: "1999-01-01",
|
||||||
|
expectedVal: "1989-01-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Home key on month field sets it to the minimum month, which is 01.
|
||||||
|
keys: ["VK_HOME"],
|
||||||
|
initialVal: "2016-06-01",
|
||||||
|
expectedVal: "2016-01-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// End key on month field sets it to the maximum month, which is 12.
|
||||||
|
keys: ["VK_END"],
|
||||||
|
initialVal: "2016-06-01",
|
||||||
|
expectedVal: "2016-12-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Home key on day field sets it to the minimum day, which is 01.
|
||||||
|
keys: ["VK_TAB", "VK_HOME"],
|
||||||
|
initialVal: "2016-01-10",
|
||||||
|
expectedVal: "2016-01-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// End key on day field sets it to the maximum day, which is 31.
|
||||||
|
keys: ["VK_TAB", "VK_END"],
|
||||||
|
initialVal: "2016-01-10",
|
||||||
|
expectedVal: "2016-01-31"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Home key on year field sets it to the minimum year, which is 0001.
|
||||||
|
keys: ["VK_TAB", "VK_TAB", "VK_HOME"],
|
||||||
|
initialVal: "2016-01-01",
|
||||||
|
expectedVal: "0001-01-01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// End key on year field sets it to the maximum year, which is 275760.
|
||||||
|
keys: ["VK_TAB", "VK_TAB", "VK_END"],
|
||||||
|
initialVal: "2016-01-01",
|
||||||
|
expectedVal: "275760-01-01"
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function sendKeys(aKeys) {
|
||||||
|
for (let i = 0; i < aKeys.length; i++) {
|
||||||
|
let key = aKeys[i];
|
||||||
|
if (key.startsWith("VK")) {
|
||||||
|
synthesizeKey(key, {});
|
||||||
|
} else {
|
||||||
|
sendString(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
var elem = document.getElementById("input");
|
||||||
|
|
||||||
|
for (let { keys, initialVal, expectedVal } of testData) {
|
||||||
|
elem.focus();
|
||||||
|
elem.value = initialVal;
|
||||||
|
sendKeys(keys);
|
||||||
|
elem.blur();
|
||||||
|
is(elem.value, expectedVal,
|
||||||
|
"Test with " + keys + ", result should be " + expectedVal);
|
||||||
|
elem.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
|
||||||
-->
|
-->
|
||||||
<head>
|
<head>
|
||||||
<title>Test focus/blur behaviour for <input type='time'></title>
|
<title>Test focus/blur behaviour for date/time input types</title>
|
||||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
</head>
|
</head>
|
||||||
@@ -12,7 +12,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
|
|||||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a>
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a>
|
||||||
<p id="display"></p>
|
<p id="display"></p>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<input id="input" type="time">
|
<input id="input_time" type="time">
|
||||||
|
<input id="input_date" type="date">
|
||||||
</div>
|
</div>
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
@@ -30,15 +31,15 @@ SimpleTest.waitForFocus(function() {
|
|||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
});
|
});
|
||||||
|
|
||||||
function test() {
|
function testFocusBlur(type) {
|
||||||
let time = document.getElementById("input");
|
let input = document.getElementById("input_" + type);
|
||||||
time.focus();
|
input.focus();
|
||||||
|
|
||||||
// The active element returns the input type=time.
|
// The active element returns the date/time input element.
|
||||||
let activeElement = document.activeElement;
|
let activeElement = document.activeElement;
|
||||||
is(activeElement, time, "activeElement should be the time element");
|
is(activeElement, input, "activeElement should be the date/time input element");
|
||||||
is(activeElement.localName, "input", "activeElement should be an input element");
|
is(activeElement.localName, "input", "activeElement should be an input element");
|
||||||
is(activeElement.type, "time", "activeElement should be of type time");
|
is(activeElement.type, type, "activeElement should be of type " + type);
|
||||||
|
|
||||||
// Use FocusManager to check that the actual focus is on the anonymous
|
// Use FocusManager to check that the actual focus is on the anonymous
|
||||||
// text control.
|
// text control.
|
||||||
@@ -48,10 +49,17 @@ function test() {
|
|||||||
is(focusedElement.localName, "input", "focusedElement should be an input element");
|
is(focusedElement.localName, "input", "focusedElement should be an input element");
|
||||||
is(focusedElement.type, "text", "focusedElement should be of type text");
|
is(focusedElement.type, "text", "focusedElement should be of type text");
|
||||||
|
|
||||||
time.blur();
|
input.blur();
|
||||||
isnot(document.activeElement, time, "activeElement should no longer be the time element");
|
isnot(document.activeElement, input, "activeElement should no longer be the datetime input element");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
let inputTypes = ["time", "date"];
|
||||||
|
|
||||||
|
for (let i = 0; i < inputTypes.length; i++) {
|
||||||
|
testFocusBlur(inputTypes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1301306
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 1301306</title>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.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=1301306">Mozilla Bug 722599</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content">
|
||||||
|
<input type="time" id="input_time" onfocus="++focusEvents[0]"
|
||||||
|
onblur="++blurEvents[0]" onfocusin="++focusInEvents[0]"
|
||||||
|
onfocusout="++focusOutEvents[0]">
|
||||||
|
<input type="date" id="input_date" onfocus="++focusEvents[1]"
|
||||||
|
onblur="++blurEvents[1]" onfocusin="++focusInEvents[1]"
|
||||||
|
onfocusout="++focusOutEvents[1]">
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for Bug 1301306.
|
||||||
|
* This test checks that when moving inside the time input element, e.g. jumping
|
||||||
|
* through the inner text boxes, does not fire extra focus/blur events.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var inputTypes = ["time", "date"];
|
||||||
|
var focusEvents = [0, 0];
|
||||||
|
var focusInEvents = [0, 0];
|
||||||
|
var focusOutEvents = [0, 0];
|
||||||
|
var blurEvents = [0, 0];
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
SimpleTest.waitForFocus(function() {
|
||||||
|
test();
|
||||||
|
SimpleTest.finish();
|
||||||
|
});
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
for (var i = 0; i < inputTypes.length; i++) {
|
||||||
|
var input = document.getElementById("input_" + inputTypes[i]);
|
||||||
|
|
||||||
|
input.focus();
|
||||||
|
is(focusEvents[i], 1, inputTypes[i] + " input element should have dispatched focus event.");
|
||||||
|
is(focusInEvents[i], 1, inputTypes[i] + " input element should have dispatched focusin event.");
|
||||||
|
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
|
||||||
|
is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
|
||||||
|
|
||||||
|
// Move around inside the input element's input box.
|
||||||
|
synthesizeKey("VK_TAB", {});
|
||||||
|
is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
|
||||||
|
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
|
||||||
|
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
|
||||||
|
is(blurEvents[i], 0, inputTypes[i] + " time input element should not have dispatched blur event.");
|
||||||
|
|
||||||
|
synthesizeKey("VK_RIGHT", {});
|
||||||
|
is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
|
||||||
|
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
|
||||||
|
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
|
||||||
|
is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
|
||||||
|
|
||||||
|
synthesizeKey("VK_LEFT", {});
|
||||||
|
is(focusEvents[i], 1,inputTypes[i] + " input element should not have dispatched focus event.");
|
||||||
|
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
|
||||||
|
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
|
||||||
|
is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
|
||||||
|
|
||||||
|
synthesizeKey("VK_RIGHT", {});
|
||||||
|
is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
|
||||||
|
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
|
||||||
|
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
|
||||||
|
is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
|
||||||
|
|
||||||
|
input.blur();
|
||||||
|
is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
|
||||||
|
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
|
||||||
|
is(focusOutEvents[i], 1, inputTypes[i] + " input element should have dispatched focusout event.");
|
||||||
|
is(blurEvents[i], 1, inputTypes[i] + " input element should have dispatched blur event.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
|
||||||
-->
|
-->
|
||||||
<head>
|
<head>
|
||||||
<title>Test tabindex attribute for <input type='time'></title>
|
<title>Test tabindex attribute for date/time input types</title>
|
||||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
@@ -16,13 +16,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
|
|||||||
<input id="time1" type="time" tabindex="0">
|
<input id="time1" type="time" tabindex="0">
|
||||||
<input id="time2" type="time" tabindex="-1">
|
<input id="time2" type="time" tabindex="-1">
|
||||||
<input id="time3" type="time" tabindex="0">
|
<input id="time3" type="time" tabindex="0">
|
||||||
|
<input id="date1" type="date" tabindex="0">
|
||||||
|
<input id="date2" type="date" tabindex="-1">
|
||||||
|
<input id="date3" type="date" tabindex="0">
|
||||||
</div>
|
</div>
|
||||||
<pre id="test">
|
<pre id="test">
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for Bug 1288591.
|
* Test for Bug 1288591.
|
||||||
* This test checks whether date/time input types' tabindex attribute works
|
* This test checks whether date/time input types tabindex attribute works
|
||||||
* correctly.
|
* correctly.
|
||||||
**/
|
**/
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
@@ -31,41 +34,49 @@ SimpleTest.waitForFocus(function() {
|
|||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
});
|
});
|
||||||
|
|
||||||
function test() {
|
function testTabindex(type) {
|
||||||
let time1 = document.getElementById("time1");
|
let input1 = document.getElementById(type + "1");
|
||||||
let time2 = document.getElementById("time2");
|
let input2 = document.getElementById(type + "2");
|
||||||
let time3 = document.getElementById("time3");
|
let input3 = document.getElementById(type + "3");
|
||||||
|
|
||||||
time1.focus();
|
input1.focus();
|
||||||
is(document.activeElement, time1,
|
is(document.activeElement, input1,
|
||||||
"input element with tabindex=0 is focusable");
|
"input element with tabindex=0 is focusable");
|
||||||
|
|
||||||
// Advance to time1 minute field
|
// Advance to next inner field
|
||||||
synthesizeKey("VK_TAB", {});
|
synthesizeKey("VK_TAB", {});
|
||||||
is(document.activeElement, time1,
|
is(document.activeElement, input1,
|
||||||
"input element with tabindex=0 is tabbable");
|
"input element with tabindex=0 is tabbable");
|
||||||
|
|
||||||
// Advance to time1 AM/PM field
|
// Advance to next inner field
|
||||||
synthesizeKey("VK_TAB", {});
|
synthesizeKey("VK_TAB", {});
|
||||||
is(document.activeElement, time1,
|
is(document.activeElement, input1,
|
||||||
"input element with tabindex=0 is tabbable");
|
"input element with tabindex=0 is tabbable");
|
||||||
|
|
||||||
// Advance to next element
|
// Advance to next element
|
||||||
synthesizeKey("VK_TAB", {});
|
synthesizeKey("VK_TAB", {});
|
||||||
is(document.activeElement, time3,
|
is(document.activeElement, input3,
|
||||||
"input element with tabindex=-1 is not tabbable");
|
"input element with tabindex=-1 is not tabbable");
|
||||||
|
|
||||||
time2.focus();
|
input2.focus();
|
||||||
is(document.activeElement, time2,
|
is(document.activeElement, input2,
|
||||||
"input element with tabindex=-1 is still focusable");
|
"input element with tabindex=-1 is still focusable");
|
||||||
|
|
||||||
// Changing the tabindex attribute dynamically.
|
// Changing the tabindex attribute dynamically.
|
||||||
time3.setAttribute("tabindex", "-1");
|
input3.setAttribute("tabindex", "-1");
|
||||||
synthesizeKey("VK_TAB", {}); // need only one TAB since time2 is not tabbable
|
synthesizeKey("VK_TAB", {}); // need only one TAB since input2 is not tabbable
|
||||||
isnot(document.activeElement, time3,
|
isnot(document.activeElement, input3,
|
||||||
"element with tabindex changed to -1 should not be tabbable");
|
"element with tabindex changed to -1 should not be tabbable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
let inputTypes = ["time", "date"];
|
||||||
|
|
||||||
|
for (let i = 0; i < inputTypes.length; i++) {
|
||||||
|
testTabindex(inputTypes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
<!DOCTYPE HTML>
|
|
||||||
<html>
|
|
||||||
<!--
|
|
||||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1301306
|
|
||||||
-->
|
|
||||||
<head>
|
|
||||||
<title>Test for Bug 1301306</title>
|
|
||||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.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=1301306">Mozilla Bug 722599</a>
|
|
||||||
<p id="display"></p>
|
|
||||||
<div id="content">
|
|
||||||
<input type="time" id="input_time" onfocus="++focusEvent" onblur="++blurEvent"
|
|
||||||
onfocusin="++focusInEvent" onfocusout="++focusOutEvent">
|
|
||||||
</div>
|
|
||||||
<pre id="test">
|
|
||||||
<script class="testbody" type="text/javascript">
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for Bug 1301306.
|
|
||||||
* This test checks that when moving inside the time input element, e.g. jumping
|
|
||||||
* through the inner text boxes, does not fire extra focus/blur events.
|
|
||||||
**/
|
|
||||||
|
|
||||||
var focusEvent = 0;
|
|
||||||
var focusInEvent = 0;
|
|
||||||
var focusOutEvent = 0;
|
|
||||||
var blurEvent = 0;
|
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
|
||||||
SimpleTest.waitForFocus(function() {
|
|
||||||
test();
|
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
var time = document.getElementById("input_time");
|
|
||||||
time.focus();
|
|
||||||
is(focusEvent, 1, "time input element should have dispatched focus event.");
|
|
||||||
is(focusInEvent, 1, "time input element should have dispatched focusin event.");
|
|
||||||
is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
|
|
||||||
is(blurEvent, 0, "time input element should not have dispatched blur event.");
|
|
||||||
|
|
||||||
// Move around inside the input element's input box.
|
|
||||||
synthesizeKey("VK_TAB", {});
|
|
||||||
is(focusEvent, 1, "time input element should not have dispatched focus event.");
|
|
||||||
is(focusInEvent, 1, "time input element should have dispatched focusin event.");
|
|
||||||
is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
|
|
||||||
is(blurEvent, 0, "time input element should not have dispatched blur event.");
|
|
||||||
|
|
||||||
synthesizeKey("VK_RIGHT", {});
|
|
||||||
is(focusEvent, 1, "time input element should not have dispatched focus event.");
|
|
||||||
is(focusInEvent, 1, "time input element should have dispatched focusin event.");
|
|
||||||
is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
|
|
||||||
is(blurEvent, 0, "time input element should not have dispatched blur event.");
|
|
||||||
|
|
||||||
synthesizeKey("VK_LEFT", {});
|
|
||||||
is(focusEvent, 1, "time input element should not have dispatched focus event.");
|
|
||||||
is(focusInEvent, 1, "time input element should have dispatched focusin event.");
|
|
||||||
is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
|
|
||||||
is(blurEvent, 0, "time input element should not have dispatched blur event.");
|
|
||||||
|
|
||||||
synthesizeKey("VK_RIGHT", {});
|
|
||||||
is(focusEvent, 1, "time input element should not have dispatched focus event.");
|
|
||||||
is(focusInEvent, 1, "time input element should have dispatched focusin event.");
|
|
||||||
is(focusOutEvent, 0, "time input element should not have dispatched focusout event.");
|
|
||||||
is(blurEvent, 0, "time input element should not have dispatched blur event.");
|
|
||||||
|
|
||||||
time.blur();
|
|
||||||
is(focusEvent, 1, "time input element should not have dispatched focus event.");
|
|
||||||
is(focusInEvent, 1, "time input element should have dispatched focusin event.");
|
|
||||||
is(focusOutEvent, 1, "time input element should not have dispatched focusout event.");
|
|
||||||
is(blurEvent, 1, "time input element should have dispatched blur event.");
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</pre>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -26,6 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=765772
|
|||||||
* This test checks that when a user types in some input types, it will not be
|
* This test checks that when a user types in some input types, it will not be
|
||||||
* in a state where the value will be un-sanitized and usable (by a script).
|
* in a state where the value will be un-sanitized and usable (by a script).
|
||||||
*/
|
*/
|
||||||
|
const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
|
||||||
|
|
||||||
var input = document.getElementById('i');
|
var input = document.getElementById('i');
|
||||||
var form = document.getElementById('f');
|
var form = document.getElementById('f');
|
||||||
@@ -138,6 +139,7 @@ function* runTest()
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
mobileOnly: true,
|
||||||
type: 'date',
|
type: 'date',
|
||||||
validData: [
|
validData: [
|
||||||
'0001-01-01',
|
'0001-01-01',
|
||||||
@@ -155,6 +157,28 @@ function* runTest()
|
|||||||
'1000-12-99',
|
'1000-12-99',
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
mobileOnly: true,
|
||||||
|
type: 'time',
|
||||||
|
validData: [
|
||||||
|
'00:00',
|
||||||
|
'09:09:00',
|
||||||
|
'08:23:23.1',
|
||||||
|
'21:43:56.12',
|
||||||
|
'23:12:45.100',
|
||||||
|
],
|
||||||
|
invalidData: [
|
||||||
|
'00:',
|
||||||
|
'00:00:',
|
||||||
|
'25:00',
|
||||||
|
'-00:00',
|
||||||
|
'00:00:00.',
|
||||||
|
'00:60',
|
||||||
|
'10:58:99',
|
||||||
|
':19:10',
|
||||||
|
'23:08:09.1012',
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'month',
|
type: 'month',
|
||||||
validData: [
|
validData: [
|
||||||
@@ -213,6 +237,10 @@ function* runTest()
|
|||||||
for (test of data) {
|
for (test of data) {
|
||||||
gCurrentTest = test;
|
gCurrentTest = test;
|
||||||
|
|
||||||
|
if (gCurrentTest.mobileOnly && isDesktop) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
input.type = test.type;
|
input.type = test.type;
|
||||||
gValidData = test.validData;
|
gValidData = test.validData;
|
||||||
gInvalidData = test.invalidData;
|
gInvalidData = test.invalidData;
|
||||||
|
|||||||
@@ -3664,13 +3664,13 @@ nsCSSFrameConstructor::FindInputData(Element* aElement,
|
|||||||
nsCSSAnonBoxes::buttonContent) },
|
nsCSSAnonBoxes::buttonContent) },
|
||||||
// TODO: this is temporary until a frame is written: bug 635240.
|
// TODO: this is temporary until a frame is written: bug 635240.
|
||||||
SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame),
|
SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame),
|
||||||
// TODO: this is temporary until a frame is written: bug 888320.
|
|
||||||
SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewTextControlFrame),
|
|
||||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||||
// On Android/B2G, date/time input appears as a normal text box.
|
// On Android/B2G, date/time input appears as a normal text box.
|
||||||
SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewTextControlFrame),
|
SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewTextControlFrame),
|
||||||
|
SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewTextControlFrame),
|
||||||
#else
|
#else
|
||||||
SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewDateTimeControlFrame),
|
SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewDateTimeControlFrame),
|
||||||
|
SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewDateTimeControlFrame),
|
||||||
#endif
|
#endif
|
||||||
// TODO: this is temporary until a frame is written: bug 888320
|
// TODO: this is temporary until a frame is written: bug 888320
|
||||||
SIMPLE_INT_CREATE(NS_FORM_INPUT_MONTH, NS_NewTextControlFrame),
|
SIMPLE_INT_CREATE(NS_FORM_INPUT_MONTH, NS_NewTextControlFrame),
|
||||||
|
|||||||
@@ -372,7 +372,8 @@ nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
|
|||||||
auto contentAsInputElem = static_cast<dom::HTMLInputElement*>(mContent);
|
auto contentAsInputElem = static_cast<dom::HTMLInputElement*>(mContent);
|
||||||
// If script changed the <input>'s type before setting these attributes
|
// If script changed the <input>'s type before setting these attributes
|
||||||
// then we don't need to do anything since we are going to be reframed.
|
// then we don't need to do anything since we are going to be reframed.
|
||||||
if (contentAsInputElem->GetType() == NS_FORM_INPUT_TIME) {
|
if (contentAsInputElem->GetType() == NS_FORM_INPUT_TIME ||
|
||||||
|
contentAsInputElem->GetType() == NS_FORM_INPUT_DATE) {
|
||||||
if (aAttribute == nsGkAtoms::value) {
|
if (aAttribute == nsGkAtoms::value) {
|
||||||
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
|
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
|
||||||
do_QueryInterface(mInputAreaContent);
|
do_QueryInterface(mInputAreaContent);
|
||||||
|
|||||||
@@ -776,6 +776,11 @@ input[type="time"] > xul|datetimebox {
|
|||||||
-moz-binding: url("chrome://global/content/bindings/datetimebox.xml#time-input");
|
-moz-binding: url("chrome://global/content/bindings/datetimebox.xml#time-input");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type="date"] > xul|datetimebox {
|
||||||
|
display: flex;
|
||||||
|
-moz-binding: url("chrome://global/content/bindings/datetimebox.xml#date-input");
|
||||||
|
}
|
||||||
|
|
||||||
/* details & summary */
|
/* details & summary */
|
||||||
details > summary:first-of-type,
|
details > summary:first-of-type,
|
||||||
details > summary:-moz-native-anonymous {
|
details > summary:-moz-native-anonymous {
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ function setupFormHistory(aCallback) {
|
|||||||
{ op : "add", fieldname : "field8", value : "value" },
|
{ op : "add", fieldname : "field8", value : "value" },
|
||||||
{ op : "add", fieldname : "field9", value : "value" },
|
{ op : "add", fieldname : "field9", value : "value" },
|
||||||
{ op : "add", fieldname : "field10", value : "42" },
|
{ op : "add", fieldname : "field10", value : "42" },
|
||||||
{ op : "add", fieldname : "field11", value : "2010-10-10" },
|
{ op : "add", fieldname : "field11", value : "2010-10-10" }, // not used, since type=date doesn't have autocomplete currently
|
||||||
{ op : "add", fieldname : "field12", value : "21:21" }, // not used, since type=time doesn't have autocomplete currently
|
{ op : "add", fieldname : "field12", value : "21:21" }, // not used, since type=time doesn't have autocomplete currently
|
||||||
{ op : "add", fieldname : "field13", value : "32" }, // not used, since type=range doesn't have a drop down menu
|
{ op : "add", fieldname : "field13", value : "32" }, // not used, since type=range doesn't have a drop down menu
|
||||||
{ op : "add", fieldname : "field14", value : "#ffffff" }, // not used, since type=color doesn't have autocomplete currently
|
{ op : "add", fieldname : "field14", value : "#ffffff" }, // not used, since type=color doesn't have autocomplete currently
|
||||||
@@ -899,15 +899,13 @@ function runTest() {
|
|||||||
|
|
||||||
input = $_(14, "field11");
|
input = $_(14, "field11");
|
||||||
restoreForm();
|
restoreForm();
|
||||||
expectPopup();
|
waitForMenuChange(0);
|
||||||
doKey("down");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 405:
|
case 405:
|
||||||
checkMenuEntries(["2010-10-10"]);
|
checkMenuEntries([]); // type=date with it's own control frame does not
|
||||||
doKey("down");
|
// have a drop down menu for now
|
||||||
doKey("return");
|
checkForm("");
|
||||||
checkForm("2010-10-10");
|
|
||||||
|
|
||||||
input = $_(15, "field12");
|
input = $_(15, "field12");
|
||||||
restoreForm();
|
restoreForm();
|
||||||
|
|||||||
@@ -10,6 +10,405 @@
|
|||||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||||
|
|
||||||
|
<binding id="date-input"
|
||||||
|
extends="chrome://global/content/bindings/datetimebox.xml#datetime-input-base">
|
||||||
|
<resources>
|
||||||
|
<stylesheet src="chrome://global/content/textbox.css"/>
|
||||||
|
<stylesheet src="chrome://global/skin/textbox.css"/>
|
||||||
|
<stylesheet src="chrome://global/content/bindings/datetimebox.css"/>
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<implementation>
|
||||||
|
<constructor>
|
||||||
|
<![CDATA[
|
||||||
|
// TODO: Bug 1320227 - [DateTimeInput] localization for
|
||||||
|
// <input type=date> input box
|
||||||
|
this.mMonthPlaceHolder = "mm";
|
||||||
|
this.mDayPlaceHolder = "dd";
|
||||||
|
this.mYearPlaceHolder = "yyyy";
|
||||||
|
this.mSeparatorText = "/";
|
||||||
|
this.mMinMonth = 1;
|
||||||
|
this.mMaxMonth = 12;
|
||||||
|
this.mMinDay = 1;
|
||||||
|
this.mMaxDay = 31;
|
||||||
|
this.mMinYear = 1;
|
||||||
|
// Maximum year limited by ECMAScript date object range, year <= 275760.
|
||||||
|
this.mMaxYear = 275760;
|
||||||
|
this.mMonthDayLength = 2;
|
||||||
|
this.mYearLength = 4;
|
||||||
|
this.mMonthPageUpDownInterval = 3;
|
||||||
|
this.mDayPageUpDownInterval = 7;
|
||||||
|
this.mYearPageUpDownInterval = 10;
|
||||||
|
|
||||||
|
// Default to en-US, month-day-year order.
|
||||||
|
this.mMonthField =
|
||||||
|
document.getAnonymousElementByAttribute(this, "anonid", "input-one");
|
||||||
|
this.mDayField =
|
||||||
|
document.getAnonymousElementByAttribute(this, "anonid", "input-two");
|
||||||
|
this.mYearField =
|
||||||
|
document.getAnonymousElementByAttribute(this, "anonid", "input-three");
|
||||||
|
this.mYearField.size = this.mYearLength;
|
||||||
|
this.mYearField.maxLength = this.mMaxYear.toString().length;
|
||||||
|
|
||||||
|
this.mMonthField.placeholder = this.mMonthPlaceHolder;
|
||||||
|
this.mDayField.placeholder = this.mDayPlaceHolder;
|
||||||
|
this.mYearField.placeholder = this.mYearPlaceHolder;
|
||||||
|
|
||||||
|
this.mMonthField.setAttribute("min", this.mMinMonth);
|
||||||
|
this.mMonthField.setAttribute("max", this.mMaxMonth);
|
||||||
|
this.mMonthField.setAttribute("pginterval",
|
||||||
|
this.mMonthPageUpDownInterval);
|
||||||
|
this.mDayField.setAttribute("min", this.mMinDay);
|
||||||
|
this.mDayField.setAttribute("max", this.mMaxDay);
|
||||||
|
this.mDayField.setAttribute("pginterval", this.mDayPageUpDownInterval);
|
||||||
|
this.mYearField.setAttribute("min", this.mMinYear);
|
||||||
|
this.mYearField.setAttribute("max", this.mMaxYear);
|
||||||
|
this.mYearField.setAttribute("pginterval",
|
||||||
|
this.mYearPageUpDownInterval);
|
||||||
|
|
||||||
|
this.mDaySeparator =
|
||||||
|
document.getAnonymousElementByAttribute(this, "anonid", "sep-first");
|
||||||
|
this.mDaySeparator.textContent = this.mSeparatorText;
|
||||||
|
this.mYearSeparator =
|
||||||
|
document.getAnonymousElementByAttribute(this, "anonid", "sep-second");
|
||||||
|
this.mYearSeparator.textContent = this.mSeparatorText;
|
||||||
|
|
||||||
|
if (this.mInputElement.value) {
|
||||||
|
this.setFieldsFromInputValue();
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</constructor>
|
||||||
|
|
||||||
|
<method name="clearInputFields">
|
||||||
|
<parameter name="aFromInputElement"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
this.log("clearInputFields");
|
||||||
|
|
||||||
|
if (this.isDisabled() || this.isReadonly()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mMonthField && !this.mMonthField.disabled &&
|
||||||
|
!this.mMonthField.readOnly) {
|
||||||
|
this.mMonthField.value = "";
|
||||||
|
this.mMonthField.setAttribute("typeBuffer", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mDayField && !this.mDayField.disabled &&
|
||||||
|
!this.mDayField.readOnly) {
|
||||||
|
this.mDayField.value = "";
|
||||||
|
this.mDayField.setAttribute("typeBuffer", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mYearField && !this.mYearField.disabled &&
|
||||||
|
!this.mYearField.readOnly) {
|
||||||
|
this.mYearField.value = "";
|
||||||
|
this.mYearField.setAttribute("typeBuffer", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aFromInputElement) {
|
||||||
|
this.mInputElement.setUserInput("");
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="setFieldsFromInputValue">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
let value = this.mInputElement.value;
|
||||||
|
if (!value) {
|
||||||
|
this.clearInputFields(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log("setFieldsFromInputValue: " + value);
|
||||||
|
let [year, month, day] = value.split("-");
|
||||||
|
|
||||||
|
this.setFieldValue(this.mYearField, year);
|
||||||
|
this.setFieldValue(this.mMonthField, month);
|
||||||
|
this.setFieldValue(this.mDayField, day);
|
||||||
|
|
||||||
|
this.notifyPicker();
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="getDaysInMonth">
|
||||||
|
<parameter name="aMonth"/>
|
||||||
|
<parameter name="aYear"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
// Javascript's month is 0-based, so this means last day of the
|
||||||
|
// previous month.
|
||||||
|
return new Date(aYear, aMonth, 0).getDate();
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="isFieldInvalid">
|
||||||
|
<parameter name="aField"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
if (this.isEmpty(aField.value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let min = Number(aField.getAttribute("min"));
|
||||||
|
let max = Number(aField.getAttribute("max"));
|
||||||
|
|
||||||
|
if (Number(aField.value) < min || Number(aField.value) > max) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="setInputValueFromFields">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
if (this.isFieldInvalid(this.mYearField) ||
|
||||||
|
this.isFieldInvalid(this.mMonthField) ||
|
||||||
|
this.isFieldInvalid(this.mDayField)) {
|
||||||
|
// We still need to notify picker in case any of the field has
|
||||||
|
// changed. If we can set input element value, then notifyPicker
|
||||||
|
// will be called in setFieldsFromInputValue().
|
||||||
|
this.notifyPicker();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let year = this.mYearField.value;
|
||||||
|
let month = this.mMonthField.value;
|
||||||
|
let day = this.mDayField.value;
|
||||||
|
|
||||||
|
if (day > this.getDaysInMonth(month, year)) {
|
||||||
|
// Don't set invalid date, otherwise input element's value will be
|
||||||
|
// set to empty.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let date = [year, month, day].join("-");
|
||||||
|
|
||||||
|
this.log("setInputValueFromFields: " + date);
|
||||||
|
this.mInputElement.setUserInput(date);
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="setFieldsFromPicker">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
// TODO: Bug 1320225 - [DateTimeInput] Integration of input type=date
|
||||||
|
// input box with picker.
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="handleKeypress">
|
||||||
|
<parameter name="aEvent"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
if (this.isDisabled() || this.isReadonly()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetField = aEvent.originalTarget;
|
||||||
|
let key = aEvent.key;
|
||||||
|
|
||||||
|
if (targetField.classList.contains("numeric") && key.match(/[0-9]/)) {
|
||||||
|
let buffer = targetField.getAttribute("typeBuffer") || "";
|
||||||
|
|
||||||
|
buffer = buffer.concat(key);
|
||||||
|
this.setFieldValue(targetField, buffer);
|
||||||
|
targetField.select();
|
||||||
|
|
||||||
|
let n = Number(buffer);
|
||||||
|
let max = targetField.getAttribute("max");
|
||||||
|
if (buffer.length >= targetField.maxLength || n * 10 > max) {
|
||||||
|
buffer = "";
|
||||||
|
this.advanceToNextField();
|
||||||
|
}
|
||||||
|
targetField.setAttribute("typeBuffer", buffer);
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="incrementFieldValue">
|
||||||
|
<parameter name="aTargetField"/>
|
||||||
|
<parameter name="aTimes"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
let value;
|
||||||
|
|
||||||
|
// Use current date if field is empty.
|
||||||
|
if (this.isEmpty(aTargetField.value)) {
|
||||||
|
let now = new Date();
|
||||||
|
|
||||||
|
if (aTargetField == this.mYearField) {
|
||||||
|
value = now.getFullYear();
|
||||||
|
} else if (aTargetField == this.mMonthField) {
|
||||||
|
value = now.getMonth() + 1;
|
||||||
|
} else if (aTargetField == this.mDayField) {
|
||||||
|
value = now.getDate();
|
||||||
|
} else {
|
||||||
|
this.log("Field not supported in incrementFieldValue.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = Number(aTargetField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let min = Number(aTargetField.getAttribute("min"));
|
||||||
|
let max = Number(aTargetField.getAttribute("max"));
|
||||||
|
|
||||||
|
value += Number(aTimes);
|
||||||
|
if (value > max) {
|
||||||
|
value -= (max - min + 1);
|
||||||
|
} else if (value < min) {
|
||||||
|
value += (max - min + 1);
|
||||||
|
}
|
||||||
|
this.setFieldValue(aTargetField, value);
|
||||||
|
aTargetField.select();
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="handleKeyboardNav">
|
||||||
|
<parameter name="aEvent"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
if (this.isDisabled() || this.isReadonly()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetField = aEvent.originalTarget;
|
||||||
|
let key = aEvent.key;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case "ArrowUp":
|
||||||
|
this.incrementFieldValue(targetField, 1);
|
||||||
|
break;
|
||||||
|
case "ArrowDown":
|
||||||
|
this.incrementFieldValue(targetField, -1);
|
||||||
|
break;
|
||||||
|
case "PageUp": {
|
||||||
|
let interval = targetField.getAttribute("pginterval");
|
||||||
|
this.incrementFieldValue(targetField, interval);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "PageDown": {
|
||||||
|
let interval = targetField.getAttribute("pginterval");
|
||||||
|
this.incrementFieldValue(targetField, 0 - interval);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "Home":
|
||||||
|
let min = targetField.getAttribute("min");
|
||||||
|
this.setFieldValue(targetField, min);
|
||||||
|
targetField.select();
|
||||||
|
break;
|
||||||
|
case "End":
|
||||||
|
let max = targetField.getAttribute("max");
|
||||||
|
this.setFieldValue(targetField, max);
|
||||||
|
targetField.select();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.setInputValueFromFields();
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="getCurrentValue">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
let year;
|
||||||
|
if (!this.isEmpty(this.mYearField.value)) {
|
||||||
|
year = Number(this.mYearField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let month;
|
||||||
|
if (!this.isEmpty(this.mMonthField.value)) {
|
||||||
|
month = Number(this.mMonthField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let day;
|
||||||
|
if (!this.isEmpty(this.mDayField.value)) {
|
||||||
|
day = Number(this.mDayField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let date = { year, month, day };
|
||||||
|
|
||||||
|
this.log("getCurrentValue: " + JSON.stringify(date));
|
||||||
|
return date;
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="setFieldValue">
|
||||||
|
<parameter name="aField"/>
|
||||||
|
<parameter name="aValue"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
let value = Number(aValue);
|
||||||
|
if (isNaN(value)) {
|
||||||
|
this.log("NaN on setFieldValue!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aValue.length == aField.maxLength) {
|
||||||
|
let min = Number(aField.getAttribute("min"));
|
||||||
|
let max = Number(aField.getAttribute("max"));
|
||||||
|
|
||||||
|
if (aValue < min) {
|
||||||
|
value = min;
|
||||||
|
} else if (aValue > max) {
|
||||||
|
value = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aField == this.mMonthField ||
|
||||||
|
aField == this.mDayField) {
|
||||||
|
// prepend zero
|
||||||
|
if (value < 10) {
|
||||||
|
value = "0" + value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// prepend zeroes
|
||||||
|
if (value < 10) {
|
||||||
|
value = "000" + value;
|
||||||
|
} else if (value < 100) {
|
||||||
|
value = "00" + value;
|
||||||
|
} else if (value < 1000) {
|
||||||
|
value = "0" + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.toString().length > this.mYearLength &&
|
||||||
|
value.toString().length <= this.mMaxYear.toString().length) {
|
||||||
|
this.mYearField.size = value.toString().length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aField.value = value;
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="isValueAvailable">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
return !this.isEmpty(this.mMonthField.value) ||
|
||||||
|
!this.isEmpty(this.mDayField.value) ||
|
||||||
|
!this.isEmpty(this.mYearField.value);
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
</implementation>
|
||||||
|
</binding>
|
||||||
|
|
||||||
<binding id="time-input"
|
<binding id="time-input"
|
||||||
extends="chrome://global/content/bindings/datetimebox.xml#datetime-input-base">
|
extends="chrome://global/content/bindings/datetimebox.xml#datetime-input-base">
|
||||||
<resources>
|
<resources>
|
||||||
@@ -745,6 +1144,12 @@
|
|||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
<method name="getCurrentValue">
|
||||||
|
<body>
|
||||||
|
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
<method name="notifyPicker">
|
<method name="notifyPicker">
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
@@ -791,7 +1196,7 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "blur": {
|
case "blur": {
|
||||||
this.setInputValueFromFields();
|
this.onBlur(aEvent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "copy":
|
case "copy":
|
||||||
@@ -822,6 +1227,19 @@
|
|||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
<method name="onBlur">
|
||||||
|
<parameter name="aEvent"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
this.log("onBlur originalTarget: " + aEvent.originalTarget);
|
||||||
|
|
||||||
|
let target = aEvent.originalTarget;
|
||||||
|
target.setAttribute("typeBuffer", "");
|
||||||
|
this.setInputValueFromFields();
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
<method name="onKeyPress">
|
<method name="onKeyPress">
|
||||||
<parameter name="aEvent"/>
|
<parameter name="aEvent"/>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Reference in New Issue
Block a user