mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
implement valid Date time Local input
This commit is contained in:
parent
bcdb82b83f
commit
b43424111e
7 changed files with 111 additions and 125 deletions
|
@ -302,6 +302,20 @@ impl DOMString {
|
||||||
pub fn is_valid_week_string(&self) -> bool {
|
pub fn is_valid_week_string(&self) -> bool {
|
||||||
parse_week_string(&*self.0).is_ok()
|
parse_week_string(&*self.0).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A valid normalized local date and time string should be "{date}T{time}"
|
||||||
|
/// where date and time are both valid, and the time string must be as short as possible
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#valid-normalised-local-date-and-time-string
|
||||||
|
pub fn convert_valid_normalized_local_date_and_time_string(&mut self) -> Result<(), ()> {
|
||||||
|
let ((year, month, day), (hour, minute, second)) = parse_local_date_and_time_string(&*self.0)?;
|
||||||
|
if second == 0.0 {
|
||||||
|
self.0 = format!("{:04}-{:02}-{:02}T{:02}:{:02}", year, month, day, hour, minute);
|
||||||
|
} else {
|
||||||
|
self.0 = format!("{:04}-{:02}-{:02}T{:02}:{:02}:{}", year, month, day, hour, minute, second);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Borrow<str> for DOMString {
|
impl Borrow<str> for DOMString {
|
||||||
|
@ -541,6 +555,84 @@ fn parse_date_component(value: &str) -> Result<(u32, u32, u32), ()> {
|
||||||
Ok((year_int, month_int, day_int))
|
Ok((year_int, month_int, day_int))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#parse-a-time-component
|
||||||
|
fn parse_time_component(value: &str) -> Result<(u32, u32, f32), ()> {
|
||||||
|
// Step 1
|
||||||
|
let mut iterator = value.split(':');
|
||||||
|
let hour = iterator.next().ok_or(())?;
|
||||||
|
if hour.len() != 2 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
let hour_int = hour.parse::<u32>().map_err(|_| ())?;
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
if hour_int > 23 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3, 4
|
||||||
|
let minute = iterator.next().ok_or(())?;
|
||||||
|
if minute.len() != 2 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
let minute_int = minute.parse::<u32>().map_err(|_| ())?;
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
if minute_int > 59 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6, 7
|
||||||
|
let second_float = match iterator.next() {
|
||||||
|
Some(second) => {
|
||||||
|
let mut second_iterator = second.split('.');
|
||||||
|
if second_iterator.next().ok_or(())?.len() != 2 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
match second_iterator.next() {
|
||||||
|
Some(second_last) => {
|
||||||
|
if second_last.len() > 3 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
second.parse::<f32>().map_err(|_| ())?
|
||||||
|
},
|
||||||
|
None => 0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
Ok((hour_int, minute_int, second_float))
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#parse-a-local-date-and-time-string
|
||||||
|
fn parse_local_date_and_time_string(value: &str) -> Result<((u32, u32, u32), (u32, u32, f32)), ()> {
|
||||||
|
// Step 1, 2, 4
|
||||||
|
let mut iterator = if value.contains('T') {
|
||||||
|
value.split('T')
|
||||||
|
} else {
|
||||||
|
value.split(' ')
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
let date = iterator.next().ok_or(())?;
|
||||||
|
let date_tuple = parse_date_component(date)?;
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
let time = iterator.next().ok_or(())?;
|
||||||
|
let time_tuple = parse_time_component(time)?;
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
if iterator.next().is_some() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7, 8, 9
|
||||||
|
Ok((date_tuple, time_tuple))
|
||||||
|
}
|
||||||
|
|
||||||
fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
|
fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
|
||||||
match month_num {
|
match month_num {
|
||||||
1|3|5|7|8|10|12 => Ok(31),
|
1|3|5|7|8|10|12 => Ok(31),
|
||||||
|
|
|
@ -996,19 +996,19 @@ impl HTMLInputElement {
|
||||||
InputType::Date => {
|
InputType::Date => {
|
||||||
let mut textinput = self.textinput.borrow_mut();
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
if !textinput.single_line_content().is_valid_date_string() {
|
if !textinput.single_line_content().is_valid_date_string() {
|
||||||
*textinput.single_line_content_mut() = "".into();
|
textinput.single_line_content_mut().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputType::Month => {
|
InputType::Month => {
|
||||||
let mut textinput = self.textinput.borrow_mut();
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
if !textinput.single_line_content().is_valid_month_string() {
|
if !textinput.single_line_content().is_valid_month_string() {
|
||||||
*textinput.single_line_content_mut() = "".into();
|
textinput.single_line_content_mut().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputType::Week => {
|
InputType::Week => {
|
||||||
let mut textinput = self.textinput.borrow_mut();
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
if !textinput.single_line_content().is_valid_week_string() {
|
if !textinput.single_line_content().is_valid_week_string() {
|
||||||
*textinput.single_line_content_mut() = "".into();
|
textinput.single_line_content_mut().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputType::Color => {
|
InputType::Color => {
|
||||||
|
@ -1034,8 +1034,15 @@ impl HTMLInputElement {
|
||||||
InputType::Time => {
|
InputType::Time => {
|
||||||
let mut textinput = self.textinput.borrow_mut();
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
|
|
||||||
if ! textinput.single_line_content().is_valid_time_string() {
|
if !textinput.single_line_content().is_valid_time_string() {
|
||||||
*textinput.single_line_content_mut() = "".into();
|
textinput.single_line_content_mut().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputType::DatetimeLocal => {
|
||||||
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
|
if textinput.single_line_content_mut()
|
||||||
|
.convert_valid_normalized_local_date_and_time_string().is_err() {
|
||||||
|
textinput.single_line_content_mut().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Implement more value sanitization algorithms for different types of inputs
|
// TODO: Implement more value sanitization algorithms for different types of inputs
|
||||||
|
|
|
@ -543003,7 +543003,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"html/semantics/forms/the-input-element/datetime-local.html": [
|
"html/semantics/forms/the-input-element/datetime-local.html": [
|
||||||
"7fe3ab2bd5a8d60e11d08460286ee8f02943b769",
|
"382370387908b4625474b410621497a76476a0cf",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"html/semantics/forms/the-input-element/datetime.html": [
|
"html/semantics/forms/the-input-element/datetime.html": [
|
||||||
|
|
|
@ -1,29 +1,9 @@
|
||||||
[datetime-local.html]
|
[datetime-local.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[datetime-local input value set to 2014-01-01 11:11:11.111 without min/max]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[datetime-local input value set to 2014-01-01 11:11 without min/max]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[datetime-local input value set to 2014-01-01 00:00:00.000 without min/max]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[datetime-local input value set to 2014-01-0 11:11 without min/max]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[datetime-local input value set to 2014-01-01 11:1 without min/max]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value >= min attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value < min attribute]
|
[Value < min attribute]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Value <= max attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value > max attribute]
|
[Value > max attribute]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -225,9 +225,6 @@
|
||||||
[change state from checkbox to email]
|
[change state from checkbox to email]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[change state from checkbox to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from checkbox to number]
|
[change state from checkbox to number]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -294,96 +291,9 @@
|
||||||
[change state from button to range]
|
[change state from button to range]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[change state from hidden to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from text to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from search to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from tel to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from url to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from email to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from password to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to checkbox]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to radio]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to submit]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to image]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to reset]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to button]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to email]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to number]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to range]
|
[change state from datetime-local to range]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[change state from number to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from range to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from checkbox to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from radio to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from submit to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from image to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from reset to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from button to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to search]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to tel]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to url]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to password]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from number to text]
|
[change state from number to text]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -414,9 +324,6 @@
|
||||||
[change state from range to password]
|
[change state from range to password]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[change state from color to datetime-local]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from color to number]
|
[change state from color to number]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,6 @@
|
||||||
[value IDL attribute of input type range with value attribute]
|
[value IDL attribute of input type range with value attribute]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[value IDL attribute of input type datetime-local without value attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[value IDL attribute of input type datetime-local with value attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[value IDL attribute of input type email without value attribute]
|
[value IDL attribute of input type email without value attribute]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
{value: "2014-01-01 00:00:00.000", expected: "2014-01-01T00:00", testname: "datetime-local input value set to 2014-01-01 00:00:00.000 without min/max"},
|
{value: "2014-01-01 00:00:00.000", expected: "2014-01-01T00:00", testname: "datetime-local input value set to 2014-01-01 00:00:00.000 without min/max"},
|
||||||
{value: "2014-01-0 11:11", expected: "", testname: "datetime-local input value set to 2014-01-0 11:11 without min/max"},
|
{value: "2014-01-0 11:11", expected: "", testname: "datetime-local input value set to 2014-01-0 11:11 without min/max"},
|
||||||
{value: "2014-01-01 11:1", expected: "", testname: "datetime-local input value set to 2014-01-01 11:1 without min/max"},
|
{value: "2014-01-01 11:1", expected: "", testname: "datetime-local input value set to 2014-01-01 11:1 without min/max"},
|
||||||
|
{value: "2014-01-01 11:1d1", expected: "", testname: "invalid datetime-local input value 1"},
|
||||||
|
{value: "2014-01-01H11:11", expected: "", testname: "invalid datetime-local input value 2"},
|
||||||
|
{value: "2014-01-01 11:11:", expected: "", testname: "invalid datetime-local input value 3"},
|
||||||
|
{value: "2014-01-01 11-11", expected: "", testname: "invalid datetime-local input value 4"},
|
||||||
|
{value: "2014-01-01 11:11:123", expected: "", testname: "invalid datetime-local input value 5"},
|
||||||
|
{value: "2014-01-01 11:11:12.1234", expected: "", testname: "invalid datetime-local input value 6"},
|
||||||
{value: "2014-01-01 11:12", attributes: { min: "2014-01-01 11:11" }, expected: "2014-01-01T11:12", testname: "Value >= min attribute"},
|
{value: "2014-01-01 11:12", attributes: { min: "2014-01-01 11:11" }, expected: "2014-01-01T11:12", testname: "Value >= min attribute"},
|
||||||
{value: "2014-01-01 11:10", attributes: { min: "2014-01-01 11:11" }, expected: "2014-01-01T11:11", testname: "Value < min attribute"},
|
{value: "2014-01-01 11:10", attributes: { min: "2014-01-01 11:11" }, expected: "2014-01-01T11:11", testname: "Value < min attribute"},
|
||||||
{value: "2014-01-01 11:10", attributes: { max: "2014-01-01 11:11" }, expected: "2014-01-01T11:10", testname: "Value <= max attribute"},
|
{value: "2014-01-01 11:10", attributes: { max: "2014-01-01 11:11" }, expected: "2014-01-01T11:10", testname: "Value <= max attribute"},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue