mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
stepUp, stepDown, valueAsNumber, valueAsDate, and list work and have tests
This commit is contained in:
parent
6b79a8f042
commit
87e86c81b9
27 changed files with 1119 additions and 1244 deletions
|
@ -294,7 +294,7 @@ impl DOMString {
|
||||||
// Step 4.3.1 "."
|
// Step 4.3.1 "."
|
||||||
State::MilliStop => next_state(c == '.', State::MilliHigh),
|
State::MilliStop => next_state(c == '.', State::MilliHigh),
|
||||||
// Step 4.3.2 "SSS"
|
// Step 4.3.2 "SSS"
|
||||||
State::MilliHigh => next_state(c.is_digit(6), State::MilliMiddle),
|
State::MilliHigh => next_state(c.is_digit(10), State::MilliMiddle),
|
||||||
State::MilliMiddle => next_state(c.is_digit(10), State::MilliLow),
|
State::MilliMiddle => next_state(c.is_digit(10), State::MilliLow),
|
||||||
State::MilliLow => next_state(c.is_digit(10), State::Done),
|
State::MilliLow => next_state(c.is_digit(10), State::Done),
|
||||||
|
|
||||||
|
@ -318,21 +318,108 @@ impl DOMString {
|
||||||
/// YYYY must be four or more digits, MM and DD both must be two digits
|
/// YYYY must be four or more digits, MM and DD both must be two digits
|
||||||
/// https://html.spec.whatwg.org/multipage/#valid-date-string
|
/// https://html.spec.whatwg.org/multipage/#valid-date-string
|
||||||
pub fn is_valid_date_string(&self) -> bool {
|
pub fn is_valid_date_string(&self) -> bool {
|
||||||
parse_date_string(&self.0).is_ok()
|
self.parse_date_string().is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#parse-a-date-string
|
||||||
|
pub fn parse_date_string(&self) -> Result<(i32, u32, u32), ()> {
|
||||||
|
let value = &self.0;
|
||||||
|
// Step 1, 2, 3
|
||||||
|
let (year_int, month_int, day_int) = parse_date_component(value)?;
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
if value.split('-').nth(3).is_some() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5, 6
|
||||||
|
Ok((year_int, month_int, day_int))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#parse-a-time-string
|
||||||
|
pub fn parse_time_string(&self) -> Result<(u32, u32, f64), ()> {
|
||||||
|
let value = &self.0;
|
||||||
|
// Step 1, 2, 3
|
||||||
|
let (hour_int, minute_int, second_float) = parse_time_component(value)?;
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
if value.split(':').nth(3).is_some() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5, 6
|
||||||
|
Ok((hour_int, minute_int, second_float))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A valid month string should be "YYYY-MM"
|
/// A valid month string should be "YYYY-MM"
|
||||||
/// YYYY must be four or more digits, MM both must be two digits
|
/// YYYY must be four or more digits, MM both must be two digits
|
||||||
/// https://html.spec.whatwg.org/multipage/#valid-month-string
|
/// https://html.spec.whatwg.org/multipage/#valid-month-string
|
||||||
pub fn is_valid_month_string(&self) -> bool {
|
pub fn is_valid_month_string(&self) -> bool {
|
||||||
parse_month_string(&self.0).is_ok()
|
self.parse_month_string().is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#parse-a-month-string
|
||||||
|
pub fn parse_month_string(&self) -> Result<(i32, u32), ()> {
|
||||||
|
let value = &self;
|
||||||
|
// Step 1, 2, 3
|
||||||
|
let (year_int, month_int) = parse_month_component(value)?;
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
if value.split("-").nth(2).is_some() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
// Step 5
|
||||||
|
Ok((year_int, month_int))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A valid week string should be like {YYYY}-W{WW}, such as "2017-W52"
|
/// A valid week string should be like {YYYY}-W{WW}, such as "2017-W52"
|
||||||
/// YYYY must be four or more digits, WW both must be two digits
|
/// YYYY must be four or more digits, WW both must be two digits
|
||||||
/// https://html.spec.whatwg.org/multipage/#valid-week-string
|
/// https://html.spec.whatwg.org/multipage/#valid-week-string
|
||||||
pub fn is_valid_week_string(&self) -> bool {
|
pub fn is_valid_week_string(&self) -> bool {
|
||||||
parse_week_string(&self.0).is_ok()
|
self.parse_week_string().is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#parse-a-week-string
|
||||||
|
pub fn parse_week_string(&self) -> Result<(i32, u32), ()> {
|
||||||
|
let value = &self.0;
|
||||||
|
// Step 1, 2, 3
|
||||||
|
let mut iterator = value.split('-');
|
||||||
|
let year = iterator.next().ok_or(())?;
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
let year_int = year.parse::<i32>().map_err(|_| ())?;
|
||||||
|
if year.len() < 4 || year_int == 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5, 6
|
||||||
|
let week = iterator.next().ok_or(())?;
|
||||||
|
let (week_first, week_last) = week.split_at(1);
|
||||||
|
if week_first != "W" {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7
|
||||||
|
let week_int = week_last.parse::<u32>().map_err(|_| ())?;
|
||||||
|
if week_last.len() != 2 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
let max_week = max_week_in_year(year_int);
|
||||||
|
|
||||||
|
// Step 9
|
||||||
|
if week_int < 1 || week_int > max_week {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 10
|
||||||
|
if iterator.next().is_some() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 11
|
||||||
|
Ok((year_int, week_int))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#valid-floating-point-number
|
/// https://html.spec.whatwg.org/multipage/#valid-floating-point-number
|
||||||
|
@ -341,12 +428,37 @@ impl DOMString {
|
||||||
static ref RE: Regex =
|
static ref RE: Regex =
|
||||||
Regex::new(r"^-?(?:\d+\.\d+|\d+|\.\d+)(?:(e|E)(\+|\-)?\d+)?$").unwrap();
|
Regex::new(r"^-?(?:\d+\.\d+|\d+|\.\d+)(?:(e|E)(\+|\-)?\d+)?$").unwrap();
|
||||||
}
|
}
|
||||||
RE.is_match(&self.0) && parse_floating_point_number(&self.0).is_ok()
|
RE.is_match(&self.0) && self.parse_floating_point_number().is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values
|
||||||
|
pub fn parse_floating_point_number(&self) -> Result<f64, ()> {
|
||||||
|
// Steps 15-16 are telling us things about IEEE rounding modes
|
||||||
|
// for floating-point significands; this code assumes the Rust
|
||||||
|
// compiler already matches them in any cases where
|
||||||
|
// that actually matters. They are not
|
||||||
|
// related to f64::round(), which is for rounding to integers.
|
||||||
|
let input = &self.0;
|
||||||
|
match input.trim().parse::<f64>() {
|
||||||
|
Ok(val)
|
||||||
|
if !(
|
||||||
|
// A valid number is the same as what rust considers to be valid,
|
||||||
|
// except for +1., NaN, and Infinity.
|
||||||
|
val.is_infinite() ||
|
||||||
|
val.is_nan() ||
|
||||||
|
input.ends_with(".") ||
|
||||||
|
input.starts_with("+")
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
Ok(val)
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#best-representation-of-the-number-as-a-floating-point-number
|
/// https://html.spec.whatwg.org/multipage/#best-representation-of-the-number-as-a-floating-point-number
|
||||||
pub fn set_best_representation_of_the_floating_point_number(&mut self) {
|
pub fn set_best_representation_of_the_floating_point_number(&mut self) {
|
||||||
if let Ok(val) = parse_floating_point_number(&self.0) {
|
if let Ok(val) = self.parse_floating_point_number() {
|
||||||
self.0 = val.to_string();
|
self.0 = val.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,7 +468,7 @@ impl DOMString {
|
||||||
/// https://html.spec.whatwg.org/multipage/#valid-normalised-local-date-and-time-string
|
/// 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<(), ()> {
|
pub fn convert_valid_normalized_local_date_and_time_string(&mut self) -> Result<(), ()> {
|
||||||
let ((year, month, day), (hour, minute, second)) =
|
let ((year, month, day), (hour, minute, second)) =
|
||||||
parse_local_date_and_time_string(&*self.0)?;
|
self.parse_local_date_and_time_string()?;
|
||||||
if second == 0.0 {
|
if second == 0.0 {
|
||||||
self.0 = format!(
|
self.0 = format!(
|
||||||
"{:04}-{:02}-{:02}T{:02}:{:02}",
|
"{:04}-{:02}-{:02}T{:02}:{:02}",
|
||||||
|
@ -370,6 +482,35 @@ impl DOMString {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#parse-a-local-date-and-time-string
|
||||||
|
pub fn parse_local_date_and_time_string(
|
||||||
|
&self,
|
||||||
|
) -> Result<((i32, u32, u32), (u32, u32, f64)), ()> {
|
||||||
|
let value = &self;
|
||||||
|
// 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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Borrow<str> for DOMString {
|
impl Borrow<str> for DOMString {
|
||||||
|
@ -498,84 +639,15 @@ impl Extend<char> for DOMString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#parse-a-month-string
|
|
||||||
fn parse_month_string(value: &str) -> Result<(u32, u32), ()> {
|
|
||||||
// Step 1, 2, 3
|
|
||||||
let (year_int, month_int) = parse_month_component(value)?;
|
|
||||||
|
|
||||||
// Step 4
|
|
||||||
if value.split("-").nth(2).is_some() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
// Step 5
|
|
||||||
Ok((year_int, month_int))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#parse-a-date-string
|
|
||||||
fn parse_date_string(value: &str) -> Result<(u32, u32, u32), ()> {
|
|
||||||
// Step 1, 2, 3
|
|
||||||
let (year_int, month_int, day_int) = parse_date_component(value)?;
|
|
||||||
|
|
||||||
// Step 4
|
|
||||||
if value.split('-').nth(3).is_some() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 5, 6
|
|
||||||
Ok((year_int, month_int, day_int))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#parse-a-week-string
|
|
||||||
fn parse_week_string(value: &str) -> Result<(u32, u32), ()> {
|
|
||||||
// Step 1, 2, 3
|
|
||||||
let mut iterator = value.split('-');
|
|
||||||
let year = iterator.next().ok_or(())?;
|
|
||||||
|
|
||||||
// Step 4
|
|
||||||
let year_int = year.parse::<u32>().map_err(|_| ())?;
|
|
||||||
if year.len() < 4 || year_int == 0 {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 5, 6
|
|
||||||
let week = iterator.next().ok_or(())?;
|
|
||||||
let (week_first, week_last) = week.split_at(1);
|
|
||||||
if week_first != "W" {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 7
|
|
||||||
let week_int = week_last.parse::<u32>().map_err(|_| ())?;
|
|
||||||
if week_last.len() != 2 {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 8
|
|
||||||
let max_week = max_week_in_year(year_int);
|
|
||||||
|
|
||||||
// Step 9
|
|
||||||
if week_int < 1 || week_int > max_week {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 10
|
|
||||||
if iterator.next().is_some() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 11
|
|
||||||
Ok((year_int, week_int))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#parse-a-month-component
|
/// https://html.spec.whatwg.org/multipage/#parse-a-month-component
|
||||||
fn parse_month_component(value: &str) -> Result<(u32, u32), ()> {
|
fn parse_month_component(value: &str) -> Result<(i32, u32), ()> {
|
||||||
// Step 3
|
// Step 3
|
||||||
let mut iterator = value.split('-');
|
let mut iterator = value.split('-');
|
||||||
let year = iterator.next().ok_or(())?;
|
let year = iterator.next().ok_or(())?;
|
||||||
let month = iterator.next().ok_or(())?;
|
let month = iterator.next().ok_or(())?;
|
||||||
|
|
||||||
// Step 1, 2
|
// Step 1, 2
|
||||||
let year_int = year.parse::<u32>().map_err(|_| ())?;
|
let year_int = year.parse::<i32>().map_err(|_| ())?;
|
||||||
if year.len() < 4 || year_int == 0 {
|
if year.len() < 4 || year_int == 0 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -591,7 +663,7 @@ fn parse_month_component(value: &str) -> Result<(u32, u32), ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#parse-a-date-component
|
/// https://html.spec.whatwg.org/multipage/#parse-a-date-component
|
||||||
fn parse_date_component(value: &str) -> Result<(u32, u32, u32), ()> {
|
fn parse_date_component(value: &str) -> Result<(i32, u32, u32), ()> {
|
||||||
// Step 1
|
// Step 1
|
||||||
let (year_int, month_int) = parse_month_component(value)?;
|
let (year_int, month_int) = parse_month_component(value)?;
|
||||||
|
|
||||||
|
@ -613,7 +685,7 @@ fn parse_date_component(value: &str) -> Result<(u32, u32, u32), ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#parse-a-time-component
|
/// https://html.spec.whatwg.org/multipage/#parse-a-time-component
|
||||||
fn parse_time_component(value: &str) -> Result<(u32, u32, f32), ()> {
|
fn parse_time_component(value: &str) -> Result<(u32, u32, f64), ()> {
|
||||||
// Step 1
|
// Step 1
|
||||||
let mut iterator = value.split(':');
|
let mut iterator = value.split(':');
|
||||||
let hour = iterator.next().ok_or(())?;
|
let hour = iterator.next().ok_or(())?;
|
||||||
|
@ -655,7 +727,7 @@ fn parse_time_component(value: &str) -> Result<(u32, u32, f32), ()> {
|
||||||
None => {},
|
None => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
second.parse::<f32>().map_err(|_| ())?
|
second.parse::<f64>().map_err(|_| ())?
|
||||||
},
|
},
|
||||||
None => 0.0,
|
None => 0.0,
|
||||||
};
|
};
|
||||||
|
@ -664,33 +736,7 @@ fn parse_time_component(value: &str) -> Result<(u32, u32, f32), ()> {
|
||||||
Ok((hour_int, minute_int, second_float))
|
Ok((hour_int, minute_int, second_float))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#parse-a-local-date-and-time-string
|
fn max_day_in_month(year_num: i32, month_num: u32) -> Result<u32, ()> {
|
||||||
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, ()> {
|
|
||||||
match month_num {
|
match month_num {
|
||||||
1 | 3 | 5 | 7 | 8 | 10 | 12 => Ok(31),
|
1 | 3 | 5 | 7 | 8 | 10 | 12 => Ok(31),
|
||||||
4 | 6 | 9 | 11 => Ok(30),
|
4 | 6 | 9 | 11 => Ok(30),
|
||||||
|
@ -706,7 +752,7 @@ fn max_day_in_month(year_num: u32, month_num: u32) -> Result<u32, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#week-number-of-the-last-day
|
/// https://html.spec.whatwg.org/multipage/#week-number-of-the-last-day
|
||||||
fn max_week_in_year(year: u32) -> u32 {
|
fn max_week_in_year(year: i32) -> u32 {
|
||||||
match Utc.ymd(year as i32, 1, 1).weekday() {
|
match Utc.ymd(year as i32, 1, 1).weekday() {
|
||||||
Weekday::Thu => 53,
|
Weekday::Thu => 53,
|
||||||
Weekday::Wed if is_leap_year(year) => 53,
|
Weekday::Wed if is_leap_year(year) => 53,
|
||||||
|
@ -715,23 +761,6 @@ fn max_week_in_year(year: u32) -> u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_leap_year(year: u32) -> bool {
|
fn is_leap_year(year: i32) -> bool {
|
||||||
year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)
|
year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values
|
|
||||||
fn parse_floating_point_number(input: &str) -> Result<f64, ()> {
|
|
||||||
match input.trim().parse::<f64>() {
|
|
||||||
Ok(val)
|
|
||||||
if !(
|
|
||||||
// A valid number is the same as what rust considers to be valid,
|
|
||||||
// except for +1., NaN, and Infinity.
|
|
||||||
val.is_infinite() || val.is_nan() || input.ends_with(".") || input.starts_with("+")
|
|
||||||
) =>
|
|
||||||
{
|
|
||||||
// TODO(#19773): need consider `min`, `max`, `step`, when they are implemented
|
|
||||||
Ok(val.round())
|
|
||||||
}
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
use crate::dom::activation::{synthetic_click_activation, Activatable, ActivationSource};
|
use crate::dom::activation::{synthetic_click_activation, Activatable, ActivationSource};
|
||||||
use crate::dom::attr::Attr;
|
use crate::dom::attr::Attr;
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::FileListBinding::FileListMethods;
|
use crate::dom::bindings::codegen::Bindings::FileListBinding::FileListMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::HTMLFormElementBinding::SelectionMode;
|
use crate::dom::bindings::codegen::Bindings::HTMLFormElementBinding::SelectionMode;
|
||||||
use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding;
|
use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding;
|
||||||
use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
|
||||||
use crate::dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
|
use crate::dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
|
||||||
use crate::dom::bindings::error::{Error, ErrorResult};
|
use crate::dom::bindings::error::{Error, ErrorResult};
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::reflector::DomObject;
|
use crate::dom::bindings::reflector::DomObject;
|
||||||
|
@ -26,6 +28,7 @@ use crate::dom::eventtarget::EventTarget;
|
||||||
use crate::dom::file::File;
|
use crate::dom::file::File;
|
||||||
use crate::dom::filelist::FileList;
|
use crate::dom::filelist::FileList;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
use crate::dom::htmldatalistelement::HTMLDataListElement;
|
||||||
use crate::dom::htmlelement::HTMLElement;
|
use crate::dom::htmlelement::HTMLElement;
|
||||||
use crate::dom::htmlfieldsetelement::HTMLFieldSetElement;
|
use crate::dom::htmlfieldsetelement::HTMLFieldSetElement;
|
||||||
use crate::dom::htmlformelement::{
|
use crate::dom::htmlformelement::{
|
||||||
|
@ -35,21 +38,29 @@ use crate::dom::htmlformelement::{ResetFrom, SubmittedFrom};
|
||||||
use crate::dom::keyboardevent::KeyboardEvent;
|
use crate::dom::keyboardevent::KeyboardEvent;
|
||||||
use crate::dom::mouseevent::MouseEvent;
|
use crate::dom::mouseevent::MouseEvent;
|
||||||
use crate::dom::node::{document_from_node, window_from_node};
|
use crate::dom::node::{document_from_node, window_from_node};
|
||||||
use crate::dom::node::{BindContext, CloneChildrenFlag, Node, NodeDamage, UnbindContext};
|
use crate::dom::node::{
|
||||||
|
BindContext, CloneChildrenFlag, Node, NodeDamage, ShadowIncluding, UnbindContext,
|
||||||
|
};
|
||||||
use crate::dom::nodelist::NodeList;
|
use crate::dom::nodelist::NodeList;
|
||||||
use crate::dom::textcontrol::{TextControlElement, TextControlSelection};
|
use crate::dom::textcontrol::{TextControlElement, TextControlSelection};
|
||||||
use crate::dom::validation::Validatable;
|
use crate::dom::validation::Validatable;
|
||||||
use crate::dom::validitystate::ValidationFlags;
|
use crate::dom::validitystate::ValidationFlags;
|
||||||
use crate::dom::virtualmethods::VirtualMethods;
|
use crate::dom::virtualmethods::VirtualMethods;
|
||||||
|
use crate::script_runtime::JSContext as SafeJSContext;
|
||||||
use crate::textinput::KeyReaction::{
|
use crate::textinput::KeyReaction::{
|
||||||
DispatchInput, Nothing, RedrawSelection, TriggerDefaultAction,
|
DispatchInput, Nothing, RedrawSelection, TriggerDefaultAction,
|
||||||
};
|
};
|
||||||
use crate::textinput::Lines::Single;
|
use crate::textinput::Lines::Single;
|
||||||
use crate::textinput::{Direction, SelectionDirection, TextInput, UTF16CodeUnits, UTF8Bytes};
|
use crate::textinput::{Direction, SelectionDirection, TextInput, UTF16CodeUnits, UTF8Bytes};
|
||||||
|
use chrono::naive::{NaiveDate, NaiveDateTime};
|
||||||
|
use chrono::{Datelike, Weekday};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use embedder_traits::FilterPattern;
|
use embedder_traits::FilterPattern;
|
||||||
use encoding_rs::Encoding;
|
use encoding_rs::Encoding;
|
||||||
use html5ever::{LocalName, Prefix};
|
use html5ever::{LocalName, Prefix};
|
||||||
|
use js::jsapi::{
|
||||||
|
ClippedTime, DateGetMsecSinceEpoch, Handle, JSObject, NewDateObject, ObjectIsDate,
|
||||||
|
};
|
||||||
use msg::constellation_msg::InputMethodType;
|
use msg::constellation_msg::InputMethodType;
|
||||||
use net_traits::blob_url_store::get_blob_origin;
|
use net_traits::blob_url_store::get_blob_origin;
|
||||||
use net_traits::filemanager_thread::FileManagerThreadMsg;
|
use net_traits::filemanager_thread::FileManagerThreadMsg;
|
||||||
|
@ -61,6 +72,7 @@ use servo_atoms::Atom;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
use std::ptr::NonNull;
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
use style::element_state::ElementState;
|
use style::element_state::ElementState;
|
||||||
use style::str::{split_commas, str_join};
|
use style::str::{split_commas, str_join};
|
||||||
|
@ -217,6 +229,12 @@ enum ValueMode {
|
||||||
Filename,
|
Filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum StepDirection {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
}
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct HTMLInputElement {
|
pub struct HTMLInputElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
|
@ -231,6 +249,10 @@ pub struct HTMLInputElement {
|
||||||
activation_state: DomRefCell<InputActivationState>,
|
activation_state: DomRefCell<InputActivationState>,
|
||||||
// https://html.spec.whatwg.org/multipage/#concept-input-value-dirty-flag
|
// https://html.spec.whatwg.org/multipage/#concept-input-value-dirty-flag
|
||||||
value_dirty: Cell<bool>,
|
value_dirty: Cell<bool>,
|
||||||
|
// not specified explicitly, but implied by the fact that sanitization can't
|
||||||
|
// happen until after all of step/min/max/value content attributes have
|
||||||
|
// been added
|
||||||
|
sanitization_flag: Cell<bool>,
|
||||||
|
|
||||||
filelist: MutNullableDom<FileList>,
|
filelist: MutNullableDom<FileList>,
|
||||||
form_owner: MutNullableDom<HTMLFormElement>,
|
form_owner: MutNullableDom<HTMLFormElement>,
|
||||||
|
@ -302,6 +324,7 @@ impl HTMLInputElement {
|
||||||
)),
|
)),
|
||||||
activation_state: DomRefCell::new(InputActivationState::new()),
|
activation_state: DomRefCell::new(InputActivationState::new()),
|
||||||
value_dirty: Cell::new(false),
|
value_dirty: Cell::new(false),
|
||||||
|
sanitization_flag: Cell::new(true),
|
||||||
filelist: MutNullableDom::new(None),
|
filelist: MutNullableDom::new(None),
|
||||||
form_owner: Default::default(),
|
form_owner: Default::default(),
|
||||||
labels_node_list: MutNullableDom::new(None),
|
labels_node_list: MutNullableDom::new(None),
|
||||||
|
@ -358,6 +381,318 @@ impl HTMLInputElement {
|
||||||
pub fn input_type(&self) -> InputType {
|
pub fn input_type(&self) -> InputType {
|
||||||
self.input_type.get()
|
self.input_type.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn disable_sanitization(&self) {
|
||||||
|
self.sanitization_flag.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_sanitization(&self) {
|
||||||
|
self.sanitization_flag.set(true);
|
||||||
|
let mut textinput = self.textinput.borrow_mut();
|
||||||
|
let mut value = textinput.single_line_content().clone();
|
||||||
|
self.sanitize_value(&mut value);
|
||||||
|
textinput.set_content(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// valueAsNumber, step, min, and max all share the same set of
|
||||||
|
// input types they apply to
|
||||||
|
fn does_value_as_number_apply(&self) -> bool {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Date |
|
||||||
|
InputType::Month |
|
||||||
|
InputType::Week |
|
||||||
|
InputType::Time |
|
||||||
|
InputType::DatetimeLocal |
|
||||||
|
InputType::Number |
|
||||||
|
InputType::Range => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn does_value_as_date_apply(&self) -> bool {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Date | InputType::Month | InputType::Week | InputType::Time => true,
|
||||||
|
// surprisingly, spec says false for DateTimeLocal!
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-step
|
||||||
|
fn allowed_value_step(&self) -> Option<f64> {
|
||||||
|
if let Some(attr) = self
|
||||||
|
.upcast::<Element>()
|
||||||
|
.get_attribute(&ns!(), &local_name!("step"))
|
||||||
|
{
|
||||||
|
if let Ok(step) = DOMString::from(attr.summarize().value).parse_floating_point_number()
|
||||||
|
{
|
||||||
|
if step > 0.0 {
|
||||||
|
return Some(step * self.step_scale_factor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.default_step()
|
||||||
|
.map(|step| step * self.step_scale_factor())
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-min
|
||||||
|
fn minimum(&self) -> Option<f64> {
|
||||||
|
if let Some(attr) = self
|
||||||
|
.upcast::<Element>()
|
||||||
|
.get_attribute(&ns!(), &local_name!("min"))
|
||||||
|
{
|
||||||
|
if let Ok(min) = self.convert_string_to_number(&DOMString::from(attr.summarize().value))
|
||||||
|
{
|
||||||
|
return Some(min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self.default_minimum();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-max
|
||||||
|
fn maximum(&self) -> Option<f64> {
|
||||||
|
if let Some(attr) = self
|
||||||
|
.upcast::<Element>()
|
||||||
|
.get_attribute(&ns!(), &local_name!("max"))
|
||||||
|
{
|
||||||
|
if let Ok(max) = self.convert_string_to_number(&DOMString::from(attr.summarize().value))
|
||||||
|
{
|
||||||
|
return Some(max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self.default_maximum();
|
||||||
|
}
|
||||||
|
|
||||||
|
// when allowed_value_step and minumum both exist, this is the smallest
|
||||||
|
// value >= minimum that lies on an integer step
|
||||||
|
fn stepped_minimum(&self) -> Option<f64> {
|
||||||
|
match (self.minimum(), self.allowed_value_step()) {
|
||||||
|
(Some(min), Some(allowed_step)) => {
|
||||||
|
let step_base = self.step_base();
|
||||||
|
// how many steps is min from step_base?
|
||||||
|
let nsteps = (min - step_base) / allowed_step;
|
||||||
|
// count that many integer steps, rounded +, from step_base
|
||||||
|
Some(step_base + (allowed_step * nsteps.ceil()))
|
||||||
|
},
|
||||||
|
(_, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when allowed_value_step and maximum both exist, this is the smallest
|
||||||
|
// value <= maximum that lies on an integer step
|
||||||
|
fn stepped_maximum(&self) -> Option<f64> {
|
||||||
|
match (self.maximum(), self.allowed_value_step()) {
|
||||||
|
(Some(max), Some(allowed_step)) => {
|
||||||
|
let step_base = self.step_base();
|
||||||
|
// how many steps is max from step_base?
|
||||||
|
let nsteps = (max - step_base) / allowed_step;
|
||||||
|
// count that many integer steps, rounded -, from step_base
|
||||||
|
Some(step_base + (allowed_step * nsteps.floor()))
|
||||||
|
},
|
||||||
|
(_, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-min-default
|
||||||
|
fn default_minimum(&self) -> Option<f64> {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Range => Some(0.0),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-max-default
|
||||||
|
fn default_maximum(&self) -> Option<f64> {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Range => Some(100.0),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-value-default-range
|
||||||
|
fn default_range_value(&self) -> f64 {
|
||||||
|
let min = self.minimum().unwrap_or(0.0);
|
||||||
|
let max = self.maximum().unwrap_or(100.0);
|
||||||
|
if max < min {
|
||||||
|
min
|
||||||
|
} else {
|
||||||
|
min + (max - min) * 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-step-default
|
||||||
|
fn default_step(&self) -> Option<f64> {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Date => Some(1.0),
|
||||||
|
InputType::Month => Some(1.0),
|
||||||
|
InputType::Week => Some(1.0),
|
||||||
|
InputType::Time => Some(60.0),
|
||||||
|
InputType::DatetimeLocal => Some(60.0),
|
||||||
|
InputType::Number => Some(1.0),
|
||||||
|
InputType::Range => Some(1.0),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-step-scale
|
||||||
|
fn step_scale_factor(&self) -> f64 {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Date => 86400000.0,
|
||||||
|
InputType::Month => 1.0,
|
||||||
|
InputType::Week => 604800000.0,
|
||||||
|
InputType::Time => 1000.0,
|
||||||
|
InputType::DatetimeLocal => 1000.0,
|
||||||
|
InputType::Number => 1.0,
|
||||||
|
InputType::Range => 1.0,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-min-zero
|
||||||
|
fn step_base(&self) -> f64 {
|
||||||
|
if let Some(attr) = self
|
||||||
|
.upcast::<Element>()
|
||||||
|
.get_attribute(&ns!(), &local_name!("min"))
|
||||||
|
{
|
||||||
|
let minstr = &DOMString::from(attr.summarize().value);
|
||||||
|
if let Ok(min) = self.convert_string_to_number(minstr) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(attr) = self
|
||||||
|
.upcast::<Element>()
|
||||||
|
.get_attribute(&ns!(), &local_name!("value"))
|
||||||
|
{
|
||||||
|
if let Ok(value) =
|
||||||
|
self.convert_string_to_number(&DOMString::from(attr.summarize().value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.default_step_base().unwrap_or(0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage#concept-input-step-default-base
|
||||||
|
fn default_step_base(&self) -> Option<f64> {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Week => Some(-259200000.0),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-stepdown
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-stepup
|
||||||
|
fn step_up_or_down(&self, n: i32, dir: StepDirection) -> ErrorResult {
|
||||||
|
// Step 1
|
||||||
|
if !self.does_value_as_number_apply() {
|
||||||
|
return Err(Error::InvalidState);
|
||||||
|
}
|
||||||
|
let step_base = self.step_base();
|
||||||
|
// Step 2
|
||||||
|
let allowed_value_step = match self.allowed_value_step() {
|
||||||
|
Some(avs) => avs,
|
||||||
|
None => return Err(Error::InvalidState),
|
||||||
|
};
|
||||||
|
let minimum = self.minimum();
|
||||||
|
let maximum = self.maximum();
|
||||||
|
if let (Some(min), Some(max)) = (minimum, maximum) {
|
||||||
|
// Step 3
|
||||||
|
if min > max {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
// Step 4
|
||||||
|
if let Some(smin) = self.stepped_minimum() {
|
||||||
|
if smin > max {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Step 5
|
||||||
|
let mut value: f64 = self.convert_string_to_number(&self.Value()).unwrap_or(0.0);
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
let valueBeforeStepping = value;
|
||||||
|
|
||||||
|
// Step 7
|
||||||
|
if (value - step_base) % allowed_value_step != 0.0 {
|
||||||
|
value = match dir {
|
||||||
|
StepDirection::Down =>
|
||||||
|
//step down a fractional step to be on a step multiple
|
||||||
|
{
|
||||||
|
let intervals_from_base = ((value - step_base) / allowed_value_step).floor();
|
||||||
|
intervals_from_base * allowed_value_step + step_base
|
||||||
|
}
|
||||||
|
StepDirection::Up =>
|
||||||
|
// step up a fractional step to be on a step multiple
|
||||||
|
{
|
||||||
|
let intervals_from_base = ((value - step_base) / allowed_value_step).ceil();
|
||||||
|
intervals_from_base * allowed_value_step + step_base
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
value = value +
|
||||||
|
match dir {
|
||||||
|
StepDirection::Down => -f64::from(n) * allowed_value_step,
|
||||||
|
StepDirection::Up => f64::from(n) * allowed_value_step,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
if let Some(min) = minimum {
|
||||||
|
if value < min {
|
||||||
|
value = self.stepped_minimum().unwrap_or(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9
|
||||||
|
if let Some(max) = maximum {
|
||||||
|
if value > max {
|
||||||
|
value = self.stepped_maximum().unwrap_or(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 10
|
||||||
|
match dir {
|
||||||
|
StepDirection::Down => {
|
||||||
|
if value > valueBeforeStepping {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StepDirection::Up => {
|
||||||
|
if value < valueBeforeStepping {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 11
|
||||||
|
self.SetValueAsNumber(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#concept-input-list
|
||||||
|
fn suggestions_source_element(&self) -> Option<DomRoot<HTMLElement>> {
|
||||||
|
let list_string = self
|
||||||
|
.upcast::<Element>()
|
||||||
|
.get_string_attribute(&local_name!("list"));
|
||||||
|
if list_string.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let ancestor = self
|
||||||
|
.upcast::<Node>()
|
||||||
|
.GetRootNode(&GetRootNodeOptions::empty());
|
||||||
|
let first_with_id = &ancestor
|
||||||
|
.traverse_preorder(ShadowIncluding::No)
|
||||||
|
.find(|node| {
|
||||||
|
node.downcast::<Element>()
|
||||||
|
.map_or(false, |e| e.Id() == list_string)
|
||||||
|
});
|
||||||
|
first_with_id
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|el| {
|
||||||
|
el.downcast::<HTMLDataListElement>()
|
||||||
|
.map(|data_el| data_el.upcast::<HTMLElement>())
|
||||||
|
})
|
||||||
|
.map(|el| DomRoot::from_ref(&*el))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LayoutHTMLInputElementHelpers {
|
pub trait LayoutHTMLInputElementHelpers {
|
||||||
|
@ -678,6 +1013,96 @@ impl HTMLInputElementMethods for HTMLInputElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-input-defaultvalue
|
// https://html.spec.whatwg.org/multipage/#dom-input-defaultvalue
|
||||||
make_setter!(SetDefaultValue, "value");
|
make_setter!(SetDefaultValue, "value");
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-min
|
||||||
|
make_getter!(Min, "min");
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-min
|
||||||
|
make_setter!(SetMin, "min");
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-list
|
||||||
|
fn GetList(&self) -> Option<DomRoot<HTMLElement>> {
|
||||||
|
self.suggestions_source_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-valueasdate
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn GetValueAsDate(&self, cx: SafeJSContext) -> Option<NonNull<JSObject>> {
|
||||||
|
self.convert_string_to_naive_datetime(self.Value())
|
||||||
|
.map(|dt| unsafe {
|
||||||
|
let time = ClippedTime {
|
||||||
|
t: dt.timestamp_millis() as f64,
|
||||||
|
};
|
||||||
|
NonNull::new_unchecked(NewDateObject(*cx, time))
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-valueasdate
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn SetValueAsDate(&self, cx: SafeJSContext, value: *mut JSObject) -> ErrorResult {
|
||||||
|
rooted!(in(*cx) let value = value);
|
||||||
|
if !self.does_value_as_date_apply() {
|
||||||
|
return Err(Error::InvalidState);
|
||||||
|
}
|
||||||
|
if value.is_null() {
|
||||||
|
return self.SetValue(DOMString::from(""));
|
||||||
|
}
|
||||||
|
let mut msecs: f64 = 0.0;
|
||||||
|
// We need to go through unsafe code to interrogate jsapi about a Date.
|
||||||
|
// To minimize the amount of unsafe code to maintain, this just gets the milliseconds,
|
||||||
|
// which we then reinflate into a NaiveDate for use in safe code.
|
||||||
|
unsafe {
|
||||||
|
let mut isDate = false;
|
||||||
|
if !ObjectIsDate(*cx, Handle::from(value.handle()), &mut isDate) {
|
||||||
|
return Err(Error::JSFailed);
|
||||||
|
}
|
||||||
|
if !isDate {
|
||||||
|
return Err(Error::Type("Value was not a date".to_string()));
|
||||||
|
}
|
||||||
|
if !DateGetMsecSinceEpoch(*cx, Handle::from(value.handle()), &mut msecs) {
|
||||||
|
return Err(Error::JSFailed);
|
||||||
|
}
|
||||||
|
if !msecs.is_finite() {
|
||||||
|
return self.SetValue(DOMString::from(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// now we make a Rust date out of it so we can use safe code for the
|
||||||
|
// actual conversion logic
|
||||||
|
match milliseconds_to_datetime(msecs) {
|
||||||
|
Ok(dt) => match self.convert_naive_datetime_to_string(dt) {
|
||||||
|
Ok(converted) => self.SetValue(converted),
|
||||||
|
_ => self.SetValue(DOMString::from("")),
|
||||||
|
},
|
||||||
|
_ => self.SetValue(DOMString::from("")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-valueasnumber
|
||||||
|
fn ValueAsNumber(&self) -> f64 {
|
||||||
|
self.convert_string_to_number(&self.Value())
|
||||||
|
.unwrap_or(std::f64::NAN)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-valueasnumber
|
||||||
|
fn SetValueAsNumber(&self, value: f64) -> ErrorResult {
|
||||||
|
if value.is_infinite() {
|
||||||
|
Err(Error::Type("value is not finite".to_string()))
|
||||||
|
} else if !self.does_value_as_number_apply() {
|
||||||
|
Err(Error::InvalidState)
|
||||||
|
} else if value.is_nan() {
|
||||||
|
self.SetValue(DOMString::from(""))
|
||||||
|
} else if let Ok(converted) = self.convert_number_to_string(value) {
|
||||||
|
self.SetValue(converted)
|
||||||
|
} else {
|
||||||
|
// The most literal spec-compliant implementation would
|
||||||
|
// use bignum chrono types so overflow is impossible,
|
||||||
|
// but just setting an overflow to the empty string matches
|
||||||
|
// Firefox's behavior.
|
||||||
|
// (for example, try input.valueAsNumber=1e30 on a type="date" input)
|
||||||
|
self.SetValue(DOMString::from(""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#attr-fe-name
|
// https://html.spec.whatwg.org/multipage/#attr-fe-name
|
||||||
make_getter!(Name, "name");
|
make_getter!(Name, "name");
|
||||||
|
|
||||||
|
@ -743,12 +1168,6 @@ impl HTMLInputElementMethods for HTMLInputElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-input-minlength
|
// https://html.spec.whatwg.org/multipage/#dom-input-minlength
|
||||||
make_limited_int_setter!(SetMinLength, "minlength", DEFAULT_MIN_LENGTH);
|
make_limited_int_setter!(SetMinLength, "minlength", DEFAULT_MIN_LENGTH);
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-input-min
|
|
||||||
make_getter!(Min, "min");
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-input-min
|
|
||||||
make_setter!(SetMin, "min");
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-input-multiple
|
// https://html.spec.whatwg.org/multipage/#dom-input-multiple
|
||||||
make_bool_getter!(Multiple, "multiple");
|
make_bool_getter!(Multiple, "multiple");
|
||||||
|
|
||||||
|
@ -875,6 +1294,16 @@ impl HTMLInputElementMethods for HTMLInputElement {
|
||||||
self.select_files(Some(paths));
|
self.select_files(Some(paths));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-stepup
|
||||||
|
fn StepUp(&self, n: i32) -> ErrorResult {
|
||||||
|
self.step_up_or_down(n, StepDirection::Up)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-input-stepdown
|
||||||
|
fn StepDown(&self, n: i32) -> ErrorResult {
|
||||||
|
self.step_up_or_down(n, StepDirection::Down)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -1160,6 +1589,13 @@ impl HTMLInputElement {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#value-sanitization-algorithm
|
// https://html.spec.whatwg.org/multipage/#value-sanitization-algorithm
|
||||||
fn sanitize_value(&self, value: &mut DOMString) {
|
fn sanitize_value(&self, value: &mut DOMString) {
|
||||||
|
// if sanitization_flag is false, we are setting content attributes
|
||||||
|
// on an element we haven't really finished creating; we will
|
||||||
|
// enable the flag and really sanitize before this element becomes
|
||||||
|
// observable.
|
||||||
|
if !self.sanitization_flag.get() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
match self.input_type() {
|
match self.input_type() {
|
||||||
InputType::Text | InputType::Search | InputType::Tel | InputType::Password => {
|
InputType::Text | InputType::Search | InputType::Tel | InputType::Password => {
|
||||||
value.strip_newlines();
|
value.strip_newlines();
|
||||||
|
@ -1216,10 +1652,63 @@ impl HTMLInputElement {
|
||||||
if !value.is_valid_floating_point_number_string() {
|
if !value.is_valid_floating_point_number_string() {
|
||||||
value.clear();
|
value.clear();
|
||||||
}
|
}
|
||||||
|
// Spec says that user agent "may" round the value
|
||||||
|
// when it's suffering a step mismatch, but WPT tests
|
||||||
|
// want it unrounded, and this matches other browser
|
||||||
|
// behavior (typing an unrounded number into an
|
||||||
|
// integer field box and pressing enter generally keeps
|
||||||
|
// the number intact but makes the input box :invalid)
|
||||||
},
|
},
|
||||||
// https://html.spec.whatwg.org/multipage/#range-state-(type=range):value-sanitization-algorithm
|
// https://html.spec.whatwg.org/multipage/#range-state-(type=range):value-sanitization-algorithm
|
||||||
InputType::Range => {
|
InputType::Range => {
|
||||||
value.set_best_representation_of_the_floating_point_number();
|
if !value.is_valid_floating_point_number_string() {
|
||||||
|
*value = DOMString::from(self.default_range_value().to_string());
|
||||||
|
}
|
||||||
|
if let Ok(fval) = &value.parse::<f64>() {
|
||||||
|
let mut fval = *fval;
|
||||||
|
// comparing max first, because if they contradict
|
||||||
|
// the spec wants min to be the one that applies
|
||||||
|
if let Some(max) = self.maximum() {
|
||||||
|
if fval > max {
|
||||||
|
fval = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(min) = self.minimum() {
|
||||||
|
if fval < min {
|
||||||
|
fval = min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// https://html.spec.whatwg.org/multipage/#range-state-(type=range):suffering-from-a-step-mismatch
|
||||||
|
// Spec does not describe this in a way that lends itself to
|
||||||
|
// reproducible handling of floating-point rounding;
|
||||||
|
// Servo may fail a WPT test because .1 * 6 == 6.000000000000001
|
||||||
|
if let Some(allowed_value_step) = self.allowed_value_step() {
|
||||||
|
let step_base = self.step_base();
|
||||||
|
let steps_from_base = (fval - step_base) / allowed_value_step;
|
||||||
|
if steps_from_base.fract() != 0.0 {
|
||||||
|
// not an integer number of steps, there's a mismatch
|
||||||
|
// round the number of steps...
|
||||||
|
let int_steps = round_halves_positive(steps_from_base);
|
||||||
|
// and snap the value to that rounded value...
|
||||||
|
fval = int_steps * allowed_value_step + step_base;
|
||||||
|
|
||||||
|
// but if after snapping we're now outside min..max
|
||||||
|
// we have to adjust! (adjusting to min last because
|
||||||
|
// that "wins" over max in the spec)
|
||||||
|
if let Some(stepped_maximum) = self.stepped_maximum() {
|
||||||
|
if fval > stepped_maximum {
|
||||||
|
fval = stepped_maximum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(stepped_minimum) = self.stepped_minimum() {
|
||||||
|
if fval < stepped_minimum {
|
||||||
|
fval = stepped_minimum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*value = DOMString::from(fval.to_string());
|
||||||
|
};
|
||||||
},
|
},
|
||||||
InputType::Email => {
|
InputType::Email => {
|
||||||
if !self.Multiple() {
|
if !self.Multiple() {
|
||||||
|
@ -1325,6 +1814,142 @@ impl HTMLInputElement {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#concept-input-value-string-number
|
||||||
|
fn convert_string_to_number(&self, value: &DOMString) -> Result<f64, ()> {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Date => match value.parse_date_string() {
|
||||||
|
Ok((year, month, day)) => {
|
||||||
|
let d = NaiveDate::from_ymd(year, month, day);
|
||||||
|
let duration = d.signed_duration_since(NaiveDate::from_ymd(1970, 1, 1));
|
||||||
|
Ok(duration.num_milliseconds() as f64)
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
},
|
||||||
|
InputType::Month => match value.parse_month_string() {
|
||||||
|
// This one returns number of months, not milliseconds
|
||||||
|
// (specification requires this, presumably because number of
|
||||||
|
// milliseconds is not consistent across months)
|
||||||
|
// the - 1.0 is because january is 1, not 0
|
||||||
|
Ok((year, month)) => Ok(((year - 1970) * 12) as f64 + (month as f64 - 1.0)),
|
||||||
|
_ => Err(()),
|
||||||
|
},
|
||||||
|
InputType::Week => match value.parse_week_string() {
|
||||||
|
Ok((year, weeknum)) => {
|
||||||
|
let d = NaiveDate::from_isoywd(year, weeknum, Weekday::Mon);
|
||||||
|
let duration = d.signed_duration_since(NaiveDate::from_ymd(1970, 1, 1));
|
||||||
|
Ok(duration.num_milliseconds() as f64)
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
},
|
||||||
|
InputType::Time => match value.parse_time_string() {
|
||||||
|
Ok((hours, minutes, seconds)) => {
|
||||||
|
Ok((seconds as f64 + 60.0 * minutes as f64 + 3600.0 * hours as f64) * 1000.0)
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
},
|
||||||
|
InputType::DatetimeLocal => match value.parse_local_date_and_time_string() {
|
||||||
|
// Is this supposed to know the locale's daylight-savings-time rules?
|
||||||
|
Ok(((year, month, day), (hours, minutes, seconds))) => {
|
||||||
|
let d = NaiveDate::from_ymd(year, month, day);
|
||||||
|
let ymd_duration = d.signed_duration_since(NaiveDate::from_ymd(1970, 1, 1));
|
||||||
|
let hms_millis =
|
||||||
|
(seconds + 60.0 * minutes as f64 + 3600.0 * hours as f64) * 1000.0;
|
||||||
|
Ok(ymd_duration.num_milliseconds() as f64 + hms_millis)
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
},
|
||||||
|
InputType::Number | InputType::Range => value.parse_floating_point_number(),
|
||||||
|
// min/max/valueAsNumber/stepDown/stepUp do not apply to
|
||||||
|
// the remaining types
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#concept-input-value-string-number
|
||||||
|
fn convert_number_to_string(&self, value: f64) -> Result<DOMString, ()> {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Date => {
|
||||||
|
let datetime = milliseconds_to_datetime(value)?;
|
||||||
|
Ok(DOMString::from(datetime.format("%Y-%m-%d").to_string()))
|
||||||
|
},
|
||||||
|
InputType::Month => {
|
||||||
|
// interpret value as months(not millis) in epoch, return monthstring
|
||||||
|
let year_from_1970 = (value / 12.0).floor();
|
||||||
|
let month = (value - year_from_1970 * 12.0).floor() as u32 + 1; // january is 1, not 0
|
||||||
|
let year = (year_from_1970 + 1970.0) as u64;
|
||||||
|
Ok(DOMString::from(format!("{:04}-{:02}", year, month)))
|
||||||
|
},
|
||||||
|
InputType::Week => {
|
||||||
|
let datetime = milliseconds_to_datetime(value)?;
|
||||||
|
let year = datetime.iso_week().year(); // not necessarily the same as datetime.year()
|
||||||
|
let week = datetime.iso_week().week();
|
||||||
|
Ok(DOMString::from(format!("{:04}-W{:02}", year, week)))
|
||||||
|
},
|
||||||
|
InputType::Time => {
|
||||||
|
let datetime = milliseconds_to_datetime(value)?;
|
||||||
|
Ok(DOMString::from(datetime.format("%H:%M:%S%.3f").to_string()))
|
||||||
|
},
|
||||||
|
InputType::DatetimeLocal => {
|
||||||
|
let datetime = milliseconds_to_datetime(value)?;
|
||||||
|
Ok(DOMString::from(
|
||||||
|
datetime.format("%Y-%m-%dT%H:%M:%S%.3f").to_string(),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
InputType::Number | InputType::Range => Ok(DOMString::from(value.to_string())),
|
||||||
|
// this won't be called from other input types
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#concept-input-value-string-date
|
||||||
|
// This does the safe Rust part of conversion; the unsafe JS Date part
|
||||||
|
// is in GetValueAsDate
|
||||||
|
fn convert_string_to_naive_datetime(&self, value: DOMString) -> Result<NaiveDateTime, ()> {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Date => value
|
||||||
|
.parse_date_string()
|
||||||
|
.and_then(|(y, m, d)| NaiveDate::from_ymd_opt(y, m, d).ok_or(()))
|
||||||
|
.map(|date| date.and_hms(0, 0, 0)),
|
||||||
|
InputType::Time => value.parse_time_string().and_then(|(h, m, s)| {
|
||||||
|
let whole_seconds = s.floor();
|
||||||
|
let nanos = ((s - whole_seconds) * 1e9).floor() as u32;
|
||||||
|
NaiveDate::from_ymd(1970, 1, 1)
|
||||||
|
.and_hms_nano_opt(h, m, whole_seconds as u32, nanos)
|
||||||
|
.ok_or(())
|
||||||
|
}),
|
||||||
|
InputType::Week => value
|
||||||
|
.parse_week_string()
|
||||||
|
.and_then(|(iso_year, week)| {
|
||||||
|
NaiveDate::from_isoywd_opt(iso_year, week, Weekday::Mon).ok_or(())
|
||||||
|
})
|
||||||
|
.map(|date| date.and_hms(0, 0, 0)),
|
||||||
|
InputType::Month => value
|
||||||
|
.parse_month_string()
|
||||||
|
.and_then(|(y, m)| NaiveDate::from_ymd_opt(y, m, 1).ok_or(()))
|
||||||
|
.map(|date| date.and_hms(0, 0, 0)),
|
||||||
|
// does not apply to other types
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#concept-input-value-date-string
|
||||||
|
// This does the safe Rust part of conversion; the unsafe JS Date part
|
||||||
|
// is in SetValueAsDate
|
||||||
|
fn convert_naive_datetime_to_string(&self, value: NaiveDateTime) -> Result<DOMString, ()> {
|
||||||
|
match self.input_type() {
|
||||||
|
InputType::Date => Ok(DOMString::from(value.format("%Y-%m-%d").to_string())),
|
||||||
|
InputType::Month => Ok(DOMString::from(value.format("%Y-%m").to_string())),
|
||||||
|
InputType::Week => {
|
||||||
|
let year = value.iso_week().year(); // not necessarily the same as value.year()
|
||||||
|
let week = value.iso_week().week();
|
||||||
|
Ok(DOMString::from(format!("{:04}-W{:02}", year, week)))
|
||||||
|
},
|
||||||
|
InputType::Time => Ok(DOMString::from(value.format("%H:%M:%S%.3f").to_string())),
|
||||||
|
// this won't be called from other input types
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualMethods for HTMLInputElement {
|
impl VirtualMethods for HTMLInputElement {
|
||||||
|
@ -1889,3 +2514,21 @@ fn filter_from_accept(s: &DOMString) -> Vec<FilterPattern> {
|
||||||
|
|
||||||
filter
|
filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn round_halves_positive(n: f64) -> f64 {
|
||||||
|
// WHATWG specs about input steps say to round to the nearest step,
|
||||||
|
// rounding halves always to positive infinity.
|
||||||
|
// This differs from Rust's .round() in the case of -X.5.
|
||||||
|
if n.fract() == -0.5 {
|
||||||
|
n.ceil()
|
||||||
|
} else {
|
||||||
|
n.round()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn milliseconds_to_datetime(value: f64) -> Result<NaiveDateTime, ()> {
|
||||||
|
let seconds = (value / 1000.0).floor();
|
||||||
|
let milliseconds = value - (seconds * 1000.0);
|
||||||
|
let nanoseconds = milliseconds * 1e6;
|
||||||
|
NaiveDateTime::from_timestamp_opt(seconds as i64, nanoseconds as u32).ok_or(())
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator};
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
|
use crate::dom::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
|
||||||
use crate::dom::htmlimageelement::HTMLImageElement;
|
use crate::dom::htmlimageelement::HTMLImageElement;
|
||||||
|
use crate::dom::htmlinputelement::HTMLInputElement;
|
||||||
use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult};
|
use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult};
|
||||||
use crate::dom::htmltemplateelement::HTMLTemplateElement;
|
use crate::dom::htmltemplateelement::HTMLTemplateElement;
|
||||||
use crate::dom::node::{Node, ShadowIncluding};
|
use crate::dom::node::{Node, ShadowIncluding};
|
||||||
|
@ -1244,13 +1245,32 @@ fn create_element_for_token(
|
||||||
} else {
|
} else {
|
||||||
CustomElementCreationMode::Asynchronous
|
CustomElementCreationMode::Asynchronous
|
||||||
};
|
};
|
||||||
|
|
||||||
let element = Element::create(name, is, document, creator, creation_mode);
|
let element = Element::create(name, is, document, creator, creation_mode);
|
||||||
|
|
||||||
// Step 8.
|
// https://html.spec.whatwg.org/multipage#the-input-element:value-sanitization-algorithm-3
|
||||||
|
// says to invoke sanitization "when an input element is first created";
|
||||||
|
// however, since sanitization requires content attributes to function,
|
||||||
|
// it can't mean that literally.
|
||||||
|
// Indeed, to make sanitization work correctly, we need to _not_ sanitize
|
||||||
|
// until after all content attributes have been added
|
||||||
|
|
||||||
|
let maybe_input = element.downcast::<HTMLInputElement>();
|
||||||
|
if let Some(input) = maybe_input {
|
||||||
|
input.disable_sanitization();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
element.set_attribute_from_parser(attr.name, attr.value, None);
|
element.set_attribute_from_parser(attr.name, attr.value, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _now_ we can sanitize (and we sanitize now even if the "value"
|
||||||
|
// attribute isn't present!)
|
||||||
|
if let Some(input) = maybe_input {
|
||||||
|
input.enable_sanitization();
|
||||||
|
}
|
||||||
|
|
||||||
// Step 9.
|
// Step 9.
|
||||||
if will_execute_script {
|
if will_execute_script {
|
||||||
// Steps 9.1 - 9.2.
|
// Steps 9.1 - 9.2.
|
||||||
|
|
|
@ -39,7 +39,7 @@ interface HTMLInputElement : HTMLElement {
|
||||||
attribute boolean indeterminate;
|
attribute boolean indeterminate;
|
||||||
// [CEReactions]
|
// [CEReactions]
|
||||||
// attribute DOMString inputMode;
|
// attribute DOMString inputMode;
|
||||||
// readonly attribute HTMLElement? list;
|
readonly attribute HTMLElement? list;
|
||||||
[CEReactions]
|
[CEReactions]
|
||||||
attribute DOMString max;
|
attribute DOMString max;
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
|
@ -72,15 +72,15 @@ interface HTMLInputElement : HTMLElement {
|
||||||
attribute DOMString defaultValue;
|
attribute DOMString defaultValue;
|
||||||
[CEReactions, SetterThrows]
|
[CEReactions, SetterThrows]
|
||||||
attribute [TreatNullAs=EmptyString] DOMString value;
|
attribute [TreatNullAs=EmptyString] DOMString value;
|
||||||
// attribute Date? valueAsDate;
|
[SetterThrows]
|
||||||
// attribute unrestricted double valueAsNumber;
|
attribute object? valueAsDate;
|
||||||
// attribute double valueLow;
|
[SetterThrows]
|
||||||
// attribute double valueHigh;
|
attribute unrestricted double valueAsNumber;
|
||||||
// [CEReactions]
|
// [CEReactions]
|
||||||
// attribute unsigned long width;
|
// attribute unsigned long width;
|
||||||
|
|
||||||
//void stepUp(optional long n = 1);
|
[Throws] void stepUp(optional long n = 1);
|
||||||
//void stepDown(optional long n = 1);
|
[Throws] void stepDown(optional long n = 1);
|
||||||
|
|
||||||
//readonly attribute boolean willValidate;
|
//readonly attribute boolean willValidate;
|
||||||
//readonly attribute ValidityState validity;
|
//readonly attribute ValidityState validity;
|
||||||
|
|
|
@ -368483,6 +368483,12 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"html/semantics/forms/the-input-element/input-list.html": [
|
||||||
|
[
|
||||||
|
"html/semantics/forms/the-input-element/input-list.html",
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"html/semantics/forms/the-input-element/input-setcustomvalidity.html": [
|
"html/semantics/forms/the-input-element/input-setcustomvalidity.html": [
|
||||||
[
|
[
|
||||||
"html/semantics/forms/the-input-element/input-setcustomvalidity.html",
|
"html/semantics/forms/the-input-element/input-setcustomvalidity.html",
|
||||||
|
@ -368537,6 +368543,12 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"html/semantics/forms/the-input-element/input-valueasdate-stepping.html": [
|
||||||
|
[
|
||||||
|
"html/semantics/forms/the-input-element/input-valueasdate-stepping.html",
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"html/semantics/forms/the-input-element/input-valueasdate.html": [
|
"html/semantics/forms/the-input-element/input-valueasdate.html": [
|
||||||
[
|
[
|
||||||
"html/semantics/forms/the-input-element/input-valueasdate.html",
|
"html/semantics/forms/the-input-element/input-valueasdate.html",
|
||||||
|
@ -368549,6 +368561,12 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"html/semantics/forms/the-input-element/input-valueasnumber-stepping.html": [
|
||||||
|
[
|
||||||
|
"html/semantics/forms/the-input-element/input-valueasnumber-stepping.html",
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"html/semantics/forms/the-input-element/input-valueasnumber.html": [
|
"html/semantics/forms/the-input-element/input-valueasnumber.html": [
|
||||||
[
|
[
|
||||||
"html/semantics/forms/the-input-element/input-valueasnumber.html",
|
"html/semantics/forms/the-input-element/input-valueasnumber.html",
|
||||||
|
@ -666180,6 +666198,10 @@
|
||||||
"77f4d8b31a5131994ee30f27179d02981047a828",
|
"77f4d8b31a5131994ee30f27179d02981047a828",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"html/semantics/forms/the-input-element/input-list.html": [
|
||||||
|
"006a8fbd8f1b84d18e9ec29285f751f037118389",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"html/semantics/forms/the-input-element/input-setcustomvalidity.html": [
|
"html/semantics/forms/the-input-element/input-setcustomvalidity.html": [
|
||||||
"accb24d8f9564f97e12bf4784162ff3cd00f35af",
|
"accb24d8f9564f97e12bf4784162ff3cd00f35af",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -666216,6 +666238,10 @@
|
||||||
"bd49a15fc82136105c17818561cc1e8f7fbfe7ee",
|
"bd49a15fc82136105c17818561cc1e8f7fbfe7ee",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"html/semantics/forms/the-input-element/input-valueasdate-stepping.html": [
|
||||||
|
"09856110314aaeab6630086e62596b7801d1ec35",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"html/semantics/forms/the-input-element/input-valueasdate.html": [
|
"html/semantics/forms/the-input-element/input-valueasdate.html": [
|
||||||
"a958e991ec53a22413bc311d832bc28b3b4baccf",
|
"a958e991ec53a22413bc311d832bc28b3b4baccf",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -666224,6 +666250,10 @@
|
||||||
"a3187ff3fbca4252d701b30c761819f5075611cc",
|
"a3187ff3fbca4252d701b30c761819f5075611cc",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"html/semantics/forms/the-input-element/input-valueasnumber-stepping.html": [
|
||||||
|
"c93c25b23fd3c5728dee7eb087fd512410f7c0fe",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"html/semantics/forms/the-input-element/input-valueasnumber.html": [
|
"html/semantics/forms/the-input-element/input-valueasnumber.html": [
|
||||||
"321c981c74d2293694fecf18284126b089aca1c2",
|
"321c981c74d2293694fecf18284126b089aca1c2",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +0,0 @@
|
||||||
[date.html]
|
|
||||||
type: testharness
|
|
||||||
[The min attribute, if specified, must have a value that is a valid date string.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[The max attribute, if specified, must have a value that is a valid date string.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
[datetime.html]
|
|
||||||
type: testharness
|
|
||||||
[[date\] stepUp method support on input 'date' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[date\] stepDown method support on input 'date' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[time\] stepUp method support on input 'time' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[time\] stepDown method support on input 'time' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[datetime\] stepUp method support on input 'datetime' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[datetime\] stepDown method support on input 'datetime' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[month\] stepUp method support on input 'month' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[month\] stepDown method support on input 'month' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[week\] stepUp method support on input 'week' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[week\] stepDown method support on input 'week' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[datetime-local\] stepUp method support on input 'datetime-local' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[[datetime-local\] stepDown method support on input 'datetime-local' element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,20 +1,5 @@
|
||||||
[hidden.html]
|
[hidden.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[valueAsDate attribute must return null for hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber attribute must return NaN for hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[list attribute must return null for hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown does not apply for hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp does not apply for hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type=hidden is barred from constraint validation]
|
[input type=hidden is barred from constraint validation]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[input-stepdown.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[Forms]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[input-stepup.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[Forms]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[input-valueasdate-invalidstateerr.html]
|
|
||||||
type: testharness
|
|
||||||
[Forms]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,79 +1,19 @@
|
||||||
[input-valueasdate.html]
|
[input-valueasdate.html]
|
||||||
[valueAsDate getter on type date (actual value: 2019-00-12, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type date (actual value: 2016-02-29, expected valueAsDate: Mon Feb 29 2016 00:00:00 GMT+0000 (Coordinated Universal Time))]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type date (actual value: , expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type week (actual value: 2019-W00, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate setter on type date (actual valueAsDate: Tue Dec 10 2019 00:00:00 GMT+0000 (Coordinated Universal Time), expected value: 2019-12-10)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type month (actual value: 2019-12, expected valueAsDate: Sun Dec 01 2019 00:00:00 GMT+0000 (Coordinated Universal Time))]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type week (actual value: 2019-W50, expected valueAsDate: Mon Dec 09 2019 00:00:00 GMT+0000 (Coordinated Universal Time))]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type week (actual value: 2019-W60, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type date (actual value: 2019-12-10, expected valueAsDate: Tue Dec 10 2019 00:00:00 GMT+0000 (Coordinated Universal Time))]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type date (actual value: 2019-13-10, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type time (actual value: 00:60, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate setter on type time (actual valueAsDate: Thu Jan 01 1970 00:00:00 GMT+0000 (Coordinated Universal Time), expected value: 00:00)]
|
[valueAsDate setter on type time (actual valueAsDate: Thu Jan 01 1970 00:00:00 GMT+0000 (Coordinated Universal Time), expected value: 00:00)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[valueAsDate getter on type date (actual value: 2019-12-00, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type month (actual value: 2019-00, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type week (actual value: , expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type time (actual value: , expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type month (actual value: , expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type time (actual value: 12:00, expected valueAsDate: Thu Jan 01 1970 12:00:00 GMT+0000 (Coordinated Universal Time))]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type time (actual value: 23:59, expected valueAsDate: Thu Jan 01 1970 23:59:00 GMT+0000 (Coordinated Universal Time))]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type date (actual value: 2019-02-29, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type month (actual value: 0000-12, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type week (actual value: 0000-W50, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate getter on type date (actual value: 0000-12-10, expected valueAsDate: null)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate setter on type time (actual valueAsDate: Thu Jan 01 1970 12:00:00 GMT+0000 (Coordinated Universal Time), expected value: 12:00)]
|
[valueAsDate setter on type time (actual valueAsDate: Thu Jan 01 1970 12:00:00 GMT+0000 (Coordinated Universal Time), expected value: 12:00)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[valueAsDate getter on type time (actual value: 00:00, expected valueAsDate: Thu Jan 01 1970 00:00:00 GMT+0000 (Coordinated Universal Time))]
|
[valueAsDate setter on type time (actual valueAsDate: Thu Jan 01 1970 23:59:00 GMT+0000 (Coordinated Universal Time), expected value: 23:59)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[valueAsDate getter on type time (actual value: 24:00, expected valueAsDate: null)]
|
[valueAsDate setter on type time (actual valueAsDate: Wed Dec 31 1969 19:00:00 GMT-0500 (Eastern Standard Time), expected value: 00:00)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[valueAsDate setter on type time (actual valueAsDate: Thu Jan 01 1970 07:00:00 GMT-0500 (Eastern Standard Time), expected value: 12:00)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[valueAsDate setter on type time (actual valueAsDate: Thu Jan 01 1970 18:59:00 GMT-0500 (Eastern Standard Time), expected value: 23:59)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[input-valueasnumber-invalidstateerr.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,38 +1,5 @@
|
||||||
[input-valueasnumber.html]
|
[input-valueasnumber.html]
|
||||||
[valueAsNumber getter on type month (actual value: 0000-12, expected valueAsNumber: NaN)]
|
[valueAsNumber setter on type time (actual valueAsNumber: 86340000, expected value: 23:59)]
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type datetime-local (actual value: 2019-12-10T12:00, expected valueAsNumber: 1575979200000)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type month (actual value: 2019-00, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type date (actual value: 2016-02-29, expected valueAsNumber: 1456704000000)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type time (actual value: , expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber setter on type range (actual valueAsNumber: 0, expected value: 0)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type range (actual value: 110, expected valueAsNumber: 100)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type range (actual value: -10, expected valueAsNumber: 0)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber setter on type date (actual valueAsNumber: 0, expected value: 1970-01-01)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type date (actual value: 2019-00-12, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type date (actual value: 2019-12-00, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber setter on type date (actual valueAsNumber: 1575936000000, expected value: 2019-12-10)]
|
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[valueAsNumber setter on type time (actual valueAsNumber: 43200000, expected value: 12:00)]
|
[valueAsNumber setter on type time (actual valueAsNumber: 43200000, expected value: 12:00)]
|
||||||
|
@ -40,97 +7,3 @@
|
||||||
|
|
||||||
[valueAsNumber setter on type time (actual valueAsNumber: 0, expected value: 00:00)]
|
[valueAsNumber setter on type time (actual valueAsNumber: 0, expected value: 00:00)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[valueAsNumber getter on type time (actual value: 24:00, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber setter on type number (actual valueAsNumber: 123, expected value: 123)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type time (actual value: 00:60, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type week (actual value: 2019-W60, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type date (actual value: , expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type number (actual value: 123, expected valueAsNumber: 123)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber setter on type range (actual valueAsNumber: 50, expected value: 50)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber setter on type week (actual valueAsNumber: 0, expected value: 1970-W01)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type week (actual value: , expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type range (actual value: 100, expected valueAsNumber: 100)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type datetime-local (actual value: 2019-12-10T00:00, expected valueAsNumber: 1575936000000)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type time (actual value: 12:00, expected valueAsNumber: 43200000)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type datetime-local (actual value: , expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type number (actual value: , expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type number (actual value: 123.456, expected valueAsNumber: 123.456)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type time (actual value: 23:59, expected valueAsNumber: 86340000)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type week (actual value: 0000-W50, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type month (actual value: 2019-12, expected valueAsNumber: 599)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type range (actual value: 0, expected valueAsNumber: 0)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type range (actual value: 50, expected valueAsNumber: 50)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type week (actual value: 2019-W50, expected valueAsNumber: 1575849600000)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber setter on type datetime-local (actual valueAsNumber: 1575936000000, expected value: 2019-12-10T00:00)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type date (actual value: 0000-12-10, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type date (actual value: 2019-13-10, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type time (actual value: 00:00, expected valueAsNumber: 0)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type range (actual value: , expected valueAsNumber: 50)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber setter on type range (actual valueAsNumber: 100, expected value: 100)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type date (actual value: 2019-02-29, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type date (actual value: 2019-12-10, expected valueAsNumber: 1575936000000)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type week (actual value: 2019-W00, expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber getter on type month (actual value: , expected valueAsNumber: NaN)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[month.html]
|
|
||||||
type: testharness
|
|
||||||
[When step attribute is given invalid value, it must ignore the invalid value and use defaul value instead.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,14 +1,4 @@
|
||||||
[range-2.html]
|
[range-2.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[range input value set to '']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[range input value equals 50]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[range input value equals 100]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[range input value set to an integer]
|
[range input value set to an integer]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,7 @@
|
||||||
[range.html]
|
[range.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Converting an illegal string to the default value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Converting an illegal string to the default step]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the value is set to min when a smaller value than min attribute is given]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the value is set to max when a larger value than max attribute is given]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[default value when min and max attributes are given (= min plus half the difference between min and max)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[default value with step control when both min and max attributes are given]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[default value when both min and max attributes are given, while min > max]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Step scale factor behavior when min attribute has integer value but max attribute is non-integer ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[The default scale factor is 1 even if step attribute is explicitly set to non-integer value, unless min attribute has non-integer value]
|
[The default scale factor is 1 even if step attribute is explicitly set to non-integer value, unless min attribute has non-integer value]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Solving the step mismatch]
|
[Skip ASCII whitespace within input]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Performing stepUp()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Performing stepDown()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Performing stepUp() beyond the value of the max attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Performing stepDown() beyond the value of the min attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
[text.html]
|
|
||||||
type: testharness
|
|
||||||
[valueAsDate attribute must return null for text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber attribute must return NaN for text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[list attribute must return null for text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown does not apply for text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp does not apply for text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsDate attribute must return null for search]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[valueAsNumber attribute must return NaN for search]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[list attribute must return null for search]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown does not apply for search]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp does not apply for search]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[time-datalist-crash.html]
|
|
||||||
[Moving a datalist enclosing an input type=time using that list should not crash.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
[time.html]
|
|
||||||
type: testharness
|
|
||||||
[stepUp function support on input Element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown function support on input Element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp step value empty on default step value ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown step value empty default step value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp on step value minus]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown on step value minus]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp on step value zero ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown on step value zero ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp on step value 24 hour]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown on step value 24 hour ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp on step value hour ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown on step value hour ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp on step value second ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown on step value second ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp on step value miri second ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown on step value miri second ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp argment 2 times]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown argment 2 times]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp stop because it exceeds the maximum value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown Stop so lower than the minimum value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stop at border on stepUp]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stop at border on stepDown]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ empty value of stepUp]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp on step value with fractional seconds]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown on step value with fractional seconds]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepUp argument 2 times]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown argument 2 times]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[stepDown stop so lower than the minimum value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[type-change-file-to-text-crash.html]
|
|
||||||
[Changing type from file to text should not crash.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
[type-change-state.html]
|
|
||||||
type: testharness
|
|
||||||
[change state from hidden to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from hidden to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from text to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from text to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from search to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from search to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from tel to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from tel to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from url to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from url to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from email to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from email to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from password to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from password to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime to text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime to search]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime to tel]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime to url]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime to password]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime to week]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from date to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from date to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from date to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from month to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from week to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from week to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from time to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from time to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from number to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from range to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from checkbox to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from radio to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from radio to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from submit to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from submit to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from image to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from image to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from reset to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from reset to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from button to datetime]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from button to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from datetime-local to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[change state from color to range]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
[valueMode.html]
|
|
||||||
type: testharness
|
|
||||||
[value IDL attribute of input type datetime without value attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[value IDL attribute of input type datetime with value attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[value IDL attribute of input type range without value attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[value IDL attribute of input type range with value attribute]
|
|
||||||
expected: FAIL
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>input list attribute</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
<h3>input_list</h3>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div id="log"></div>
|
||||||
|
|
||||||
|
<form method="post"
|
||||||
|
enctype="application/x-www-form-urlencoded"
|
||||||
|
action=""
|
||||||
|
name="input_form">
|
||||||
|
<datalist id="thelist">
|
||||||
|
<option value="one">one</option>
|
||||||
|
<option value="two">two</option>
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
<p id="non_datalist_first">
|
||||||
|
<datalist id="non_datalist_first">
|
||||||
|
<option value="one">one</option>
|
||||||
|
<option value="two">two</option>
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
<datalist id="datalist_first">
|
||||||
|
<option value="one">one</option>
|
||||||
|
<option value="two">two</option>
|
||||||
|
</datalist>
|
||||||
|
<p id="datalist_first">
|
||||||
|
|
||||||
|
<p><input list="thelist" id='input_with_list'></p>
|
||||||
|
<p><input id='input_without_list'></p>
|
||||||
|
<p><input list="input_with_list" id='input_with_nondatalist_list'></p>
|
||||||
|
<p><input list="not_an_id" id='input_with_missing_list'></p>
|
||||||
|
<p><input list="non_datalist_first" id='input_with_non_datalist_first'></p>
|
||||||
|
<p><input list="datalist_first" id='input_with_datalist_first'></p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById("input_with_list").list, document.getElementById("thelist"));
|
||||||
|
}, "getting .list of input must return the datalist with that id");
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById("input_without_list").list, null);
|
||||||
|
}, "getting .list of input must return null if it has no list attribute");
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById("input_with_nondatalist_list").list, null);
|
||||||
|
}, "getting .list of input must return null if the list attribute is a non-datalist's id");
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById("input_with_missing_list").list, null);
|
||||||
|
}, "getting .list of input must return null if the list attribute is no element's id");
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById("input_with_non_datalist_first").list, null);
|
||||||
|
}, "getting .list of input must return null if the list attribute is used in a non-datalist earlier than a datalist");
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById("input_with_datalist_first").list, document.querySelector("datalist#datalist_first"));
|
||||||
|
}, "getting .list of input must return the datalist with that id even if a later non-datalist also has the id");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,83 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>valueAsDate stepping</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
<h3>input_valueAsDate_stepping</h3>
|
||||||
|
<!-- This test verifies that valueAsDate reads and writes Date values,
|
||||||
|
that those values step by the correct default step, and that the values
|
||||||
|
represent the correct times.
|
||||||
|
-->
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div id="log"></div>
|
||||||
|
|
||||||
|
<form method="post"
|
||||||
|
enctype="application/x-www-form-urlencoded"
|
||||||
|
action=""
|
||||||
|
name="input_form">
|
||||||
|
<p><input type='date' id='input_date'></p>
|
||||||
|
<p><input type='time' id='input_time'></p>
|
||||||
|
<p><input type='week' id='input_week'></p>
|
||||||
|
<p><input type='month' id='input_month'></p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function test_stepping(inputType, stringValue, steppedString, baseMillis, stepAmount) {
|
||||||
|
test(function() {
|
||||||
|
// put date in, constructed from a UTC timestamp so the test doesn't
|
||||||
|
// vary by local timezone
|
||||||
|
input = document.getElementById("input_" + inputType);
|
||||||
|
input.valueAsDate = new Date(baseMillis)
|
||||||
|
|
||||||
|
// get string out (using startsWith here to allow for optional
|
||||||
|
// seconds and milliseconds)
|
||||||
|
var sanitizedStr = input.value;
|
||||||
|
assert_true(sanitizedStr.startsWith(stringValue),
|
||||||
|
"The input value [" + sanitizedStr + "] must resemble [" + stringValue + "]");
|
||||||
|
|
||||||
|
// get date out
|
||||||
|
var sanitized = input.valueAsDate;
|
||||||
|
assert_equals(sanitized.getTime(), baseMillis, "The input valueAsDate must represent the same time as the original Date.")
|
||||||
|
|
||||||
|
// step up, get new date out
|
||||||
|
input.stepUp()
|
||||||
|
var steppedDate = input.valueAsDate;
|
||||||
|
assert_equals(steppedDate.getTime(), baseMillis + stepAmount, "Stepping must be by the correct amount")
|
||||||
|
|
||||||
|
// get new string out
|
||||||
|
var steppedStrOut = input.value;
|
||||||
|
assert_true(steppedStrOut.startsWith(steppedString),
|
||||||
|
"The changed input value [" + steppedStrOut + "] must resemble ["+steppedString+"]");
|
||||||
|
|
||||||
|
// step back down, get first date out again
|
||||||
|
input.stepDown()
|
||||||
|
var backDown = input.valueAsDate;
|
||||||
|
assert_equals(backDown.getTime(), baseMillis, "Stepping back down must return the date to its original value");
|
||||||
|
|
||||||
|
}, inputType + " should step correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
var millis_per_day = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
// jan 1 midnight, step 1 day to jan 2
|
||||||
|
test_stepping("date", "1970-01-01", "1970-01-02", 0, millis_per_day);
|
||||||
|
|
||||||
|
// jan 1 midnight, step 1 minute to 00:01:00
|
||||||
|
test_stepping("time", "00:00", "00:01", 0, 60 * 1000);
|
||||||
|
|
||||||
|
// jan 1 midnight, step 31 days to feb 1
|
||||||
|
test_stepping("month", "1970-01", "1970-02", 0, 31 * millis_per_day);
|
||||||
|
|
||||||
|
// monday jan 5 1970 midnight, step 7 days to jan 12
|
||||||
|
// (this has to start on a monday for stepping up and down to return)
|
||||||
|
test_stepping("week", "1970-W02", "1970-W03", 4 * millis_per_day, 7 * millis_per_day);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,94 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>valueAsNumber stepping</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
<h3>input_valueAsNumber_stepping</h3>
|
||||||
|
<!-- This test verifies that valueAsNumber reads and writes number values,
|
||||||
|
that those values step by the correct default step, and that the values
|
||||||
|
represent the correct milliseconds/months.
|
||||||
|
-->
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div id="log"></div>
|
||||||
|
|
||||||
|
<form method="post"
|
||||||
|
enctype="application/x-www-form-urlencoded"
|
||||||
|
action=""
|
||||||
|
name="input_form">
|
||||||
|
<p><input type='date' id='input_date'></p>
|
||||||
|
<p><input type='time' id='input_time'></p>
|
||||||
|
<p><input type='week' id='input_week'></p>
|
||||||
|
<p><input type='month' id='input_month'></p>
|
||||||
|
<p><input type='datetime-local' id='input_datetime-local'></p>
|
||||||
|
<p><input type='range' id='input_range'></p>
|
||||||
|
<p><input type='number' id='input_number'></p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function test_stepping(inputType, stringValue, steppedString, baseNumber, stepAmount) {
|
||||||
|
test(function() {
|
||||||
|
// put number in
|
||||||
|
input = document.getElementById("input_" + inputType);
|
||||||
|
input.valueAsNumber = baseNumber
|
||||||
|
|
||||||
|
// get string out
|
||||||
|
// startsWith is here to allow for optional seconds and milliseconds.
|
||||||
|
// the replace("T", " ") fallback is for https://github.com/web-platform-tests/wpt/issues/20994
|
||||||
|
var sanitizedStr = input.value;
|
||||||
|
assert_true(sanitizedStr.startsWith(stringValue) || sanitizedStr.startsWith(stringValue.replace("T", " ")),
|
||||||
|
"The input value [" + sanitizedStr + "] must resemble [" + stringValue + "]");
|
||||||
|
|
||||||
|
// get number out
|
||||||
|
var sanitized = input.valueAsNumber;
|
||||||
|
assert_equals(sanitized, baseNumber, "The input valueAsNumber must equal the original number.")
|
||||||
|
|
||||||
|
// step up, get new date out
|
||||||
|
input.stepUp()
|
||||||
|
var steppedNumber = input.valueAsNumber;
|
||||||
|
assert_equals(steppedNumber, baseNumber + stepAmount, "Stepping must be by the correct amount")
|
||||||
|
|
||||||
|
// get new string out
|
||||||
|
var steppedStrOut = input.value;
|
||||||
|
assert_true(steppedStrOut.startsWith(steppedString) || steppedStrOut.startsWith(steppedString.replace("T", " ")),
|
||||||
|
"The changed input value [" + steppedStrOut + "] must resemble [" + steppedString + "]");
|
||||||
|
|
||||||
|
// step back down, get first date out again
|
||||||
|
input.stepDown()
|
||||||
|
var backDown = input.valueAsNumber;
|
||||||
|
assert_equals(backDown, baseNumber, "Stepping back down must return the number to its original value");
|
||||||
|
|
||||||
|
}, inputType + " should step correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
var millis_per_day = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
// jan 1 midnight, step 1 day to jan 2
|
||||||
|
test_stepping("date", "1970-01-01", "1970-01-02", 0, millis_per_day);
|
||||||
|
|
||||||
|
// jan 1 midnight, step 1 minute to 00:01:00
|
||||||
|
test_stepping("time", "00:00", "00:01", 0, 60 * 1000);
|
||||||
|
|
||||||
|
// jan 1 midnight, step 1 month (not counting by milliseconds) to feb 1
|
||||||
|
test_stepping("month", "1970-01", "1970-02", 0, 1);
|
||||||
|
|
||||||
|
// monday jan 5 1970 midnight, step 7 days to jan 12
|
||||||
|
// (this has to start on a monday for stepping up and down to return)
|
||||||
|
test_stepping("week", "1970-W02", "1970-W03", 4 * millis_per_day, 7 * millis_per_day);
|
||||||
|
|
||||||
|
// jan 1 midnight, step 1 minute to 00:01:00
|
||||||
|
test_stepping("datetime-local", "1970-01-01T00:00", "1970-01-01T00:01", 0, 60 * 1000);
|
||||||
|
|
||||||
|
// numbers, for which the default step is 1
|
||||||
|
test_stepping("range", "22", "23", 22, 1);
|
||||||
|
test_stepping("number", "24", "25", 24, 1);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue